* Sync up to trunk head (r65353).
[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: subsys/win32k/ntuser/scrollbar.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
7 * Jason Filby (jasonfilby@yahoo.com)
8 */
9
10 #include <win32k.h>
11 DBG_DEFAULT_CHANNEL(UserScrollbar);
12
13 #define MINTRACKTHUMB 8 /* Minimum size of the rectangle between the arrows */
14
15 /* What to do after SetScrollInfo() */
16 #define SA_SSI_HIDE 0x0001
17 #define SA_SSI_SHOW 0x0002
18 #define SA_SSI_REFRESH 0x0004
19 #define SA_SSI_REPAINT_ARROWS 0x0008
20
21 #define SBRG_SCROLLBAR 0 /* The scrollbar itself */
22 #define SBRG_TOPRIGHTBTN 1 /* The top or right button */
23 #define SBRG_PAGEUPRIGHT 2 /* The page up or page right region */
24 #define SBRG_SCROLLBOX 3 /* The scroll box */
25 #define SBRG_PAGEDOWNLEFT 4 /* The page down or page left region */
26 #define SBRG_BOTTOMLEFTBTN 5 /* The bottom or left button */
27
28 #define CHANGERGSTATE(item, status) \
29 if(Info->rgstate[(item)] != (status)) \
30 Chg = TRUE; \
31 Info->rgstate[(item)] = (status);
32
33 /* FUNCTIONS *****************************************************************/
34
35 /* Ported from WINE20020904 */
36 /* Compute the scroll bar rectangle, in drawing coordinates (i.e. client coords for SB_CTL, window coords for SB_VERT and
37 * SB_HORZ). 'arrowSize' returns the width or height of an arrow (depending on * the orientation of the scrollbar),
38 * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
39 * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
40 */
41 static inline void mirror_rect( const RECT *window_rect, RECT *rect )
42 {
43 int width = window_rect->right - window_rect->left;
44 int tmp = rect->left;
45 rect->left = width - rect->right;
46 rect->right = width - tmp;
47 }
48
49 PSBDATA FASTCALL
50 IntGetSBData(PWND pwnd, INT Bar)
51 {
52 PSBWND pSBWnd;
53 PSBINFO pSBInfo;
54
55 pSBInfo = pwnd->pSBInfo;
56 switch (Bar)
57 {
58 case SB_HORZ:
59 return &pSBInfo->Horz;
60 case SB_VERT:
61 return &pSBInfo->Vert;
62 case SB_CTL:
63 if ( pwnd->cbwndExtra != (sizeof(SBWND)-sizeof(WND)) )
64 {
65 ERR("IntGetSBData Wrong Extra bytes for CTL Scrollbar!\n");
66 return 0;
67 }
68 pSBWnd = (PSBWND)pwnd;
69 return (PSBDATA)&pSBWnd->SBCalc;
70 default:
71 ERR("IntGetSBData Bad Bar!\n");
72 }
73 return NULL;
74 }
75
76 BOOL FASTCALL
77 IntGetScrollBarRect (PWND Wnd, INT nBar, RECTL *lprect)
78 {
79 BOOL vertical;
80 *lprect = Wnd->rcClient;
81
82 RECTL_vOffsetRect( lprect, -Wnd->rcWindow.left, -Wnd->rcWindow.top );
83 if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
84 mirror_rect( &Wnd->rcWindow, lprect );
85
86 switch (nBar)
87 {
88 case SB_HORZ:
89 lprect->top = lprect->bottom;
90 lprect->bottom += UserGetSystemMetrics (SM_CYHSCROLL);
91 if (Wnd->style & WS_BORDER)
92 {
93 lprect->left--;
94 lprect->right++;
95 }
96 else if (Wnd->style & WS_VSCROLL)
97 {
98 lprect->right++;
99 }
100 vertical = FALSE;
101 break;
102
103 case SB_VERT:
104 if(Wnd->ExStyle & WS_EX_LEFTSCROLLBAR)
105 {
106 lprect->right = lprect->left;
107 lprect->left -= UserGetSystemMetrics(SM_CXVSCROLL);
108 }
109 else
110 {
111 lprect->left = lprect->right;
112 lprect->right += UserGetSystemMetrics(SM_CXVSCROLL);
113 }
114 if (Wnd->style & WS_BORDER)
115 {
116 lprect->top--;
117 lprect->bottom++;
118 }
119 else if (Wnd->style & WS_HSCROLL)
120 {
121 lprect->bottom++;
122 }
123 vertical = TRUE;
124 break;
125
126 case SB_CTL:
127 IntGetClientRect (Wnd, lprect);
128 vertical = !!(Wnd->style & SBS_VERT);
129 break;
130
131 default:
132 return FALSE;
133 }
134
135 return vertical;
136 }
137
138 BOOL FASTCALL
139 IntCalculateThumb(PWND Wnd, LONG idObject, PSCROLLBARINFO psbi, PSBDATA pSBData)
140 {
141 INT Thumb, ThumbBox, ThumbPos, cxy, mx;
142 RECTL ClientRect;
143
144 switch(idObject)
145 {
146 case SB_HORZ:
147 Thumb = UserGetSystemMetrics(SM_CXHSCROLL);
148 cxy = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
149 break;
150 case SB_VERT:
151 Thumb = UserGetSystemMetrics(SM_CYVSCROLL);
152 cxy = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
153 break;
154 case SB_CTL:
155 IntGetClientRect(Wnd, &ClientRect);
156 if(Wnd->style & SBS_VERT)
157 {
158 Thumb = UserGetSystemMetrics(SM_CYVSCROLL);
159 cxy = ClientRect.bottom - ClientRect.top;
160 }
161 else
162 {
163 Thumb = UserGetSystemMetrics(SM_CXHSCROLL);
164 cxy = ClientRect.right - ClientRect.left;
165 }
166 break;
167 default:
168 return FALSE;
169 }
170
171 ThumbPos = Thumb;
172 /* Calculate Thumb */
173 if(cxy <= (2 * Thumb))
174 {
175 Thumb = cxy / 2;
176 psbi->xyThumbTop = 0;
177 psbi->xyThumbBottom = 0;
178 ThumbPos = Thumb;
179 }
180 else
181 {
182 ThumbBox = pSBData->page ? MINTRACKTHUMB : UserGetSystemMetrics(SM_CXHTHUMB);
183 cxy -= (2 * Thumb);
184 if(cxy >= ThumbBox)
185 {
186 if(pSBData->page)
187 {
188 ThumbBox = max(EngMulDiv(cxy, pSBData->page, pSBData->posMax - pSBData->posMin + 1), ThumbBox);
189 }
190
191 if(cxy > ThumbBox)
192 {
193 mx = pSBData->posMax - max(pSBData->page - 1, 0);
194 if(pSBData->posMin < mx)
195 ThumbPos = Thumb + EngMulDiv(cxy - ThumbBox, pSBData->pos - pSBData->posMin, mx - pSBData->posMin);
196 else
197 ThumbPos = Thumb + ThumbBox;
198 }
199
200 psbi->xyThumbTop = ThumbPos;
201 psbi->xyThumbBottom = ThumbPos + ThumbBox;
202 }
203 else
204 {
205 psbi->xyThumbTop = 0;
206 psbi->xyThumbBottom = 0;
207 }
208 }
209 psbi->dxyLineButton = Thumb;
210
211 return TRUE;
212 }
213 /*
214 static VOID FASTCALL
215 IntUpdateSBInfo(PWND Window, int wBar)
216 {
217 PSCROLLBARINFO sbi;
218 PSBDATA pSBData;
219
220 ASSERT(Window);
221 ASSERT(Window->pSBInfo);
222 ASSERT(Window->pSBInfoex);
223
224 sbi = IntGetScrollbarInfoFromWindow(Window, wBar);
225 pSBData = IntGetSBData(Window, wBar);
226 IntGetScrollBarRect(Window, wBar, &(sbi->rcScrollBar));
227 IntCalculateThumb(Window, wBar, sbi, pSBData);
228 }
229 */
230 static BOOL FASTCALL
231 co_IntGetScrollInfo(PWND Window, INT nBar, PSBDATA pSBData, LPSCROLLINFO lpsi)
232 {
233 UINT Mask;
234 LPSCROLLINFO psi;
235
236 ASSERT_REFS_CO(Window);
237
238 if(!SBID_IS_VALID(nBar))
239 {
240 EngSetLastError(ERROR_INVALID_PARAMETER);
241 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar);
242 return FALSE;
243 }
244
245 if (!Window->pSBInfo)
246 {
247 ERR("IntGetScrollInfo No window scrollbar info!\n");
248 return FALSE;
249 }
250
251 psi = IntGetScrollInfoFromWindow(Window, nBar);
252
253 if (lpsi->fMask == SIF_ALL)
254 {
255 Mask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
256 }
257 else
258 {
259 Mask = lpsi->fMask;
260 }
261
262 if (0 != (Mask & SIF_PAGE))
263 {
264 lpsi->nPage = psi->nPage;
265 }
266
267 if (0 != (Mask & SIF_POS))
268 {
269 lpsi->nPos = psi->nPos;
270 }
271
272 if (0 != (Mask & SIF_RANGE))
273 {
274 lpsi->nMin = psi->nMin;
275 lpsi->nMax = psi->nMax;
276 }
277
278 if (0 != (Mask & SIF_TRACKPOS))
279 {
280 lpsi->nTrackPos = psi->nTrackPos;
281 }
282
283 return TRUE;
284 }
285
286 BOOL FASTCALL
287 NEWco_IntGetScrollInfo(
288 PWND pWnd,
289 INT nBar,
290 PSBDATA pSBData,
291 LPSCROLLINFO lpsi)
292 {
293 UINT Mask;
294 PSBTRACK pSBTrack = pWnd->head.pti->pSBTrack;
295
296 if (!SBID_IS_VALID(nBar))
297 {
298 EngSetLastError(ERROR_INVALID_PARAMETER);
299 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar);
300 return FALSE;
301 }
302
303 if (!pWnd->pSBInfo || !pSBTrack) return FALSE;
304
305 Mask = lpsi->fMask;
306
307 if (0 != (Mask & SIF_PAGE))
308 {
309 lpsi->nPage = pSBData->page;
310 }
311
312 if (0 != (Mask & SIF_POS))
313 {
314 lpsi->nPos = pSBData->pos;
315 }
316
317 if (0 != (Mask & SIF_RANGE))
318 {
319 lpsi->nMin = pSBData->posMin;
320 lpsi->nMax = pSBData->posMax;
321 }
322
323 if (0 != (Mask & SIF_TRACKPOS))
324 {
325 if ( pSBTrack &&
326 pSBTrack->nBar == nBar &&
327 pSBTrack->spwndTrack == pWnd )
328 lpsi->nTrackPos = pSBTrack->posNew;
329 else
330 lpsi->nTrackPos = pSBData->pos;
331 }
332 return (Mask & SIF_ALL) !=0;
333 }
334
335 static DWORD FASTCALL
336 co_IntSetScrollInfo(PWND Window, INT nBar, LPCSCROLLINFO lpsi, BOOL bRedraw)
337 {
338 /*
339 * Update the scrollbar state and set action flags according to
340 * what has to be done graphics wise.
341 */
342
343 LPSCROLLINFO Info;
344 PSCROLLBARINFO psbi;
345 UINT new_flags;
346 INT action = 0;
347 PSBDATA pSBData;
348 DWORD OldPos = 0;
349 BOOL bChangeParams = FALSE; /* Don't show/hide scrollbar if params don't change */
350
351 ASSERT_REFS_CO(Window);
352
353 if(!SBID_IS_VALID(nBar))
354 {
355 EngSetLastError(ERROR_INVALID_PARAMETER);
356 ERR("Trying to set scrollinfo for unknown scrollbar type %d", nBar);
357 return FALSE;
358 }
359
360 if(!co_IntCreateScrollBars(Window))
361 {
362 return FALSE;
363 }
364
365 if (lpsi->cbSize != sizeof(SCROLLINFO) &&
366 lpsi->cbSize != (sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos)))
367 {
368 EngSetLastError(ERROR_INVALID_PARAMETER);
369 return 0;
370 }
371 if (lpsi->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL | SIF_PREVIOUSPOS))
372 {
373 EngSetLastError(ERROR_INVALID_PARAMETER);
374 return 0;
375 }
376
377 psbi = IntGetScrollbarInfoFromWindow(Window, nBar);
378 Info = IntGetScrollInfoFromWindow(Window, nBar);
379 pSBData = IntGetSBData(Window, nBar);
380
381 /* Set the page size */
382 if (lpsi->fMask & SIF_PAGE)
383 {
384 if (Info->nPage != lpsi->nPage)
385 {
386 Info->nPage = lpsi->nPage;
387 pSBData->page = lpsi->nPage;
388 bChangeParams = TRUE;
389 }
390 }
391
392 /* Set the scroll pos */
393 if (lpsi->fMask & SIF_POS)
394 {
395 if (Info->nPos != lpsi->nPos)
396 {
397 OldPos = Info->nPos;
398 Info->nPos = lpsi->nPos;
399 pSBData->pos = lpsi->nPos;
400 bChangeParams = TRUE;
401 }
402 }
403
404 /* Set the scroll range */
405 if (lpsi->fMask & SIF_RANGE)
406 {
407 /* Invalid range -> range is set to (0,0) */
408 if ((lpsi->nMin > lpsi->nMax) ||
409 ((UINT)(lpsi->nMax - lpsi->nMin) >= 0x80000000))
410 {
411 Info->nMin = 0;
412 Info->nMax = 0;
413 pSBData->posMin = 0;
414 pSBData->posMax = 0;
415 bChangeParams = TRUE;
416 }
417 else if (Info->nMin != lpsi->nMin || Info->nMax != lpsi->nMax)
418 {
419 Info->nMin = lpsi->nMin;
420 Info->nMax = lpsi->nMax;
421 pSBData->posMin = lpsi->nMin;
422 pSBData->posMax = lpsi->nMax;
423 bChangeParams = TRUE;
424 }
425 }
426
427 /* Make sure the page size is valid */
428 if (Info->nPage < 0)
429 {
430 pSBData->page = Info->nPage = 0;
431 }
432 else if ((Info->nMax - Info->nMin + 1UL) < Info->nPage)
433 {
434 pSBData->page = Info->nPage = Info->nMax - Info->nMin + 1;
435 }
436
437 /* Make sure the pos is inside the range */
438 if (Info->nPos < Info->nMin)
439 {
440 pSBData->pos = Info->nPos = Info->nMin;
441 }
442 else if (Info->nPos > (Info->nMax - max((int)Info->nPage - 1, 0)))
443 {
444 pSBData->pos = Info->nPos = Info->nMax - max(Info->nPage - 1, 0);
445 }
446
447 /*
448 * Don't change the scrollbar state if SetScrollInfo is just called
449 * with SIF_DISABLENOSCROLL
450 */
451 if (!(lpsi->fMask & SIF_ALL))
452 {
453 //goto done;
454 return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos;
455 }
456
457 /* Check if the scrollbar should be hidden or disabled */
458 if (lpsi->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL))
459 {
460 new_flags = Window->pSBInfo->WSBflags;
461 if (Info->nMin >= (int)(Info->nMax - max(Info->nPage - 1, 0)))
462 {
463 /* Hide or disable scroll-bar */
464 if (lpsi->fMask & SIF_DISABLENOSCROLL)
465 {
466 new_flags = ESB_DISABLE_BOTH;
467 bChangeParams = TRUE;
468 }
469 else if ((nBar != SB_CTL) && bChangeParams)
470 {
471 action = SA_SSI_HIDE;
472 }
473 }
474 else /* Show and enable scroll-bar only if no page only changed. */
475 if (lpsi->fMask != SIF_PAGE)
476 {
477 new_flags = ESB_ENABLE_BOTH;
478 if ((nBar != SB_CTL) && bChangeParams)
479 {
480 action |= SA_SSI_SHOW;
481 }
482 }
483
484 if (Window->pSBInfo->WSBflags != new_flags) /* Check arrow flags */
485 {
486 Window->pSBInfo->WSBflags = new_flags;
487 action |= SA_SSI_REPAINT_ARROWS;
488 }
489 }
490
491 //done:
492 if ( action & SA_SSI_HIDE )
493 {
494 co_UserShowScrollBar(Window, nBar, FALSE, FALSE);
495 }
496 else
497 {
498 if ( action & SA_SSI_SHOW )
499 if ( co_UserShowScrollBar(Window, nBar, TRUE, TRUE) )
500 return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos; /* SetWindowPos() already did the painting */
501 if (bRedraw)
502 { // FIXME: Arrows and interior.
503 RECTL UpdateRect = psbi->rcScrollBar;
504 UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
505 UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
506 UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
507 UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
508 co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
509 } // FIXME: Arrows
510 /* else if( action & SA_SSI_REPAINT_ARROWS )
511 {
512 RECTL UpdateRect = psbi->rcScrollBar;
513 UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
514 UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
515 UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
516 UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
517 co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
518 }
519 */ }
520 /* Return current position */
521 return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos;
522 }
523
524 BOOL FASTCALL
525 co_IntGetScrollBarInfo(PWND Window, LONG idObject, PSCROLLBARINFO psbi)
526 {
527 INT Bar;
528 PSCROLLBARINFO sbi;
529 PSBDATA pSBData;
530 ASSERT_REFS_CO(Window);
531
532 Bar = SBOBJ_TO_SBID(idObject);
533
534 if(!SBID_IS_VALID(Bar))
535 {
536 EngSetLastError(ERROR_INVALID_PARAMETER);
537 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
538 return FALSE;
539 }
540
541 if(!co_IntCreateScrollBars(Window))
542 {
543 ERR("Failed to create scrollbars for window.\n");
544 return FALSE;
545 }
546
547 sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
548 pSBData = IntGetSBData(Window, Bar);
549
550 IntGetScrollBarRect(Window, Bar, &(sbi->rcScrollBar));
551 IntCalculateThumb(Window, Bar, sbi, pSBData);
552
553 RtlCopyMemory(psbi, sbi, sizeof(SCROLLBARINFO));
554
555 return TRUE;
556 }
557
558 BOOL FASTCALL
559 co_IntCreateScrollBars(PWND Window)
560 {
561 PSCROLLBARINFO psbi;
562 PSBDATA pSBData;
563 ULONG Size, s;
564 INT i;
565
566 ASSERT_REFS_CO(Window);
567
568 if (Window->pSBInfo && Window->pSBInfoex)
569 {
570 /* No need to create it anymore */
571 return TRUE;
572 }
573
574 /* Allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
575 Size = 3 * (sizeof(SBINFOEX));
576 if(!(Window->pSBInfoex = ExAllocatePoolWithTag(PagedPool, Size, TAG_SBARINFO)))
577 {
578 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window->head.h);
579 return FALSE;
580 }
581
582 RtlZeroMemory(Window->pSBInfoex, Size);
583
584 if(!(Window->pSBInfo = DesktopHeapAlloc( Window->head.rpdesk, sizeof(SBINFO))))
585 {
586 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window->head.h);
587 return FALSE;
588 }
589
590 RtlZeroMemory(Window->pSBInfo, sizeof(SBINFO));
591 Window->pSBInfo->Vert.posMax = 100;
592 Window->pSBInfo->Horz.posMax = 100;
593
594 co_WinPosGetNonClientSize(Window,
595 &Window->rcWindow,
596 &Window->rcClient);
597
598 for(s = SB_HORZ; s <= SB_VERT; s++)
599 {
600 psbi = IntGetScrollbarInfoFromWindow(Window, s);
601 psbi->cbSize = sizeof(SCROLLBARINFO);
602 for (i = 0; i < CCHILDREN_SCROLLBAR + 1; i++)
603 psbi->rgstate[i] = 0;
604
605 pSBData = IntGetSBData(Window, s);
606
607 IntGetScrollBarRect(Window, s, &(psbi->rcScrollBar));
608 IntCalculateThumb(Window, s, psbi, pSBData);
609 }
610
611 return TRUE;
612 }
613
614 BOOL FASTCALL
615 IntDestroyScrollBars(PWND Window)
616 {
617 if (Window->pSBInfo && Window->pSBInfoex)
618 {
619 DesktopHeapFree(Window->head.rpdesk, Window->pSBInfo);
620 Window->pSBInfo = NULL;
621 ExFreePoolWithTag(Window->pSBInfoex, TAG_SBARINFO);
622 Window->pSBInfoex = NULL;
623 return TRUE;
624 }
625 return FALSE;
626 }
627
628 BOOL APIENTRY
629 IntEnableScrollBar(BOOL Horz, PSCROLLBARINFO Info, UINT wArrows)
630 {
631 BOOL Chg = FALSE;
632 switch(wArrows)
633 {
634 case ESB_DISABLE_BOTH:
635 CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
636 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
637 break;
638 case ESB_DISABLE_RTDN:
639 if(Horz)
640 {
641 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
642 }
643 else
644 {
645 CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
646 }
647 break;
648 case ESB_DISABLE_LTUP:
649 if(Horz)
650 {
651 CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
652 }
653 else
654 {
655 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
656 }
657 break;
658 case ESB_ENABLE_BOTH:
659 CHANGERGSTATE(SBRG_TOPRIGHTBTN, 0);
660 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, 0);
661 break;
662 }
663 return Chg;
664 }
665
666 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
667 DWORD FASTCALL
668 co_UserShowScrollBar(PWND Wnd, int nBar, BOOL fShowH, BOOL fShowV)
669 {
670 ULONG old_style, set_bits = 0, clear_bits = 0;
671
672 ASSERT_REFS_CO(Wnd);
673
674 switch(nBar)
675 {
676 case SB_CTL:
677 {
678 //IntUpdateSBInfo(Wnd, SB_CTL); // Is this needed? Was tested w/o!
679
680 co_WinPosShowWindow(Wnd, fShowH ? SW_SHOW : SW_HIDE);
681 return TRUE;
682 }
683 case SB_BOTH:
684 case SB_HORZ:
685 if (fShowH) set_bits |= WS_HSCROLL;
686 else clear_bits |= WS_HSCROLL;
687 if( nBar == SB_HORZ ) break;
688 /* Fall through */
689 case SB_VERT:
690 if (fShowV) set_bits |= WS_VSCROLL;
691 else clear_bits |= WS_VSCROLL;
692 break;
693 default:
694 EngSetLastError(ERROR_INVALID_PARAMETER);
695 return FALSE;
696 }
697
698 old_style = IntSetStyle( Wnd, set_bits, clear_bits );
699 if ((old_style & clear_bits) != 0 || (old_style & set_bits) != set_bits)
700 {
701 ///// Is this needed? Was tested w/o!
702 //if (Wnd->style & WS_HSCROLL) IntUpdateSBInfo(Wnd, SB_HORZ);
703 //if (Wnd->style & WS_VSCROLL) IntUpdateSBInfo(Wnd, SB_VERT);
704 /////
705 /* Frame has been changed, let the window redraw itself */
706 co_WinPosSetWindowPos(Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
707 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOSENDCHANGING);
708 return TRUE;
709 }
710 return FALSE;
711 }
712
713 LRESULT APIENTRY
714 ScrollBarWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
715 {
716 LRESULT lResult = 0;
717 PWND pWnd;
718 pWnd = UserGetWindowObject(hWnd);
719 if (!pWnd) return 0;
720
721 switch(Msg)
722 {
723 case WM_ENABLE:
724 {
725 if (pWnd->pSBInfo)
726 {
727 pWnd->pSBInfo->WSBflags = wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
728 }
729 }
730 break;
731 }
732 return lResult;
733 }
734
735 ////
736
737 BOOL
738 APIENTRY
739 NtUserGetScrollBarInfo(HWND hWnd, LONG idObject, PSCROLLBARINFO psbi)
740 {
741 NTSTATUS Status;
742 SCROLLBARINFO sbi;
743 PWND Window;
744 BOOL Ret;
745 DECLARE_RETURN(BOOL);
746 USER_REFERENCE_ENTRY Ref;
747
748 TRACE("Enter NtUserGetScrollBarInfo\n");
749 UserEnterExclusive();
750
751 Status = MmCopyFromCaller(&sbi, psbi, sizeof(SCROLLBARINFO));
752 if(!NT_SUCCESS(Status) || (sbi.cbSize != sizeof(SCROLLBARINFO)))
753 {
754 SetLastNtError(Status);
755 RETURN(FALSE);
756 }
757
758 if(!(Window = UserGetWindowObject(hWnd)))
759 {
760 RETURN(FALSE);
761 }
762
763 UserRefObjectCo(Window, &Ref);
764 Ret = co_IntGetScrollBarInfo(Window, idObject, &sbi);
765 UserDerefObjectCo(Window);
766
767 Status = MmCopyToCaller(psbi, &sbi, sizeof(SCROLLBARINFO));
768 if(!NT_SUCCESS(Status))
769 {
770 SetLastNtError(Status);
771 Ret = FALSE;
772 }
773
774 RETURN( Ret);
775
776 CLEANUP:
777 TRACE("Leave NtUserGetScrollBarInfo, ret=%i\n",_ret_);
778 UserLeave();
779 END_CLEANUP;
780
781 }
782
783 BOOL
784 APIENTRY
785 NtUserSBGetParms(
786 HWND hWnd,
787 int fnBar,
788 PSBDATA pSBData,
789 LPSCROLLINFO lpsi)
790 {
791 PWND Window;
792 SCROLLINFO psi;
793 BOOL Ret;
794 SBDATA SBDataSafe;
795 DECLARE_RETURN(BOOL);
796 USER_REFERENCE_ENTRY Ref;
797
798 TRACE("Enter NtUserGetScrollInfo\n");
799 UserEnterShared();
800
801 _SEH2_TRY
802 {
803 RtlCopyMemory(&psi, lpsi, sizeof(SCROLLINFO));
804 if (pSBData)
805 {
806 RtlCopyMemory(&SBDataSafe, pSBData, sizeof(SBDATA));
807 }
808 }
809 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
810 {
811 ERR("NtUserGetScrollInfo Failed size.\n");
812 SetLastNtError(_SEH2_GetExceptionCode());
813 _SEH2_YIELD(RETURN(FALSE));
814 }
815 _SEH2_END
816
817 if(!(Window = UserGetWindowObject(hWnd)))
818 {
819 ERR("NtUserGetScrollInfo Bad window.\n");
820 RETURN(FALSE);
821 }
822
823 UserRefObjectCo(Window, &Ref);
824 Ret = co_IntGetScrollInfo(Window, fnBar, &SBDataSafe, &psi);
825 UserDerefObjectCo(Window);
826
827 _SEH2_TRY
828 {
829 RtlCopyMemory(lpsi, &psi, sizeof(SCROLLINFO));
830 }
831 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
832 {
833 ERR("NtUserGetScrollInfo Failed copy to user.\n");
834 SetLastNtError(_SEH2_GetExceptionCode());
835 _SEH2_YIELD(RETURN(FALSE));
836 }
837 _SEH2_END
838
839 RETURN( Ret);
840
841 CLEANUP:
842 TRACE("Leave NtUserGetScrollInfo, ret=%i\n",_ret_);
843 UserLeave();
844 END_CLEANUP;
845 }
846
847 BOOL
848 APIENTRY
849 NtUserEnableScrollBar(
850 HWND hWnd,
851 UINT wSBflags,
852 UINT wArrows)
853 {
854 UINT OrigArrows;
855 PWND Window = NULL;
856 PSCROLLBARINFO InfoV = NULL, InfoH = NULL;
857 BOOL Chg = FALSE;
858 DECLARE_RETURN(BOOL);
859 USER_REFERENCE_ENTRY Ref;
860
861 TRACE("Enter NtUserEnableScrollBar\n");
862 UserEnterExclusive();
863
864 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
865 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
866 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
867 {
868 RETURN(FALSE);
869 }
870 UserRefObjectCo(Window, &Ref);
871
872 if (!co_IntCreateScrollBars(Window))
873 {
874 RETURN( FALSE);
875 }
876
877 OrigArrows = Window->pSBInfo->WSBflags;
878 Window->pSBInfo->WSBflags = wArrows;
879
880 if (wSBflags == SB_CTL)
881 {
882 if ((wArrows == ESB_DISABLE_BOTH || wArrows == ESB_ENABLE_BOTH))
883 IntEnableWindow(hWnd, (wArrows == ESB_ENABLE_BOTH));
884
885 RETURN(TRUE);
886 }
887
888 if(wSBflags != SB_BOTH && !SBID_IS_VALID(wSBflags))
889 {
890 EngSetLastError(ERROR_INVALID_PARAMETER);
891 ERR("Trying to set scrollinfo for unknown scrollbar type %u", wSBflags);
892 RETURN(FALSE);
893 }
894
895 switch(wSBflags)
896 {
897 case SB_BOTH:
898 InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
899 /* Fall through */
900 case SB_HORZ:
901 InfoH = IntGetScrollbarInfoFromWindow(Window, SB_HORZ);
902 break;
903 case SB_VERT:
904 InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
905 break;
906 default:
907 RETURN(FALSE);
908 }
909
910 if(InfoV)
911 Chg = IntEnableScrollBar(FALSE, InfoV, wArrows);
912
913 if(InfoH)
914 Chg = (IntEnableScrollBar(TRUE, InfoH, wArrows) || Chg);
915
916 ERR("FIXME: EnableScrollBar wSBflags %u wArrows %u Chg %d\n", wSBflags, wArrows, Chg);
917 // Done in user32:
918 // SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
919
920 RETURN( Chg);
921 if (OrigArrows == wArrows) RETURN( FALSE);
922 RETURN( TRUE);
923
924 CLEANUP:
925 if (Window)
926 UserDerefObjectCo(Window);
927
928 TRACE("Leave NtUserEnableScrollBar, ret=%i\n",_ret_);
929 UserLeave();
930 END_CLEANUP;
931 }
932
933 DWORD
934 APIENTRY
935 NtUserSetScrollInfo(
936 HWND hWnd,
937 int fnBar,
938 LPCSCROLLINFO lpsi,
939 BOOL bRedraw)
940 {
941 PWND Window = NULL;
942 NTSTATUS Status;
943 SCROLLINFO ScrollInfo;
944 DECLARE_RETURN(DWORD);
945 USER_REFERENCE_ENTRY Ref;
946
947 TRACE("Enter NtUserSetScrollInfo\n");
948 UserEnterExclusive();
949
950 if(!(Window = UserGetWindowObject(hWnd)) || // FIXME:
951 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
952 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
953 {
954 RETURN( 0);
955 }
956 UserRefObjectCo(Window, &Ref);
957
958 Status = MmCopyFromCaller(&ScrollInfo, lpsi, sizeof(SCROLLINFO) - sizeof(ScrollInfo.nTrackPos));
959 if(!NT_SUCCESS(Status))
960 {
961 SetLastNtError(Status);
962 RETURN( 0);
963 }
964
965 RETURN(co_IntSetScrollInfo(Window, fnBar, &ScrollInfo, bRedraw));
966
967 CLEANUP:
968 if (Window)
969 UserDerefObjectCo(Window);
970
971 TRACE("Leave NtUserSetScrollInfo, ret=%lu\n", _ret_);
972 UserLeave();
973 END_CLEANUP;
974
975 }
976
977 DWORD APIENTRY
978 NtUserShowScrollBar(HWND hWnd, int nBar, DWORD bShow)
979 {
980 PWND Window;
981 DECLARE_RETURN(DWORD);
982 DWORD ret;
983 USER_REFERENCE_ENTRY Ref;
984
985 TRACE("Enter NtUserShowScrollBar\n");
986 UserEnterExclusive();
987
988 if (!(Window = UserGetWindowObject(hWnd)))
989 {
990 RETURN(0);
991 }
992
993 UserRefObjectCo(Window, &Ref);
994 ret = co_UserShowScrollBar(Window, nBar, (nBar == SB_VERT) ? 0 : bShow,
995 (nBar == SB_HORZ) ? 0 : bShow);
996 UserDerefObjectCo(Window);
997
998 RETURN(ret);
999
1000 CLEANUP:
1001 TRACE("Leave NtUserShowScrollBar, ret%lu\n", _ret_);
1002 UserLeave();
1003 END_CLEANUP;
1004
1005 }
1006
1007
1008 //// Ugly NtUser API ////
1009
1010 BOOL
1011 APIENTRY
1012 NtUserSetScrollBarInfo(
1013 HWND hWnd,
1014 LONG idObject,
1015 SETSCROLLBARINFO *info)
1016 {
1017 PWND Window = NULL;
1018 SETSCROLLBARINFO Safeinfo;
1019 PSCROLLBARINFO sbi;
1020 LPSCROLLINFO psi;
1021 NTSTATUS Status;
1022 LONG Obj;
1023 DECLARE_RETURN(BOOL);
1024 USER_REFERENCE_ENTRY Ref;
1025
1026 TRACE("Enter NtUserSetScrollBarInfo\n");
1027 UserEnterExclusive();
1028
1029 if(!(Window = UserGetWindowObject(hWnd)))
1030 {
1031 RETURN( FALSE);
1032 }
1033 UserRefObjectCo(Window, &Ref);
1034
1035 Obj = SBOBJ_TO_SBID(idObject);
1036 if(!SBID_IS_VALID(Obj))
1037 {
1038 EngSetLastError(ERROR_INVALID_PARAMETER);
1039 ERR("Trying to set scrollinfo for unknown scrollbar type %d\n", Obj);
1040 RETURN( FALSE);
1041 }
1042
1043 if(!co_IntCreateScrollBars(Window))
1044 {
1045 RETURN(FALSE);
1046 }
1047
1048 Status = MmCopyFromCaller(&Safeinfo, info, sizeof(SETSCROLLBARINFO));
1049 if(!NT_SUCCESS(Status))
1050 {
1051 SetLastNtError(Status);
1052 RETURN(FALSE);
1053 }
1054
1055 sbi = IntGetScrollbarInfoFromWindow(Window, Obj);
1056 psi = IntGetScrollInfoFromWindow(Window, Obj);
1057
1058 psi->nTrackPos = Safeinfo.nTrackPos;
1059 sbi->reserved = Safeinfo.reserved;
1060 RtlCopyMemory(&sbi->rgstate, &Safeinfo.rgstate, sizeof(Safeinfo.rgstate));
1061
1062 RETURN(TRUE);
1063
1064 CLEANUP:
1065 if (Window)
1066 UserDerefObjectCo(Window);
1067
1068 TRACE("Leave NtUserSetScrollBarInfo, ret=%i\n",_ret_);
1069 UserLeave();
1070 END_CLEANUP;
1071 }
1072
1073 /* EOF */