[WIN32K:NTUSER]
[reactos.git] / reactos / win32ss / user / ntuser / scrollbar.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Scrollbars
5 * FILE: subsys/win32k/ntuser/scrollbar.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
7 * Jason Filby (jasonfilby@yahoo.com)
8 */
9
10 #include <win32k.h>
11 DBG_DEFAULT_CHANNEL(UserScrollbar);
12
13 /* Definitions for scrollbar hit testing [See SCROLLBARINFO in MSDN] */
14 #define SCROLL_NOWHERE 0x00 /* Outside the scroll bar */
15 #define SCROLL_TOP_ARROW 0x01 /* Top or left arrow */
16 #define SCROLL_TOP_RECT 0x02 /* Rectangle between the top arrow and the thumb */
17 #define SCROLL_THUMB 0x03 /* Thumb rectangle */
18 #define SCROLL_BOTTOM_RECT 0x04 /* Rectangle between the thumb and the bottom arrow */
19 #define SCROLL_BOTTOM_ARROW 0x05 /* Bottom or right arrow */
20
21 #define SCROLL_FIRST_DELAY 200 /* Delay (in ms) before first repetition when
22 holding the button down */
23 #define SCROLL_REPEAT_DELAY 50 /* Delay (in ms) between scroll repetitions */
24
25 #define SCROLL_TIMER 0 /* Scroll timer id */
26
27 /* Minimum size of the rectangle between the arrows */
28 #define SCROLL_MIN_RECT 4
29
30 /* Minimum size of the thumb in pixels */
31 #define SCROLL_MIN_THUMB 6
32
33 /* Overlap between arrows and thumb */
34 #define SCROLL_ARROW_THUMB_OVERLAP 0
35
36 //
37 //
38 //
39 #define MINTRACKTHUMB 8 /* Minimum size of the rectangle between the arrows */
40
41 /* What to do after SetScrollInfo() */
42 #define SA_SSI_HIDE 0x0001
43 #define SA_SSI_SHOW 0x0002
44 #define SA_SSI_REFRESH 0x0004
45 #define SA_SSI_REPAINT_ARROWS 0x0008
46
47 #define SBRG_SCROLLBAR 0 /* The scrollbar itself */
48 #define SBRG_TOPRIGHTBTN 1 /* The top or right button */
49 #define SBRG_PAGEUPRIGHT 2 /* The page up or page right region */
50 #define SBRG_SCROLLBOX 3 /* The scroll box */
51 #define SBRG_PAGEDOWNLEFT 4 /* The page down or page left region */
52 #define SBRG_BOTTOMLEFTBTN 5 /* The bottom or left button */
53
54 #define CHANGERGSTATE(item, status) \
55 if(Info->rgstate[(item)] != (status)) \
56 Chg = TRUE; \
57 Info->rgstate[(item)] = (status);
58
59 /* FUNCTIONS *****************************************************************/
60
61 /* Ported from WINE20020904 */
62 /* Compute the scroll bar rectangle, in drawing coordinates (i.e. client coords for SB_CTL, window coords for SB_VERT and
63 * SB_HORZ). 'arrowSize' returns the width or height of an arrow (depending on * the orientation of the scrollbar),
64 * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
65 * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
66 */
67 static inline void mirror_rect( const RECT *window_rect, RECT *rect )
68 {
69 int width = window_rect->right - window_rect->left;
70 int tmp = rect->left;
71 rect->left = width - rect->right;
72 rect->right = width - tmp;
73 }
74
75 PSBDATA FASTCALL
76 IntGetSBData(PWND pwnd, INT Bar)
77 {
78 PSBWND pSBWnd;
79 PSBINFO pSBInfo;
80
81 pSBInfo = pwnd->pSBInfo;
82 switch (Bar)
83 {
84 case SB_HORZ:
85 return &pSBInfo->Horz;
86 case SB_VERT:
87 return &pSBInfo->Vert;
88 case SB_CTL:
89 if ( pwnd->cbwndExtra != (sizeof(SBWND)-sizeof(WND)) )
90 {
91 ERR("IntGetSBData Wrong Extra bytes for CTL Scrollbar!\n");
92 return 0;
93 }
94 pSBWnd = (PSBWND)pwnd;
95 return (PSBDATA)&pSBWnd->SBCalc;
96 default:
97 ERR("IntGetSBData Bad Bar!\n");
98 }
99 return NULL;
100 }
101
102 BOOL FASTCALL
103 IntGetScrollBarRect (PWND Wnd, INT nBar, RECTL *lprect)
104 {
105 BOOL vertical;
106 *lprect = Wnd->rcClient;
107
108 RECTL_vOffsetRect( lprect, -Wnd->rcWindow.left, -Wnd->rcWindow.top );
109 if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
110 mirror_rect( &Wnd->rcWindow, lprect );
111
112 switch (nBar)
113 {
114 case SB_HORZ:
115 lprect->top = lprect->bottom;
116 lprect->bottom += UserGetSystemMetrics (SM_CYHSCROLL);
117 if (Wnd->style & WS_BORDER)
118 {
119 lprect->left--;
120 lprect->right++;
121 }
122 else if (Wnd->style & WS_VSCROLL)
123 {
124 lprect->right++;
125 }
126 vertical = FALSE;
127 break;
128
129 case SB_VERT:
130 if(Wnd->ExStyle & WS_EX_LEFTSCROLLBAR)
131 {
132 lprect->right = lprect->left;
133 lprect->left -= UserGetSystemMetrics(SM_CXVSCROLL);
134 }
135 else
136 {
137 lprect->left = lprect->right;
138 lprect->right += UserGetSystemMetrics(SM_CXVSCROLL);
139 }
140 if (Wnd->style & WS_BORDER)
141 {
142 lprect->top--;
143 lprect->bottom++;
144 }
145 else if (Wnd->style & WS_HSCROLL)
146 {
147 lprect->bottom++;
148 }
149 vertical = TRUE;
150 break;
151
152 case SB_CTL:
153 IntGetClientRect (Wnd, lprect);
154 vertical = !!(Wnd->style & SBS_VERT);
155 break;
156
157 default:
158 return FALSE;
159 }
160
161 return vertical;
162 }
163
164 BOOL FASTCALL
165 IntCalculateThumb(PWND Wnd, LONG idObject, PSCROLLBARINFO psbi, PSBDATA pSBData)
166 {
167 INT Thumb, ThumbBox, ThumbPos, cxy, mx;
168 RECTL ClientRect;
169
170 switch(idObject)
171 {
172 case SB_HORZ:
173 Thumb = UserGetSystemMetrics(SM_CXHSCROLL);
174 cxy = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
175 break;
176 case SB_VERT:
177 Thumb = UserGetSystemMetrics(SM_CYVSCROLL);
178 cxy = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
179 break;
180 case SB_CTL:
181 IntGetClientRect(Wnd, &ClientRect);
182 if(Wnd->style & SBS_VERT)
183 {
184 Thumb = UserGetSystemMetrics(SM_CYVSCROLL);
185 cxy = ClientRect.bottom - ClientRect.top;
186 }
187 else
188 {
189 Thumb = UserGetSystemMetrics(SM_CXHSCROLL);
190 cxy = ClientRect.right - ClientRect.left;
191 }
192 break;
193 default:
194 return FALSE;
195 }
196
197 ThumbPos = Thumb;
198 /* Calculate Thumb */
199 if(cxy <= (2 * Thumb))
200 {
201 Thumb = cxy / 2;
202 psbi->xyThumbTop = 0;
203 psbi->xyThumbBottom = 0;
204 ThumbPos = Thumb;
205 }
206 else
207 {
208 ThumbBox = pSBData->page ? MINTRACKTHUMB : UserGetSystemMetrics(SM_CXHTHUMB);
209 cxy -= (2 * Thumb);
210 if(cxy >= ThumbBox)
211 {
212 if(pSBData->page)
213 {
214 ThumbBox = max(EngMulDiv(cxy, pSBData->page, pSBData->posMax - pSBData->posMin + 1), ThumbBox);
215 }
216
217 if(cxy > ThumbBox)
218 {
219 mx = pSBData->posMax - max(pSBData->page - 1, 0);
220 if(pSBData->posMin < mx)
221 ThumbPos = Thumb + EngMulDiv(cxy - ThumbBox, pSBData->pos - pSBData->posMin, mx - pSBData->posMin);
222 else
223 ThumbPos = Thumb + ThumbBox;
224 }
225
226 psbi->xyThumbTop = ThumbPos;
227 psbi->xyThumbBottom = ThumbPos + ThumbBox;
228 }
229 else
230 {
231 psbi->xyThumbTop = 0;
232 psbi->xyThumbBottom = 0;
233 }
234 }
235 psbi->dxyLineButton = Thumb;
236
237 return TRUE;
238 }
239 /*
240 static VOID FASTCALL
241 IntUpdateSBInfo(PWND Window, int wBar)
242 {
243 PSCROLLBARINFO sbi;
244 PSBDATA pSBData;
245
246 ASSERT(Window);
247 ASSERT(Window->pSBInfo);
248 ASSERT(Window->pSBInfoex);
249
250 sbi = IntGetScrollbarInfoFromWindow(Window, wBar);
251 pSBData = IntGetSBData(Window, wBar);
252 IntGetScrollBarRect(Window, wBar, &(sbi->rcScrollBar));
253 IntCalculateThumb(Window, wBar, sbi, pSBData);
254 }
255 */
256 static BOOL FASTCALL
257 co_IntGetScrollInfo(PWND Window, INT nBar, PSBDATA pSBData, LPSCROLLINFO lpsi)
258 {
259 UINT Mask;
260 LPSCROLLINFO psi;
261
262 ASSERT_REFS_CO(Window);
263
264 if(!SBID_IS_VALID(nBar))
265 {
266 EngSetLastError(ERROR_INVALID_PARAMETER);
267 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar);
268 return FALSE;
269 }
270
271 if (!Window->pSBInfo)
272 {
273 ERR("IntGetScrollInfo No window scrollbar info!\n");
274 return FALSE;
275 }
276
277 psi = IntGetScrollInfoFromWindow(Window, nBar);
278
279 if (lpsi->fMask == SIF_ALL)
280 {
281 Mask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
282 }
283 else
284 {
285 Mask = lpsi->fMask;
286 }
287
288 if (0 != (Mask & SIF_PAGE))
289 {
290 lpsi->nPage = psi->nPage;
291 }
292
293 if (0 != (Mask & SIF_POS))
294 {
295 lpsi->nPos = psi->nPos;
296 }
297
298 if (0 != (Mask & SIF_RANGE))
299 {
300 lpsi->nMin = psi->nMin;
301 lpsi->nMax = psi->nMax;
302 }
303
304 if (0 != (Mask & SIF_TRACKPOS))
305 {
306 lpsi->nTrackPos = psi->nTrackPos;
307 }
308
309 return TRUE;
310 }
311
312 BOOL FASTCALL
313 NEWco_IntGetScrollInfo(
314 PWND pWnd,
315 INT nBar,
316 PSBDATA pSBData,
317 LPSCROLLINFO lpsi)
318 {
319 UINT Mask;
320 PSBTRACK pSBTrack = pWnd->head.pti->pSBTrack;
321
322 if (!SBID_IS_VALID(nBar))
323 {
324 EngSetLastError(ERROR_INVALID_PARAMETER);
325 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar);
326 return FALSE;
327 }
328
329 if (!pWnd->pSBInfo || !pSBTrack) return FALSE;
330
331 Mask = lpsi->fMask;
332
333 if (0 != (Mask & SIF_PAGE))
334 {
335 lpsi->nPage = pSBData->page;
336 }
337
338 if (0 != (Mask & SIF_POS))
339 {
340 lpsi->nPos = pSBData->pos;
341 }
342
343 if (0 != (Mask & SIF_RANGE))
344 {
345 lpsi->nMin = pSBData->posMin;
346 lpsi->nMax = pSBData->posMax;
347 }
348
349 if (0 != (Mask & SIF_TRACKPOS))
350 {
351 if ( pSBTrack &&
352 pSBTrack->nBar == nBar &&
353 pSBTrack->spwndTrack == pWnd )
354 lpsi->nTrackPos = pSBTrack->posNew;
355 else
356 lpsi->nTrackPos = pSBData->pos;
357 }
358 return (Mask & SIF_ALL) !=0;
359 }
360
361 static DWORD FASTCALL
362 co_IntSetScrollInfo(PWND Window, INT nBar, LPCSCROLLINFO lpsi, BOOL bRedraw)
363 {
364 /*
365 * Update the scrollbar state and set action flags according to
366 * what has to be done graphics wise.
367 */
368
369 LPSCROLLINFO Info;
370 PSCROLLBARINFO psbi;
371 UINT new_flags;
372 INT action = 0;
373 PSBDATA pSBData;
374 DWORD OldPos = 0;
375 BOOL bChangeParams = FALSE; /* Don't show/hide scrollbar if params don't change */
376 UINT MaxPage;
377 int MaxPos;
378
379 ASSERT_REFS_CO(Window);
380
381 if(!SBID_IS_VALID(nBar))
382 {
383 EngSetLastError(ERROR_INVALID_PARAMETER);
384 ERR("Trying to set scrollinfo for unknown scrollbar type %d", nBar);
385 return FALSE;
386 }
387
388 if(!co_IntCreateScrollBars(Window))
389 {
390 return FALSE;
391 }
392
393 if (lpsi->cbSize != sizeof(SCROLLINFO) &&
394 lpsi->cbSize != (sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos)))
395 {
396 EngSetLastError(ERROR_INVALID_PARAMETER);
397 return 0;
398 }
399 if (lpsi->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL | SIF_PREVIOUSPOS))
400 {
401 EngSetLastError(ERROR_INVALID_PARAMETER);
402 return 0;
403 }
404
405 psbi = IntGetScrollbarInfoFromWindow(Window, nBar);
406 Info = IntGetScrollInfoFromWindow(Window, nBar);
407 pSBData = IntGetSBData(Window, nBar);
408
409 /* Set the page size */
410 if (lpsi->fMask & SIF_PAGE)
411 {
412 if (Info->nPage != lpsi->nPage)
413 {
414 Info->nPage = lpsi->nPage;
415 pSBData->page = lpsi->nPage;
416 bChangeParams = TRUE;
417 }
418 }
419
420 /* Set the scroll pos */
421 if (lpsi->fMask & SIF_POS)
422 {
423 if (Info->nPos != lpsi->nPos)
424 {
425 OldPos = Info->nPos;
426 Info->nPos = lpsi->nPos;
427 pSBData->pos = lpsi->nPos;
428 bChangeParams = TRUE;
429 }
430 }
431
432 /* Set the scroll range */
433 if (lpsi->fMask & SIF_RANGE)
434 {
435 if (lpsi->nMin > lpsi->nMax)
436 {
437 Info->nMin = lpsi->nMin;
438 Info->nMax = lpsi->nMin;
439 pSBData->posMin = lpsi->nMin;
440 pSBData->posMax = lpsi->nMin;
441 bChangeParams = TRUE;
442 }
443 else if (Info->nMin != lpsi->nMin || Info->nMax != lpsi->nMax)
444 {
445 Info->nMin = lpsi->nMin;
446 Info->nMax = lpsi->nMax;
447 pSBData->posMin = lpsi->nMin;
448 pSBData->posMax = lpsi->nMax;
449 bChangeParams = TRUE;
450 }
451 }
452
453 /* Make sure the page size is valid */
454 MaxPage = abs(Info->nMax - Info->nMin) + 1;
455 if (Info->nPage > MaxPage)
456 {
457 pSBData->page = Info->nPage = MaxPage;
458 }
459
460 /* Make sure the pos is inside the range */
461 MaxPos = Info->nMax + 1 - (int)max(Info->nPage, 1);
462 ASSERT(MaxPos >= Info->nMin);
463 if (Info->nPos < Info->nMin)
464 {
465 pSBData->pos = Info->nPos = Info->nMin;
466 }
467 else if (Info->nPos > MaxPos)
468 {
469 pSBData->pos = Info->nPos = MaxPos;
470 }
471
472 /*
473 * Don't change the scrollbar state if SetScrollInfo is just called
474 * with SIF_DISABLENOSCROLL
475 */
476 if (!(lpsi->fMask & SIF_ALL))
477 {
478 //goto done;
479 return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos;
480 }
481
482 /* Check if the scrollbar should be hidden or disabled */
483 if (lpsi->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL))
484 {
485 new_flags = Window->pSBInfo->WSBflags;
486 if (Info->nMin >= (int)(Info->nMax - max(Info->nPage - 1, 0)))
487 {
488 /* Hide or disable scroll-bar */
489 if (lpsi->fMask & SIF_DISABLENOSCROLL)
490 {
491 new_flags = ESB_DISABLE_BOTH;
492 bChangeParams = TRUE;
493 }
494 else if ((nBar != SB_CTL) && bChangeParams)
495 {
496 action = SA_SSI_HIDE;
497 }
498 }
499 else /* Show and enable scroll-bar only if no page only changed. */
500 if (lpsi->fMask != SIF_PAGE)
501 {
502 new_flags = ESB_ENABLE_BOTH;
503 if ((nBar != SB_CTL) && bChangeParams)
504 {
505 action |= SA_SSI_SHOW;
506 }
507 }
508
509 if (Window->pSBInfo->WSBflags != new_flags) /* Check arrow flags */
510 {
511 Window->pSBInfo->WSBflags = new_flags;
512 action |= SA_SSI_REPAINT_ARROWS;
513 }
514 }
515
516 //done:
517 if ( action & SA_SSI_HIDE )
518 {
519 co_UserShowScrollBar(Window, nBar, FALSE, FALSE);
520 }
521 else
522 {
523 if ( action & SA_SSI_SHOW )
524 if ( co_UserShowScrollBar(Window, nBar, TRUE, TRUE) )
525 return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos; /* SetWindowPos() already did the painting */
526 if (bRedraw)
527 { // FIXME: Arrows and interior.
528 RECTL UpdateRect = psbi->rcScrollBar;
529 UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
530 UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
531 UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
532 UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
533 co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
534 } // FIXME: Arrows
535 /* else if( action & SA_SSI_REPAINT_ARROWS )
536 {
537 RECTL UpdateRect = psbi->rcScrollBar;
538 UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
539 UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
540 UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
541 UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
542 co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
543 }
544 */ }
545 /* Return current position */
546 return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos;
547 }
548
549 BOOL FASTCALL
550 co_IntGetScrollBarInfo(PWND Window, LONG idObject, PSCROLLBARINFO psbi)
551 {
552 INT Bar;
553 PSCROLLBARINFO sbi;
554 PSBDATA pSBData;
555 ASSERT_REFS_CO(Window);
556
557 Bar = SBOBJ_TO_SBID(idObject);
558
559 if(!SBID_IS_VALID(Bar))
560 {
561 EngSetLastError(ERROR_INVALID_PARAMETER);
562 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
563 return FALSE;
564 }
565
566 if(!co_IntCreateScrollBars(Window))
567 {
568 ERR("Failed to create scrollbars for window.\n");
569 return FALSE;
570 }
571
572 sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
573 pSBData = IntGetSBData(Window, Bar);
574
575 IntGetScrollBarRect(Window, Bar, &(sbi->rcScrollBar));
576 IntCalculateThumb(Window, Bar, sbi, pSBData);
577
578 RtlCopyMemory(psbi, sbi, sizeof(SCROLLBARINFO));
579
580 return TRUE;
581 }
582
583 BOOL FASTCALL
584 co_IntSetScrollBarInfo(PWND Window, LONG idObject, PSETSCROLLBARINFO psbi)
585 {
586 INT Bar;
587 PSCROLLBARINFO sbi;
588 LPSCROLLINFO psi;
589 ASSERT_REFS_CO(Window);
590
591 Bar = SBOBJ_TO_SBID(idObject);
592
593 if(!SBID_IS_VALID(Bar))
594 {
595 EngSetLastError(ERROR_INVALID_PARAMETER);
596 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
597 return FALSE;
598 }
599
600 if(!co_IntCreateScrollBars(Window))
601 {
602 ERR("Failed to create scrollbars for window.\n");
603 return FALSE;
604 }
605
606 sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
607 psi = IntGetScrollInfoFromWindow(Window, Bar);
608
609 psi->nTrackPos = psbi->nTrackPos;
610 sbi->reserved = psbi->reserved;
611 RtlCopyMemory(&sbi->rgstate, &psbi->rgstate, sizeof(psbi->rgstate));
612
613 return TRUE;
614 }
615
616 BOOL FASTCALL
617 co_IntCreateScrollBars(PWND Window)
618 {
619 PSCROLLBARINFO psbi;
620 PSBDATA pSBData;
621 ULONG Size, s;
622 INT i;
623
624 ASSERT_REFS_CO(Window);
625
626 if (Window->pSBInfo && Window->pSBInfoex)
627 {
628 /* No need to create it anymore */
629 return TRUE;
630 }
631
632 /* Allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
633 Size = 3 * (sizeof(SBINFOEX));
634 if(!(Window->pSBInfoex = ExAllocatePoolWithTag(PagedPool, Size, TAG_SBARINFO)))
635 {
636 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window->head.h);
637 return FALSE;
638 }
639
640 RtlZeroMemory(Window->pSBInfoex, Size);
641
642 if(!(Window->pSBInfo = DesktopHeapAlloc( Window->head.rpdesk, sizeof(SBINFO))))
643 {
644 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window->head.h);
645 return FALSE;
646 }
647
648 RtlZeroMemory(Window->pSBInfo, sizeof(SBINFO));
649 Window->pSBInfo->Vert.posMax = 100;
650 Window->pSBInfo->Horz.posMax = 100;
651
652 co_WinPosGetNonClientSize(Window,
653 &Window->rcWindow,
654 &Window->rcClient);
655
656 for(s = SB_HORZ; s <= SB_VERT; s++)
657 {
658 psbi = IntGetScrollbarInfoFromWindow(Window, s);
659 psbi->cbSize = sizeof(SCROLLBARINFO);
660 for (i = 0; i < CCHILDREN_SCROLLBAR + 1; i++)
661 psbi->rgstate[i] = 0;
662
663 pSBData = IntGetSBData(Window, s);
664
665 IntGetScrollBarRect(Window, s, &(psbi->rcScrollBar));
666 IntCalculateThumb(Window, s, psbi, pSBData);
667 }
668
669 return TRUE;
670 }
671
672 BOOL FASTCALL
673 IntDestroyScrollBars(PWND Window)
674 {
675 if (Window->pSBInfo && Window->pSBInfoex)
676 {
677 DesktopHeapFree(Window->head.rpdesk, Window->pSBInfo);
678 Window->pSBInfo = NULL;
679 ExFreePoolWithTag(Window->pSBInfoex, TAG_SBARINFO);
680 Window->pSBInfoex = NULL;
681 return TRUE;
682 }
683 return FALSE;
684 }
685
686 BOOL APIENTRY
687 IntEnableScrollBar(BOOL Horz, PSCROLLBARINFO Info, UINT wArrows)
688 {
689 BOOL Chg = FALSE;
690 switch(wArrows)
691 {
692 case ESB_DISABLE_BOTH:
693 CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
694 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
695 break;
696 case ESB_DISABLE_RTDN:
697 if(Horz)
698 {
699 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
700 }
701 else
702 {
703 CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
704 }
705 break;
706 case ESB_DISABLE_LTUP:
707 if(Horz)
708 {
709 CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
710 }
711 else
712 {
713 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
714 }
715 break;
716 case ESB_ENABLE_BOTH:
717 CHANGERGSTATE(SBRG_TOPRIGHTBTN, 0);
718 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, 0);
719 break;
720 }
721 return Chg;
722 }
723
724 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
725 DWORD FASTCALL
726 co_UserShowScrollBar(PWND Wnd, int nBar, BOOL fShowH, BOOL fShowV)
727 {
728 ULONG old_style, set_bits = 0, clear_bits = 0;
729
730 ASSERT_REFS_CO(Wnd);
731
732 switch(nBar)
733 {
734 case SB_CTL:
735 {
736 //IntUpdateSBInfo(Wnd, SB_CTL); // Is this needed? Was tested w/o!
737
738 co_WinPosShowWindow(Wnd, fShowH ? SW_SHOW : SW_HIDE);
739 return TRUE;
740 }
741 case SB_BOTH:
742 case SB_HORZ:
743 if (fShowH) set_bits |= WS_HSCROLL;
744 else clear_bits |= WS_HSCROLL;
745 if( nBar == SB_HORZ ) break;
746 /* Fall through */
747 case SB_VERT:
748 if (fShowV) set_bits |= WS_VSCROLL;
749 else clear_bits |= WS_VSCROLL;
750 break;
751 default:
752 EngSetLastError(ERROR_INVALID_PARAMETER);
753 return FALSE;
754 }
755
756 old_style = IntSetStyle( Wnd, set_bits, clear_bits );
757 if ((old_style & clear_bits) != 0 || (old_style & set_bits) != set_bits)
758 {
759 ///// Is this needed? Was tested w/o!
760 //if (Wnd->style & WS_HSCROLL) IntUpdateSBInfo(Wnd, SB_HORZ);
761 //if (Wnd->style & WS_VSCROLL) IntUpdateSBInfo(Wnd, SB_VERT);
762 /////
763 /* Frame has been changed, let the window redraw itself */
764 co_WinPosSetWindowPos(Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
765 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOSENDCHANGING);
766 return TRUE;
767 }
768 return FALSE;
769 }
770
771 static void
772 IntDrawScrollInterior(PWND pWnd, HDC hDC, INT nBar, BOOL Vertical, PSCROLLBARINFO ScrollBarInfo)
773 {
774 INT ThumbSize = ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
775 INT ThumbTop = ScrollBarInfo->xyThumbTop;
776 RECT Rect;
777 HBRUSH hSaveBrush, hBrush;
778 BOOL TopSelected = FALSE, BottomSelected = FALSE;
779
780 if (ScrollBarInfo->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED)
781 TopSelected = TRUE;
782 if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED)
783 BottomSelected = TRUE;
784
785 /*
786 * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
787 * The window-owned scrollbars need to call DefWndControlColor
788 * to correctly setup default scrollbar colors
789 */
790 if (nBar == SB_CTL)
791 {
792 hBrush = GetControlBrush( pWnd, hDC, WM_CTLCOLORSCROLLBAR);
793 if (!hBrush)
794 hBrush = IntGetSysColorBrush(COLOR_SCROLLBAR);
795 }
796 else
797 {
798 hBrush = DefWndControlColor(hDC, CTLCOLOR_SCROLLBAR);
799 }
800
801 hSaveBrush = NtGdiSelectBrush(hDC, hBrush);
802
803 /* Calculate the scroll rectangle */
804 if (Vertical)
805 {
806 Rect.top = ScrollBarInfo->rcScrollBar.top + ScrollBarInfo->dxyLineButton;
807 Rect.bottom = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->dxyLineButton;
808 Rect.left = ScrollBarInfo->rcScrollBar.left;
809 Rect.right = ScrollBarInfo->rcScrollBar.right;
810 }
811 else
812 {
813 Rect.top = ScrollBarInfo->rcScrollBar.top;
814 Rect.bottom = ScrollBarInfo->rcScrollBar.bottom;
815 Rect.left = ScrollBarInfo->rcScrollBar.left + ScrollBarInfo->dxyLineButton;
816 Rect.right = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->dxyLineButton;
817 }
818
819 /* Draw the scroll rectangles and thumb */
820 if (!ScrollBarInfo->xyThumbBottom)
821 {
822 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
823 Rect.bottom - Rect.top, PATCOPY);
824
825 /* Cleanup and return */
826 NtGdiSelectBrush(hDC, hSaveBrush);
827 return;
828 }
829
830 ThumbTop -= ScrollBarInfo->dxyLineButton;
831
832 if (ScrollBarInfo->dxyLineButton)
833 {
834 if (Vertical)
835 {
836 if (ThumbSize)
837 {
838 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
839 ThumbTop, TopSelected ? BLACKNESS : PATCOPY);
840 Rect.top += ThumbTop;
841 NtGdiPatBlt(hDC, Rect.left, Rect.top + ThumbSize, Rect.right - Rect.left,
842 Rect.bottom - Rect.top - ThumbSize, BottomSelected ? BLACKNESS : PATCOPY);
843 Rect.bottom = Rect.top + ThumbSize;
844 }
845 else
846 {
847 if (ThumbTop)
848 {
849 NtGdiPatBlt(hDC, Rect.left, ScrollBarInfo->dxyLineButton,
850 Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
851 }
852 }
853 }
854 else
855 {
856 if (ThumbSize)
857 {
858 NtGdiPatBlt(hDC, Rect.left, Rect.top, ThumbTop,
859 Rect.bottom - Rect.top, TopSelected ? BLACKNESS : PATCOPY);
860 Rect.left += ThumbTop;
861 NtGdiPatBlt(hDC, Rect.left + ThumbSize, Rect.top,
862 Rect.right - Rect.left - ThumbSize, Rect.bottom - Rect.top,
863 BottomSelected ? BLACKNESS : PATCOPY);
864 Rect.right = Rect.left + ThumbSize;
865 }
866 else
867 {
868 if (ThumbTop)
869 {
870 NtGdiPatBlt(hDC, ScrollBarInfo->dxyLineButton, Rect.top,
871 Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
872 }
873 }
874 }
875 }
876
877 /* Draw the thumb */
878 if (ThumbSize)
879 DrawEdge(hDC, &Rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
880
881 /* Cleanup */
882 NtGdiSelectBrush(hDC, hSaveBrush);
883 }
884
885
886 static VOID FASTCALL
887 IntDrawScrollArrows(HDC hDC, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
888 {
889 RECT RectLT, RectRB;
890 INT ScrollDirFlagLT, ScrollDirFlagRB;
891
892 RectLT = RectRB = ScrollBarInfo->rcScrollBar;
893 if (Vertical)
894 {
895 ScrollDirFlagLT = DFCS_SCROLLUP;
896 ScrollDirFlagRB = DFCS_SCROLLDOWN;
897 RectLT.bottom = RectLT.top + ScrollBarInfo->dxyLineButton;
898 RectRB.top = RectRB.bottom - ScrollBarInfo->dxyLineButton;
899 }
900 else
901 {
902 ScrollDirFlagLT = DFCS_SCROLLLEFT;
903 ScrollDirFlagRB = DFCS_SCROLLRIGHT;
904 RectLT.right = RectLT.left + ScrollBarInfo->dxyLineButton;
905 RectRB.left = RectRB.right - ScrollBarInfo->dxyLineButton;
906 }
907
908 if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_PRESSED)
909 {
910 ScrollDirFlagLT |= DFCS_PUSHED | DFCS_FLAT;
911 }
912 if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE)
913 {
914 ScrollDirFlagLT |= DFCS_INACTIVE;
915 }
916 if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_PRESSED)
917 {
918 ScrollDirFlagRB |= DFCS_PUSHED | DFCS_FLAT;
919 }
920 if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE)
921 {
922 ScrollDirFlagRB |= DFCS_INACTIVE;
923 }
924
925 DrawFrameControl(hDC, &RectLT, DFC_SCROLL, ScrollDirFlagLT);
926 DrawFrameControl(hDC, &RectRB, DFC_SCROLL, ScrollDirFlagRB);
927 }
928
929 static LONG FASTCALL
930 IntScrollGetObjectId(INT SBType)
931 {
932 if (SBType == SB_VERT)
933 return OBJID_VSCROLL;
934 if (SBType == SB_HORZ)
935 return OBJID_HSCROLL;
936 return OBJID_CLIENT;
937 }
938
939 void
940 IntDrawScrollBar(PWND Wnd, HDC DC, INT Bar)
941 {
942 //PSBWND pSBWnd;
943 //INT ThumbSize;
944 PTHREADINFO pti;
945 SCROLLBARINFO Info;
946 BOOL Vertical;
947
948 pti = PsGetCurrentThreadWin32Thread();
949
950 /*
951 * Get scroll bar info.
952 */
953 switch (Bar)
954 {
955 case SB_HORZ:
956 Vertical = FALSE;
957 break;
958
959 case SB_VERT:
960 Vertical = TRUE;
961 break;
962
963 case SB_CTL:
964 Vertical = (Wnd->style & SBS_VERT) != 0;
965 break;
966
967 default:
968 return;
969 }
970
971 if (!co_IntGetScrollBarInfo(Wnd, IntScrollGetObjectId(Bar), &Info))
972 {
973 return;
974 }
975
976 if (RECTL_bIsEmptyRect(&Info.rcScrollBar))
977 {
978 return;
979 }
980
981 //ThumbSize = pSBWnd->pSBCalc->pxThumbBottom - pSBWnd->pSBCalc->pxThumbTop;
982
983 /*
984 * Draw the arrows.
985 */
986 if (Info.dxyLineButton)
987 {
988 IntDrawScrollArrows(DC, &Info, Vertical);
989 }
990
991 /*
992 * Draw the interior.
993 */
994 IntDrawScrollInterior(Wnd, DC, Bar, Vertical, &Info);
995
996 /*
997 * If scroll bar has focus, reposition the caret.
998 */
999 if ( Wnd == pti->MessageQueue->spwndFocus && Bar == SB_CTL )
1000 {
1001 if (Vertical)
1002 {
1003 co_IntSetCaretPos(Info.rcScrollBar.top + 1, Info.dxyLineButton + 1);
1004 }
1005 else
1006 {
1007 co_IntSetCaretPos(Info.dxyLineButton + 1, Info.rcScrollBar.top + 1);
1008 }
1009 }
1010 }
1011
1012
1013 LRESULT APIENTRY
1014 ScrollBarWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
1015 {
1016 LRESULT lResult = 0;
1017 PWND pWnd;
1018 pWnd = UserGetWindowObject(hWnd);
1019 if (!pWnd) return 0;
1020
1021 switch(Msg)
1022 {
1023 case WM_ENABLE:
1024 {
1025 if (pWnd->pSBInfo)
1026 {
1027 pWnd->pSBInfo->WSBflags = wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
1028 }
1029 }
1030 break;
1031 }
1032 return lResult;
1033 }
1034
1035 ////
1036
1037 BOOL
1038 APIENTRY
1039 NtUserGetScrollBarInfo(HWND hWnd, LONG idObject, PSCROLLBARINFO psbi)
1040 {
1041 NTSTATUS Status;
1042 SCROLLBARINFO sbi;
1043 PWND Window;
1044 BOOL Ret;
1045 DECLARE_RETURN(BOOL);
1046 USER_REFERENCE_ENTRY Ref;
1047
1048 TRACE("Enter NtUserGetScrollBarInfo\n");
1049 UserEnterExclusive();
1050
1051 Status = MmCopyFromCaller(&sbi, psbi, sizeof(SCROLLBARINFO));
1052 if(!NT_SUCCESS(Status) || (sbi.cbSize != sizeof(SCROLLBARINFO)))
1053 {
1054 SetLastNtError(Status);
1055 RETURN(FALSE);
1056 }
1057
1058 if(!(Window = UserGetWindowObject(hWnd)))
1059 {
1060 RETURN(FALSE);
1061 }
1062
1063 UserRefObjectCo(Window, &Ref);
1064 Ret = co_IntGetScrollBarInfo(Window, idObject, &sbi);
1065 UserDerefObjectCo(Window);
1066
1067 Status = MmCopyToCaller(psbi, &sbi, sizeof(SCROLLBARINFO));
1068 if(!NT_SUCCESS(Status))
1069 {
1070 SetLastNtError(Status);
1071 Ret = FALSE;
1072 }
1073
1074 RETURN( Ret);
1075
1076 CLEANUP:
1077 TRACE("Leave NtUserGetScrollBarInfo, ret=%i\n",_ret_);
1078 UserLeave();
1079 END_CLEANUP;
1080
1081 }
1082
1083 BOOL
1084 APIENTRY
1085 NtUserSBGetParms(
1086 HWND hWnd,
1087 int fnBar,
1088 PSBDATA pSBData,
1089 LPSCROLLINFO lpsi)
1090 {
1091 PWND Window;
1092 SCROLLINFO psi;
1093 BOOL Ret;
1094 SBDATA SBDataSafe;
1095 DECLARE_RETURN(BOOL);
1096 USER_REFERENCE_ENTRY Ref;
1097
1098 TRACE("Enter NtUserGetScrollInfo\n");
1099 UserEnterShared();
1100
1101 _SEH2_TRY
1102 {
1103 RtlCopyMemory(&psi, lpsi, sizeof(SCROLLINFO));
1104 if (pSBData)
1105 {
1106 RtlCopyMemory(&SBDataSafe, pSBData, sizeof(SBDATA));
1107 }
1108 }
1109 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1110 {
1111 ERR("NtUserGetScrollInfo Failed size.\n");
1112 SetLastNtError(_SEH2_GetExceptionCode());
1113 _SEH2_YIELD(RETURN(FALSE));
1114 }
1115 _SEH2_END
1116
1117 if(!(Window = UserGetWindowObject(hWnd)))
1118 {
1119 ERR("NtUserGetScrollInfo Bad window.\n");
1120 RETURN(FALSE);
1121 }
1122
1123 UserRefObjectCo(Window, &Ref);
1124 Ret = co_IntGetScrollInfo(Window, fnBar, &SBDataSafe, &psi);
1125 UserDerefObjectCo(Window);
1126
1127 _SEH2_TRY
1128 {
1129 RtlCopyMemory(lpsi, &psi, sizeof(SCROLLINFO));
1130 }
1131 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1132 {
1133 ERR("NtUserGetScrollInfo Failed copy to user.\n");
1134 SetLastNtError(_SEH2_GetExceptionCode());
1135 _SEH2_YIELD(RETURN(FALSE));
1136 }
1137 _SEH2_END
1138
1139 RETURN( Ret);
1140
1141 CLEANUP:
1142 TRACE("Leave NtUserGetScrollInfo, ret=%i\n",_ret_);
1143 UserLeave();
1144 END_CLEANUP;
1145 }
1146
1147 BOOL
1148 APIENTRY
1149 NtUserEnableScrollBar(
1150 HWND hWnd,
1151 UINT wSBflags,
1152 UINT wArrows)
1153 {
1154 UINT OrigArrows;
1155 PWND Window = NULL;
1156 PSCROLLBARINFO InfoV = NULL, InfoH = NULL;
1157 BOOL Chg = FALSE;
1158 DECLARE_RETURN(BOOL);
1159 USER_REFERENCE_ENTRY Ref;
1160
1161 TRACE("Enter NtUserEnableScrollBar\n");
1162 UserEnterExclusive();
1163
1164 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
1165 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
1166 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
1167 {
1168 RETURN(FALSE);
1169 }
1170 UserRefObjectCo(Window, &Ref);
1171
1172 if (!co_IntCreateScrollBars(Window))
1173 {
1174 RETURN( FALSE);
1175 }
1176
1177 OrigArrows = Window->pSBInfo->WSBflags;
1178 Window->pSBInfo->WSBflags = wArrows;
1179
1180 if (wSBflags == SB_CTL)
1181 {
1182 if ((wArrows == ESB_DISABLE_BOTH || wArrows == ESB_ENABLE_BOTH))
1183 IntEnableWindow(hWnd, (wArrows == ESB_ENABLE_BOTH));
1184
1185 RETURN(TRUE);
1186 }
1187
1188 if(wSBflags != SB_BOTH && !SBID_IS_VALID(wSBflags))
1189 {
1190 EngSetLastError(ERROR_INVALID_PARAMETER);
1191 ERR("Trying to set scrollinfo for unknown scrollbar type %u", wSBflags);
1192 RETURN(FALSE);
1193 }
1194
1195 switch(wSBflags)
1196 {
1197 case SB_BOTH:
1198 InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
1199 /* Fall through */
1200 case SB_HORZ:
1201 InfoH = IntGetScrollbarInfoFromWindow(Window, SB_HORZ);
1202 break;
1203 case SB_VERT:
1204 InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
1205 break;
1206 default:
1207 RETURN(FALSE);
1208 }
1209
1210 if(InfoV)
1211 Chg = IntEnableScrollBar(FALSE, InfoV, wArrows);
1212
1213 if(InfoH)
1214 Chg = (IntEnableScrollBar(TRUE, InfoH, wArrows) || Chg);
1215
1216 ERR("FIXME: EnableScrollBar wSBflags %u wArrows %u Chg %d\n", wSBflags, wArrows, Chg);
1217 // Done in user32:
1218 // SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1219
1220 RETURN( Chg);
1221 if (OrigArrows == wArrows) RETURN( FALSE);
1222 RETURN( TRUE);
1223
1224 CLEANUP:
1225 if (Window)
1226 UserDerefObjectCo(Window);
1227
1228 TRACE("Leave NtUserEnableScrollBar, ret=%i\n",_ret_);
1229 UserLeave();
1230 END_CLEANUP;
1231 }
1232
1233 DWORD
1234 APIENTRY
1235 NtUserSetScrollInfo(
1236 HWND hWnd,
1237 int fnBar,
1238 LPCSCROLLINFO lpsi,
1239 BOOL bRedraw)
1240 {
1241 PWND Window = NULL;
1242 NTSTATUS Status;
1243 SCROLLINFO ScrollInfo;
1244 DECLARE_RETURN(DWORD);
1245 USER_REFERENCE_ENTRY Ref;
1246
1247 TRACE("Enter NtUserSetScrollInfo\n");
1248 UserEnterExclusive();
1249
1250 if(!(Window = UserGetWindowObject(hWnd)) || // FIXME:
1251 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
1252 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
1253 {
1254 RETURN( 0);
1255 }
1256 UserRefObjectCo(Window, &Ref);
1257
1258 Status = MmCopyFromCaller(&ScrollInfo, lpsi, sizeof(SCROLLINFO) - sizeof(ScrollInfo.nTrackPos));
1259 if(!NT_SUCCESS(Status))
1260 {
1261 SetLastNtError(Status);
1262 RETURN( 0);
1263 }
1264
1265 RETURN(co_IntSetScrollInfo(Window, fnBar, &ScrollInfo, bRedraw));
1266
1267 CLEANUP:
1268 if (Window)
1269 UserDerefObjectCo(Window);
1270
1271 TRACE("Leave NtUserSetScrollInfo, ret=%lu\n", _ret_);
1272 UserLeave();
1273 END_CLEANUP;
1274
1275 }
1276
1277 DWORD APIENTRY
1278 NtUserShowScrollBar(HWND hWnd, int nBar, DWORD bShow)
1279 {
1280 PWND Window;
1281 DECLARE_RETURN(DWORD);
1282 DWORD ret;
1283 USER_REFERENCE_ENTRY Ref;
1284
1285 TRACE("Enter NtUserShowScrollBar\n");
1286 UserEnterExclusive();
1287
1288 if (!(Window = UserGetWindowObject(hWnd)))
1289 {
1290 RETURN(0);
1291 }
1292
1293 UserRefObjectCo(Window, &Ref);
1294 ret = co_UserShowScrollBar(Window, nBar, (nBar == SB_VERT) ? 0 : bShow,
1295 (nBar == SB_HORZ) ? 0 : bShow);
1296 UserDerefObjectCo(Window);
1297
1298 RETURN(ret);
1299
1300 CLEANUP:
1301 TRACE("Leave NtUserShowScrollBar, ret%lu\n", _ret_);
1302 UserLeave();
1303 END_CLEANUP;
1304
1305 }
1306
1307
1308 //// Ugly NtUser API ////
1309
1310 BOOL
1311 APIENTRY
1312 NtUserSetScrollBarInfo(
1313 HWND hWnd,
1314 LONG idObject,
1315 SETSCROLLBARINFO *info)
1316 {
1317 PWND Window = NULL;
1318 SETSCROLLBARINFO Safeinfo;
1319 PSCROLLBARINFO sbi;
1320 LPSCROLLINFO psi;
1321 NTSTATUS Status;
1322 LONG Obj;
1323 DECLARE_RETURN(BOOL);
1324 USER_REFERENCE_ENTRY Ref;
1325
1326 TRACE("Enter NtUserSetScrollBarInfo\n");
1327 UserEnterExclusive();
1328
1329 if(!(Window = UserGetWindowObject(hWnd)))
1330 {
1331 RETURN( FALSE);
1332 }
1333 UserRefObjectCo(Window, &Ref);
1334
1335 Obj = SBOBJ_TO_SBID(idObject);
1336 if(!SBID_IS_VALID(Obj))
1337 {
1338 EngSetLastError(ERROR_INVALID_PARAMETER);
1339 ERR("Trying to set scrollinfo for unknown scrollbar type %d\n", Obj);
1340 RETURN( FALSE);
1341 }
1342
1343 if(!co_IntCreateScrollBars(Window))
1344 {
1345 RETURN(FALSE);
1346 }
1347
1348 Status = MmCopyFromCaller(&Safeinfo, info, sizeof(SETSCROLLBARINFO));
1349 if(!NT_SUCCESS(Status))
1350 {
1351 SetLastNtError(Status);
1352 RETURN(FALSE);
1353 }
1354
1355 sbi = IntGetScrollbarInfoFromWindow(Window, Obj);
1356 psi = IntGetScrollInfoFromWindow(Window, Obj);
1357
1358 psi->nTrackPos = Safeinfo.nTrackPos;
1359 sbi->reserved = Safeinfo.reserved;
1360 RtlCopyMemory(&sbi->rgstate, &Safeinfo.rgstate, sizeof(Safeinfo.rgstate));
1361
1362 RETURN(TRUE);
1363
1364 CLEANUP:
1365 if (Window)
1366 UserDerefObjectCo(Window);
1367
1368 TRACE("Leave NtUserSetScrollBarInfo, ret=%i\n",_ret_);
1369 UserLeave();
1370 END_CLEANUP;
1371 }
1372
1373 /* EOF */