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