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