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