[Win32k]
[reactos.git] / reactos / win32ss / user / ntuser / defwnd.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Miscellaneous User functions
5 * FILE: subsystems/win32/win32k/ntuser/defwnd.c
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10
11 #include <windowsx.h>
12
13 DBG_DEFAULT_CHANNEL(UserDefwnd);
14
15 #define UserHasDlgFrameStyle(Style, ExStyle) \
16 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
17 (((Style) & WS_DLGFRAME) && (!((Style) & WS_THICKFRAME))))
18
19 #define UserHasThickFrameStyle(Style, ExStyle) \
20 (((Style) & WS_THICKFRAME) && \
21 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
22
23 #define UserHasThinFrameStyle(Style, ExStyle) \
24 (((Style) & WS_BORDER) || (!((Style) & (WS_CHILD | WS_POPUP))))
25
26 #define ON_LEFT_BORDER(hit) \
27 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
28 #define ON_RIGHT_BORDER(hit) \
29 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
30 #define ON_TOP_BORDER(hit) \
31 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
32 #define ON_BOTTOM_BORDER(hit) \
33 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
34
35 // Client Shutdown messages
36 #define MCS_SHUTDOWNTIMERS 1
37 #define MCS_QUERYENDSESSION 2
38 // Client Shutdown returns
39 #define MCSR_GOODFORSHUTDOWN 1
40 #define MCSR_SHUTDOWNFINISHED 2
41 #define MCSR_DONOTSHUTDOWN 3
42
43 /*
44 * Based on CSRSS and described in pages 1115 - 1118 "Windows Internals, Fifth Edition".
45 * Apparently CSRSS sends out messages to do this w/o going into win32k internals.
46 */
47 static
48 LRESULT FASTCALL
49 IntClientShutdown(
50 PWND pWindow,
51 WPARAM wParam,
52 LPARAM lParam
53 )
54 {
55 LPARAM lParams;
56 BOOL KillTimers;
57 INT i;
58 LRESULT lResult = MCSR_GOODFORSHUTDOWN;
59 HWND *List;
60
61 lParams = wParam & (ENDSESSION_LOGOFF|ENDSESSION_CRITICAL|ENDSESSION_CLOSEAPP);
62 KillTimers = wParam & MCS_SHUTDOWNTIMERS ? TRUE : FALSE;
63 /*
64 First, send end sessions to children.
65 */
66 List = IntWinListChildren(pWindow);
67
68 if (List)
69 {
70 for (i = 0; List[i]; i++)
71 {
72 PWND WndChild;
73
74 if (!(WndChild = UserGetWindowObject(List[i])))
75 continue;
76
77 if (wParam & MCS_QUERYENDSESSION)
78 {
79 if (!co_IntSendMessage(WndChild->head.h, WM_QUERYENDSESSION, 0, lParams))
80 {
81 lResult = MCSR_DONOTSHUTDOWN;
82 break;
83 }
84 }
85 else
86 {
87 co_IntSendMessage(WndChild->head.h, WM_ENDSESSION, KillTimers, lParams);
88 if (KillTimers)
89 {
90 DestroyTimersForWindow(WndChild->head.pti, WndChild);
91 }
92 lResult = MCSR_SHUTDOWNFINISHED;
93 }
94 }
95 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
96 }
97 if (List && (lResult == MCSR_DONOTSHUTDOWN)) return lResult;
98 /*
99 Send to the caller.
100 */
101 if (wParam & MCS_QUERYENDSESSION)
102 {
103 if (!co_IntSendMessage(pWindow->head.h, WM_QUERYENDSESSION, 0, lParams))
104 {
105 lResult = MCSR_DONOTSHUTDOWN;
106 }
107 }
108 else
109 {
110 co_IntSendMessage(pWindow->head.h, WM_ENDSESSION, KillTimers, lParams);
111 if (KillTimers)
112 {
113 DestroyTimersForWindow(pWindow->head.pti, pWindow);
114 }
115 lResult = MCSR_SHUTDOWNFINISHED;
116 }
117 return lResult;
118 }
119
120 HBRUSH FASTCALL
121 DefWndControlColor(HDC hDC, UINT ctlType)
122 {
123 if (ctlType == CTLCOLOR_SCROLLBAR)
124 {
125 HBRUSH hb = IntGetSysColorBrush(COLOR_SCROLLBAR);
126 COLORREF bk = IntGetSysColor(COLOR_3DHILIGHT);
127 IntGdiSetTextColor(hDC, IntGetSysColor(COLOR_3DFACE));
128 IntGdiSetBkColor(hDC, bk);
129
130 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
131 * we better use 0x55aa bitmap brush to make scrollbar's background
132 * look different from the window background.
133 */
134 if ( bk == IntGetSysColor(COLOR_WINDOW))
135 return gpsi->hbrGray;
136
137 NtGdiUnrealizeObject( hb );
138 return hb;
139 }
140
141 IntGdiSetTextColor(hDC, IntGetSysColor(COLOR_WINDOWTEXT));
142
143 if ((ctlType == CTLCOLOR_EDIT) || (ctlType == CTLCOLOR_LISTBOX))
144 {
145 IntGdiSetBkColor(hDC, IntGetSysColor(COLOR_WINDOW));
146 }
147 else
148 {
149 IntGdiSetBkColor(hDC, IntGetSysColor(COLOR_3DFACE));
150 return IntGetSysColorBrush(COLOR_3DFACE);
151 }
152
153 return IntGetSysColorBrush(COLOR_WINDOW);
154 }
155
156 LRESULT FASTCALL
157 DefWndHandleWindowPosChanging(PWND pWnd, WINDOWPOS* Pos)
158 {
159 POINT maxTrack, minTrack;
160 LONG style = pWnd->style;
161
162 if (Pos->flags & SWP_NOSIZE) return 0;
163 if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
164 {
165 co_WinPosGetMinMaxInfo(pWnd, NULL, NULL, &minTrack, &maxTrack);
166 Pos->cx = min(Pos->cx, maxTrack.x);
167 Pos->cy = min(Pos->cy, maxTrack.y);
168 if (!(style & WS_MINIMIZE))
169 {
170 if (Pos->cx < minTrack.x) Pos->cx = minTrack.x;
171 if (Pos->cy < minTrack.y) Pos->cy = minTrack.y;
172 }
173 }
174 else
175 {
176 Pos->cx = max(Pos->cx, 0);
177 Pos->cy = max(Pos->cy, 0);
178 }
179 return 0;
180 }
181
182 LRESULT FASTCALL
183 DefWndHandleWindowPosChanged(PWND pWnd, WINDOWPOS* Pos)
184 {
185 RECT Rect;
186 LONG style = pWnd->style;
187
188 IntGetClientRect(pWnd, &Rect);
189 IntMapWindowPoints(pWnd, (style & WS_CHILD ? IntGetParent(pWnd) : NULL), (LPPOINT) &Rect, 2);
190
191 if (!(Pos->flags & SWP_NOCLIENTMOVE))
192 {
193 co_IntSendMessage(UserHMGetHandle(pWnd), WM_MOVE, 0, MAKELONG(Rect.left, Rect.top));
194 }
195
196 if (!(Pos->flags & SWP_NOCLIENTSIZE) || (Pos->flags & SWP_STATECHANGED))
197 {
198 if (style & WS_MINIMIZE) co_IntSendMessage(UserHMGetHandle(pWnd), WM_SIZE, SIZE_MINIMIZED, 0 );
199 else
200 {
201 WPARAM wp = (style & WS_MAXIMIZE) ? SIZE_MAXIMIZED : SIZE_RESTORED;
202 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SIZE, wp, MAKELONG(Rect.right - Rect.left, Rect.bottom - Rect.top));
203 }
204 }
205 return 0;
206 }
207
208 VOID FASTCALL
209 UserDrawWindowFrame(HDC hdc,
210 RECTL *rect,
211 ULONG width,
212 ULONG height)
213 {
214 HBRUSH hbrush = NtGdiSelectBrush( hdc, gpsi->hbrGray );
215 NtGdiPatBlt( hdc, rect->left, rect->top, rect->right - rect->left - width, height, PATINVERT );
216 NtGdiPatBlt( hdc, rect->left, rect->top + height, width, rect->bottom - rect->top - height, PATINVERT );
217 NtGdiPatBlt( hdc, rect->left + width, rect->bottom - 1, rect->right - rect->left - width, -height, PATINVERT );
218 NtGdiPatBlt( hdc, rect->right - 1, rect->top, -width, rect->bottom - rect->top - height, PATINVERT );
219 NtGdiSelectBrush( hdc, hbrush );
220 }
221
222 VOID FASTCALL
223 UserDrawMovingFrame(HDC hdc,
224 RECTL *rect,
225 BOOL thickframe)
226 {
227 if (thickframe) UserDrawWindowFrame(hdc, rect, UserGetSystemMetrics(SM_CXFRAME), UserGetSystemMetrics(SM_CYFRAME));
228 else UserDrawWindowFrame(hdc, rect, 1, 1);
229 }
230
231 /***********************************************************************
232 * NC_GetInsideRect
233 *
234 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
235 * but without the borders (if any).
236 */
237 void FASTCALL
238 NC_GetInsideRect(PWND Wnd, RECT *rect)
239 {
240 ULONG Style;
241 ULONG ExStyle;
242
243 Style = Wnd->style;
244 ExStyle = Wnd->ExStyle;
245
246 rect->top = rect->left = 0;
247 rect->right = Wnd->rcWindow.right - Wnd->rcWindow.left;
248 rect->bottom = Wnd->rcWindow.bottom - Wnd->rcWindow.top;
249
250 if (Style & WS_ICONIC) return;
251
252 /* Remove frame from rectangle */
253 if (UserHasThickFrameStyle(Style, ExStyle ))
254 {
255 RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME));
256 }
257 else
258 {
259 if (UserHasDlgFrameStyle(Style, ExStyle ))
260 {
261 RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
262 /* FIXME: this isn't in NC_AdjustRect? why not? */
263 if (ExStyle & WS_EX_DLGMODALFRAME)
264 RECTL_vInflateRect( rect, -1, 0 );
265 }
266 else
267 {
268 if (UserHasThinFrameStyle(Style, ExStyle))
269 {
270 RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
271 }
272 }
273 }
274 /* We have additional border information if the window
275 * is a child (but not an MDI child) */
276 if ((Style & WS_CHILD) && !(ExStyle & WS_EX_MDICHILD))
277 {
278 if (ExStyle & WS_EX_CLIENTEDGE)
279 RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
280 if (ExStyle & WS_EX_STATICEDGE)
281 RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
282 }
283 }
284
285 LONG FASTCALL
286 DefWndStartSizeMove(PWND Wnd, WPARAM wParam, POINT *capturePoint)
287 {
288 LONG hittest = 0;
289 POINT pt;
290 MSG msg;
291 RECT rectWindow;
292 ULONG Style = Wnd->style;
293 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
294
295 rectWindow = Wnd->rcWindow;
296
297 if ((wParam & 0xfff0) == SC_MOVE)
298 {
299 /* Move pointer at the center of the caption */
300 RECT rect = rectWindow;
301 /* Note: to be exactly centered we should take the different types
302 * of border into account, but it shouldn't make more than a few pixels
303 * of difference so let's not bother with that */
304 if (Style & WS_SYSMENU)
305 rect.left += UserGetSystemMetrics(SM_CXSIZE) + 1;
306 if (Style & WS_MINIMIZEBOX)
307 rect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
308 if (Style & WS_MAXIMIZEBOX)
309 rect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
310 pt.x = (rect.right + rect.left) / 2;
311 pt.y = rect.top + UserGetSystemMetrics(SM_CYSIZE)/2;
312 hittest = HTCAPTION;
313 *capturePoint = pt;
314 }
315 else /* SC_SIZE */
316 {
317 pt.x = pt.y = 0;
318 while (!hittest)
319 {
320 if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) return 0;
321 if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue;
322
323 switch(msg.message)
324 {
325 case WM_MOUSEMOVE:
326 //// Clamp the mouse position to the window rectangle when starting a window resize.
327 pt.x = min( max( msg.pt.x, rectWindow.left ), rectWindow.right - 1 );
328 pt.y = min( max( msg.pt.y, rectWindow.top ), rectWindow.bottom - 1 );
329 hittest = GetNCHitEx(Wnd, pt);
330 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
331 break;
332
333 case WM_LBUTTONUP:
334 return 0;
335
336 case WM_KEYDOWN:
337 switch (msg.wParam)
338 {
339 case VK_UP:
340 hittest = HTTOP;
341 pt.x = (rectWindow.left+rectWindow.right)/2;
342 pt.y = rectWindow.top + UserGetSystemMetrics(SM_CYFRAME) / 2;
343 break;
344 case VK_DOWN:
345 hittest = HTBOTTOM;
346 pt.x = (rectWindow.left+rectWindow.right)/2;
347 pt.y = rectWindow.bottom - UserGetSystemMetrics(SM_CYFRAME) / 2;
348 break;
349 case VK_LEFT:
350 hittest = HTLEFT;
351 pt.x = rectWindow.left + UserGetSystemMetrics(SM_CXFRAME) / 2;
352 pt.y = (rectWindow.top+rectWindow.bottom)/2;
353 break;
354 case VK_RIGHT:
355 hittest = HTRIGHT;
356 pt.x = rectWindow.right - UserGetSystemMetrics(SM_CXFRAME) / 2;
357 pt.y = (rectWindow.top+rectWindow.bottom)/2;
358 break;
359 case VK_RETURN:
360 case VK_ESCAPE:
361 return 0;
362 }
363 default:
364 IntTranslateKbdMessage( &msg, 0 );
365 pti->TIF_flags |= TIF_MOVESIZETRACKING;
366 IntDispatchMessage( &msg );
367 pti->TIF_flags |= TIF_MOVESIZETRACKING;
368 break;
369 }
370 }
371 *capturePoint = pt;
372 }
373 UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
374 co_IntSendMessage(UserHMGetHandle(Wnd), WM_SETCURSOR, (WPARAM)UserHMGetHandle(Wnd), MAKELONG(hittest, WM_MOUSEMOVE));
375 return hittest;
376 }
377
378 //
379 // System Command Size and Move
380 //
381 // Perform SC_MOVE and SC_SIZE commands.
382 //
383 VOID FASTCALL
384 DefWndDoSizeMove(PWND pwnd, WORD wParam)
385 {
386 MSG msg;
387 RECT sizingRect, mouseRect, origRect, unmodRect;
388 HDC hdc;
389 LONG hittest = (LONG)(wParam & 0x0f);
390 HCURSOR hDragCursor = 0, hOldCursor = 0;
391 POINT minTrack, maxTrack;
392 POINT capturePoint, pt;
393 ULONG Style, ExStyle;
394 BOOL thickframe;
395 BOOL iconic;
396 BOOL moved = FALSE;
397 BOOL DragFullWindows = FALSE;
398 PWND pWndParent = NULL;
399 WPARAM syscommand = (wParam & 0xfff0);
400 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
401 //PMONITOR mon = 0; Don't port sync from wine!!! This breaks explorer task bar sizing!!
402 // The task bar can grow in size and can not reduce due to the change
403 // in the work area.
404
405 Style = pwnd->style;
406 ExStyle = pwnd->ExStyle;
407 iconic = (Style & WS_MINIMIZE) != 0;
408
409 if ((Style & WS_MAXIMIZE) || !IntIsWindowVisible(pwnd)) return;
410
411 thickframe = UserHasThickFrameStyle(Style, ExStyle) && !iconic;
412
413 //
414 // Show window contents while dragging the window, get flag from registry data.
415 //
416 UserSystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
417
418 pt.x = pti->ptLast.x;
419 pt.y = pti->ptLast.y;
420 capturePoint = pt;
421 UserClipCursor( NULL );
422
423 TRACE("pwnd %p command %04lx, hittest %d, pos %d,%d\n",
424 pwnd, syscommand, hittest, pt.x, pt.y);
425
426 if (syscommand == SC_MOVE)
427 {
428 if (!hittest) hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
429 if (!hittest) return;
430 }
431 else /* SC_SIZE */
432 {
433 if (!thickframe) return;
434 if (hittest && (syscommand != SC_MOUSEMENU))
435 {
436 hittest += (HTLEFT - WMSZ_LEFT);
437 }
438 else
439 {
440 co_UserSetCapture(UserHMGetHandle(pwnd));
441 hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
442 if (!hittest)
443 {
444 IntReleaseCapture();
445 return;
446 }
447 }
448 }
449
450 /* Get min/max info */
451
452 co_WinPosGetMinMaxInfo(pwnd, NULL, NULL, &minTrack, &maxTrack);
453 sizingRect = pwnd->rcWindow;
454 origRect = sizingRect;
455 if (Style & WS_CHILD)
456 {
457 pWndParent = IntGetParent(pwnd);
458 IntGetClientRect( pWndParent, &mouseRect );
459 IntMapWindowPoints( pWndParent, 0, (LPPOINT)&mouseRect, 2 );
460 IntMapWindowPoints( 0, pWndParent, (LPPOINT)&sizingRect, 2 );
461 unmodRect = sizingRect;
462 }
463 else
464 {
465 if (!(ExStyle & WS_EX_TOPMOST))
466 {
467 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0);
468 }
469 else
470 {
471 RECTL_vSetRect(&mouseRect, 0, 0, UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN));
472 }
473 unmodRect = sizingRect;
474 }
475
476 if (ON_LEFT_BORDER(hittest))
477 {
478 mouseRect.left = max( mouseRect.left, sizingRect.right-maxTrack.x+capturePoint.x-sizingRect.left );
479 mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x+capturePoint.x-sizingRect.left );
480 }
481 else if (ON_RIGHT_BORDER(hittest))
482 {
483 mouseRect.left = max( mouseRect.left, sizingRect.left+minTrack.x+capturePoint.x-sizingRect.right );
484 mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x+capturePoint.x-sizingRect.right );
485 }
486 if (ON_TOP_BORDER(hittest))
487 {
488 mouseRect.top = max( mouseRect.top, sizingRect.bottom-maxTrack.y+capturePoint.y-sizingRect.top );
489 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y+capturePoint.y-sizingRect.top);
490 }
491 else if (ON_BOTTOM_BORDER(hittest))
492 {
493 mouseRect.top = max( mouseRect.top, sizingRect.top+minTrack.y+capturePoint.y-sizingRect.bottom );
494 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y+capturePoint.y-sizingRect.bottom );
495 }
496
497 hdc = UserGetDCEx( pWndParent, 0, DCX_CACHE );
498
499 if ( iconic ) /* create a cursor for dragging */
500 {
501 hDragCursor = pwnd->pcls->hIcon;;
502 if ( !hDragCursor ) hDragCursor = (HCURSOR)co_IntSendMessage( UserHMGetHandle(pwnd), WM_QUERYDRAGICON, 0, 0 );
503 if ( !hDragCursor ) iconic = FALSE;
504 }
505
506 /* repaint the window before moving it around */
507 co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
508
509 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZESTART, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
510
511 co_IntSendMessage( UserHMGetHandle(pwnd), WM_ENTERSIZEMOVE, 0, 0 );
512
513 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, UserHMGetHandle(pwnd));
514
515 if (IntGetCapture() != UserHMGetHandle(pwnd)) co_UserSetCapture( UserHMGetHandle(pwnd) );
516
517 pwnd->head.pti->TIF_flags |= TIF_MOVESIZETRACKING;
518
519 for(;;)
520 {
521 int dx = 0, dy = 0;
522
523 if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) break;
524 if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue;
525
526 /* Exit on button-up, Return, or Esc */
527 if ((msg.message == WM_LBUTTONUP) ||
528 ((msg.message == WM_KEYDOWN) &&
529 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
530
531 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
532 {
533 IntTranslateKbdMessage( &msg , 0 );
534 IntDispatchMessage( &msg );
535 continue; /* We are not interested in other messages */
536 }
537
538 pt = msg.pt;
539
540 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
541 {
542 case VK_UP: pt.y -= 8; break;
543 case VK_DOWN: pt.y += 8; break;
544 case VK_LEFT: pt.x -= 8; break;
545 case VK_RIGHT: pt.x += 8; break;
546 }
547
548 pt.x = max( pt.x, mouseRect.left );
549 pt.x = min( pt.x, mouseRect.right - 1 );
550 pt.y = max( pt.y, mouseRect.top );
551 pt.y = min( pt.y, mouseRect.bottom - 1 );
552
553 dx = pt.x - capturePoint.x;
554 dy = pt.y - capturePoint.y;
555
556 if (dx || dy)
557 {
558 if ( !moved )
559 {
560 moved = TRUE;
561
562 if ( iconic ) /* ok, no system popup tracking */
563 {
564 hOldCursor = IntSetCursor(hDragCursor);
565 UserShowCursor( TRUE );
566 }
567 else if(!DragFullWindows)
568 UserDrawMovingFrame( hdc, &sizingRect, thickframe );
569 }
570
571 if (msg.message == WM_KEYDOWN) UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
572 else
573 {
574 RECT newRect = unmodRect;
575
576 if (!iconic && !DragFullWindows) UserDrawMovingFrame( hdc, &sizingRect, thickframe );
577 if (hittest == HTCAPTION) RECTL_vOffsetRect( &newRect, dx, dy );
578 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
579 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
580 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
581 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
582 capturePoint = pt;
583
584 //
585 // Save the new position to the unmodified rectangle. This allows explorer task bar
586 // sizing. Explorer will forces back the position unless a certain amount of sizing
587 // has occurred.
588 //
589 unmodRect = newRect;
590
591 /* determine the hit location */
592 if (syscommand == SC_SIZE)
593 {
594 WPARAM wpSizingHit = 0;
595
596 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
597 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
598 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SIZING, wpSizingHit, (LPARAM)&newRect );
599 }
600 else
601 co_IntSendMessage( UserHMGetHandle(pwnd), WM_MOVING, 0, (LPARAM)&newRect );
602
603 if (!iconic)
604 {
605 if (!DragFullWindows)
606 UserDrawMovingFrame( hdc, &newRect, thickframe );
607 else
608 { // Moving the whole window now!
609 PWND pwndTemp;
610 //// This causes the mdi child window to jump up when it is moved.
611 //IntMapWindowPoints( 0, pWndParent, (POINT *)&rect, 2 );
612 co_WinPosSetWindowPos( pwnd,
613 0,
614 newRect.left,
615 newRect.top,
616 newRect.right - newRect.left,
617 newRect.bottom - newRect.top,
618 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
619
620 // Update all the windows after the move or size, including this window.
621 for ( pwndTemp = pwnd->head.rpdesk->pDeskInfo->spwnd->spwndChild;
622 pwndTemp;
623 pwndTemp = pwndTemp->spwndNext )
624 {
625 RECTL rect;
626 // Only the windows that overlap will be redrawn.
627 if (RECTL_bIntersectRect( &rect, &pwnd->rcWindow, &pwndTemp->rcWindow ))
628 {
629 co_UserRedrawWindow( pwndTemp, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN);
630 }
631 }
632 }
633 }
634 sizingRect = newRect;
635 }
636 }
637 }
638
639 pwnd->head.pti->TIF_flags &= ~TIF_MOVESIZETRACKING;
640
641 IntReleaseCapture();
642
643 if ( iconic )
644 {
645 if ( moved ) /* restore cursors, show icon title later on */
646 {
647 UserShowCursor( FALSE );
648 IntSetCursor( hOldCursor );
649 }
650 IntDestroyCursor( hDragCursor, FALSE );
651 }
652 else if ( moved && !DragFullWindows )
653 UserDrawMovingFrame( hdc, &sizingRect, thickframe );
654
655 UserReleaseDC(NULL, hdc, FALSE);
656
657 //// This causes the mdi child window to jump up when it is moved.
658 //if (pWndParent) IntMapWindowPoints( 0, pWndParent, (POINT *)&sizingRect, 2 );
659
660 if (co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)UserHMGetHandle(pwnd), (LPARAM)&sizingRect))
661 {
662 ERR("DoSizeMove : WH_CBT Call Hook return!\n");
663 moved = FALSE;
664 }
665
666 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZEEND, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
667
668 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
669
670 co_IntSendMessage( UserHMGetHandle(pwnd), WM_EXITSIZEMOVE, 0, 0 );
671 //// wine mdi hack
672 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SETVISIBLE, !!(pwnd->style & WS_MINIMIZE), 0L);
673 ////
674 /* window moved or resized */
675 if (moved)
676 {
677 /* if the moving/resizing isn't canceled call SetWindowPos
678 * with the new position or the new size of the window
679 */
680 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
681 {
682 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
683 if (!DragFullWindows || iconic )
684 {
685 co_WinPosSetWindowPos( pwnd,
686 0,
687 sizingRect.left,
688 sizingRect.top,
689 sizingRect.right - sizingRect.left,
690 sizingRect.bottom - sizingRect.top,
691 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
692 }
693 }
694 else
695 { /* restore previous size/position */
696 if ( DragFullWindows )
697 {
698 co_WinPosSetWindowPos( pwnd,
699 0,
700 origRect.left,
701 origRect.top,
702 origRect.right - origRect.left,
703 origRect.bottom - origRect.top,
704 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
705 }
706 }
707 }
708
709 if ( IntIsWindow(UserHMGetHandle(pwnd)) )
710 if ( iconic )
711 {
712 /* Single click brings up the system menu when iconized */
713 if ( !moved )
714 {
715 if( Style & WS_SYSMENU )
716 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
717 }
718 }
719 }
720
721 //
722 // Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
723 //
724 LRESULT FASTCALL
725 DefWndHandleSysCommand(PWND pWnd, WPARAM wParam, LPARAM lParam)
726 {
727 LRESULT lResult = 0;
728 BOOL Hook = FALSE;
729
730 if (ISITHOOKED(WH_CBT) || (pWnd->head.rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)))
731 {
732 Hook = TRUE;
733 lResult = co_HOOK_CallHooks(WH_CBT, HCBT_SYSCOMMAND, wParam, lParam);
734
735 if (lResult) return lResult;
736 }
737
738 switch (wParam & 0xfff0)
739 {
740 case SC_MOVE:
741 case SC_SIZE:
742 DefWndDoSizeMove(pWnd, wParam);
743 break;
744
745 case SC_MINIMIZE:
746 if (UserHMGetHandle(pWnd) == UserGetActiveWindow())
747 IntShowOwnedPopups(pWnd,FALSE); // This is done in ShowWindow! Need to retest!
748 co_WinPosShowWindow( pWnd, SW_MINIMIZE );
749 break;
750
751 case SC_MAXIMIZE:
752 if (((pWnd->style & WS_MINIMIZE) != 0) && UserHMGetHandle(pWnd) == UserGetActiveWindow())
753 IntShowOwnedPopups(pWnd,TRUE);
754 co_WinPosShowWindow( pWnd, SW_MAXIMIZE );
755 break;
756
757 case SC_RESTORE:
758 if (((pWnd->style & WS_MINIMIZE) != 0) && UserHMGetHandle(pWnd) == UserGetActiveWindow())
759 IntShowOwnedPopups(pWnd,TRUE);
760 co_WinPosShowWindow( pWnd, SW_RESTORE );
761 break;
762
763 case SC_CLOSE:
764 return co_IntSendMessage(UserHMGetHandle(pWnd), WM_CLOSE, 0, 0);
765
766 case SC_SCREENSAVE:
767 ERR("Screensaver Called!\n");
768 UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_START_SCREENSAVE, 0); // always lParam 0 == not Secure
769 break;
770
771 case SC_HOTKEY:
772 {
773 USER_REFERENCE_ENTRY Ref;
774
775 pWnd = ValidateHwndNoErr((HWND)lParam);
776 if (pWnd)
777 {
778 if (pWnd->spwndLastActive)
779 {
780 pWnd = pWnd->spwndLastActive;
781 }
782 UserRefObjectCo(pWnd, &Ref);
783 co_IntSetForegroundWindow(pWnd);
784 UserDerefObjectCo(pWnd);
785 if (pWnd->style & WS_MINIMIZE)
786 {
787 UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_RESTORE, 0);
788 }
789 }
790 }
791 break;
792
793
794 default:
795 // We do not support anything else here so we should return normal even when sending a hook.
796 return 0;
797 }
798
799 return(Hook ? 1 : 0); // Don't call us again from user space.
800 }
801
802 VOID FASTCALL DefWndPrint( PWND pwnd, HDC hdc, ULONG uFlags)
803 {
804 /*
805 * Visibility flag.
806 */
807 if ( (uFlags & PRF_CHECKVISIBLE) &&
808 !IntIsWindowVisible(pwnd) )
809 return;
810
811 /*
812 * Unimplemented flags.
813 */
814 if ( (uFlags & PRF_CHILDREN) ||
815 (uFlags & PRF_OWNED) ||
816 (uFlags & PRF_NONCLIENT) )
817 {
818 FIXME("WM_PRINT message with unsupported flags\n");
819 }
820
821 /*
822 * Background
823 */
824 if ( uFlags & PRF_ERASEBKGND)
825 co_IntSendMessage(UserHMGetHandle(pwnd), WM_ERASEBKGND, (WPARAM)hdc, 0);
826
827 /*
828 * Client area
829 */
830 if ( uFlags & PRF_CLIENT)
831 co_IntSendMessage(UserHMGetHandle(pwnd), WM_PRINTCLIENT, (WPARAM)hdc, uFlags);
832 }
833
834
835 /*
836 Win32k counterpart of User DefWindowProc
837 */
838 LRESULT FASTCALL
839 IntDefWindowProc(
840 PWND Wnd,
841 UINT Msg,
842 WPARAM wParam,
843 LPARAM lParam,
844 BOOL Ansi)
845 {
846 LRESULT lResult = 0;
847 USER_REFERENCE_ENTRY Ref;
848
849 if (Msg > WM_USER) return 0;
850
851 switch (Msg)
852 {
853 case WM_SYSCOMMAND:
854 {
855 ERR("hwnd %p WM_SYSCOMMAND %lx %lx\n", Wnd->head.h, wParam, lParam );
856 lResult = DefWndHandleSysCommand(Wnd, wParam, lParam);
857 break;
858 }
859 case WM_SHOWWINDOW:
860 {
861 if ((Wnd->style & WS_VISIBLE) && wParam) break;
862 if (!(Wnd->style & WS_VISIBLE) && !wParam) break;
863 if (!Wnd->spwndOwner) break;
864 if (LOWORD(lParam))
865 {
866 if (wParam)
867 {
868 if (!(Wnd->state & WNDS_HIDDENPOPUP)) break;
869 Wnd->state &= ~WNDS_HIDDENPOPUP;
870 }
871 else
872 Wnd->state |= WNDS_HIDDENPOPUP;
873
874 co_WinPosShowWindow(Wnd, wParam ? SW_SHOWNOACTIVATE : SW_HIDE);
875 }
876 }
877 break;
878 case WM_CLIENTSHUTDOWN:
879 return IntClientShutdown(Wnd, wParam, lParam);
880
881 case WM_APPCOMMAND:
882 ERR("WM_APPCOMMAND\n");
883 if ( (Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
884 Wnd != co_GetDesktopWindow(Wnd) )
885 {
886 if (!co_HOOK_CallHooks(WH_SHELL, HSHELL_APPCOMMAND, wParam, lParam))
887 co_IntShellHookNotify(HSHELL_APPCOMMAND, wParam, lParam);
888 break;
889 }
890 UserRefObjectCo(Wnd->spwndParent, &Ref);
891 lResult = co_IntSendMessage(UserHMGetHandle(Wnd->spwndParent), WM_APPCOMMAND, wParam, lParam);
892 UserDerefObjectCo(Wnd->spwndParent);
893 break;
894
895 case WM_CLOSE:
896 co_UserDestroyWindow(Wnd);
897 break;
898
899 case WM_CTLCOLORMSGBOX:
900 case WM_CTLCOLOREDIT:
901 case WM_CTLCOLORLISTBOX:
902 case WM_CTLCOLORBTN:
903 case WM_CTLCOLORDLG:
904 case WM_CTLCOLORSTATIC:
905 case WM_CTLCOLORSCROLLBAR:
906 return (LRESULT) DefWndControlColor((HDC)wParam, Msg - WM_CTLCOLORMSGBOX);
907
908 case WM_CTLCOLOR:
909 return (LRESULT) DefWndControlColor((HDC)wParam, HIWORD(lParam));
910
911 case WM_ACTIVATE:
912 /* The default action in Windows is to set the keyboard focus to
913 * the window, if it's being activated and not minimized */
914 if (LOWORD(wParam) != WA_INACTIVE &&
915 !(Wnd->style & WS_MINIMIZE))
916 {
917 //ERR("WM_ACTIVATE %p\n",hWnd);
918 co_UserSetFocus(Wnd);
919 }
920 break;
921
922 case WM_MOUSEWHEEL:
923 if (Wnd->style & WS_CHILD)
924 {
925 HWND hwndParent;
926 PWND pwndParent = IntGetParent(Wnd);
927 hwndParent = pwndParent ? UserHMGetHandle(pwndParent) : NULL;
928 return co_IntSendMessage( hwndParent, WM_MOUSEWHEEL, wParam, lParam);
929 }
930 break;
931
932 case WM_ERASEBKGND:
933 case WM_ICONERASEBKGND:
934 {
935 RECT Rect;
936 HBRUSH hBrush = Wnd->pcls->hbrBackground;
937 if (!hBrush) return 0;
938 if (hBrush <= (HBRUSH)COLOR_MENUBAR)
939 {
940 hBrush = IntGetSysColorBrush((INT)hBrush);
941 }
942 if (Wnd->pcls->style & CS_PARENTDC)
943 {
944 /* can't use GetClipBox with a parent DC or we fill the whole parent */
945 IntGetClientRect(Wnd, &Rect);
946 GreDPtoLP((HDC)wParam, (LPPOINT)&Rect, 2);
947 }
948 else
949 {
950 GdiGetClipBox((HDC)wParam, &Rect);
951 }
952 FillRect((HDC)wParam, &Rect, hBrush);
953 return (1);
954 }
955
956 case WM_GETHOTKEY:
957 //ERR("WM_GETHOTKEY\n");
958 return DefWndGetHotKey(Wnd);
959 case WM_SETHOTKEY:
960 //ERR("WM_SETHOTKEY\n");
961 return DefWndSetHotKey(Wnd, wParam);
962
963 case WM_NCHITTEST:
964 {
965 POINT Point;
966 Point.x = GET_X_LPARAM(lParam);
967 Point.y = GET_Y_LPARAM(lParam);
968 return GetNCHitEx(Wnd, Point);
969 }
970
971 case WM_PRINT:
972 {
973 DefWndPrint(Wnd, (HDC)wParam, lParam);
974 return (0);
975 }
976
977 case WM_PAINTICON:
978 case WM_PAINT:
979 {
980 PAINTSTRUCT Ps;
981 HDC hDC;
982
983 /* If already in Paint and Client area is not empty just return. */
984 if (Wnd->state2 & WNDS2_STARTPAINT && !RECTL_bIsEmptyRect(&Wnd->rcClient))
985 {
986 ERR("In Paint and Client area is not empty!\n");
987 return 0;
988 }
989
990 hDC = IntBeginPaint(Wnd, &Ps);
991 if (hDC)
992 {
993 HICON hIcon;
994 if (((Wnd->style & WS_MINIMIZE) != 0) && (hIcon = Wnd->pcls->hIcon))
995 {
996 RECT ClientRect;
997 INT x, y;
998 PCURICON_OBJECT pIcon;
999 if (!(pIcon = UserGetCurIconObject(hIcon))) return 0;
1000 ERR("Doing Paint and Client area is empty!\n");
1001 IntGetClientRect(Wnd, &ClientRect);
1002 x = (ClientRect.right - ClientRect.left - UserGetSystemMetrics(SM_CXICON)) / 2;
1003 y = (ClientRect.bottom - ClientRect.top - UserGetSystemMetrics(SM_CYICON)) / 2;
1004 UserDrawIconEx( hDC, x, y, pIcon, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE );
1005 }
1006 IntEndPaint(Wnd, &Ps);
1007 }
1008 return (0);
1009 }
1010
1011 case WM_SYNCPAINT:
1012 {
1013 HRGN hRgn;
1014 Wnd->state &= ~WNDS_SYNCPAINTPENDING;
1015 ERR("WM_SYNCPAINT\n");
1016 hRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1017 if (co_UserGetUpdateRgn(Wnd, hRgn, FALSE) != NULLREGION)
1018 {
1019 if (!wParam) wParam = (RDW_ERASENOW | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
1020 co_UserRedrawWindow(Wnd, NULL, hRgn, wParam);
1021 }
1022 GreDeleteObject(hRgn);
1023 return 0;
1024 }
1025
1026 case WM_SETREDRAW:
1027 ERR("WM_SETREDRAW\n");
1028 if (wParam)
1029 {
1030 if (!(Wnd->style & WS_VISIBLE))
1031 {
1032 IntSetStyle( Wnd, WS_VISIBLE, 0 );
1033 Wnd->state |= WNDS_SENDNCPAINT;
1034 }
1035 }
1036 else
1037 {
1038 if (Wnd->style & WS_VISIBLE)
1039 {
1040 co_UserRedrawWindow( Wnd, NULL, NULL, RDW_ALLCHILDREN | RDW_VALIDATE );
1041 IntSetStyle( Wnd, 0, WS_VISIBLE );
1042 }
1043 }
1044 return 0;
1045
1046 case WM_WINDOWPOSCHANGING:
1047 {
1048 return (DefWndHandleWindowPosChanging(Wnd, (WINDOWPOS*)lParam));
1049 }
1050
1051 case WM_WINDOWPOSCHANGED:
1052 {
1053 return (DefWndHandleWindowPosChanged(Wnd, (WINDOWPOS*)lParam));
1054 }
1055
1056 /* ReactOS only. */
1057 case WM_CBT:
1058 {
1059 switch (wParam)
1060 {
1061 case HCBT_MOVESIZE:
1062 {
1063 RECTL rt;
1064
1065 if (lParam)
1066 {
1067 _SEH2_TRY
1068 {
1069 ProbeForRead((PVOID)lParam,
1070 sizeof(RECT),
1071 1);
1072
1073 RtlCopyMemory(&rt,
1074 (PVOID)lParam,
1075 sizeof(RECT));
1076 }
1077 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1078 {
1079 lResult = 1;
1080 }
1081 _SEH2_END;
1082 }
1083 if (!lResult)
1084 lResult = co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)Wnd->head.h, lParam ? (LPARAM)&rt : 0);
1085 }
1086 break;
1087 }
1088 break;
1089 }
1090 break;
1091 }
1092 return lResult;
1093 }
1094
1095 HICON FASTCALL NC_IconForWindow( PWND pWnd )
1096 {
1097 HICON hIcon = 0;
1098 // First thing to do, init the Window Logo icons.
1099 if (!gpsi->hIconSmWindows) co_IntSetWndIcons();
1100
1101 if (!hIcon) hIcon = UserGetProp(pWnd, gpsi->atomIconSmProp);
1102 if (!hIcon) hIcon = UserGetProp(pWnd, gpsi->atomIconProp);
1103 if (!hIcon) hIcon = pWnd->pcls->hIconSm;
1104 if (!hIcon) hIcon = pWnd->pcls->hIcon;
1105
1106 if (!hIcon && pWnd->style & DS_MODALFRAME)
1107 {
1108 if (!hIcon) hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small
1109 if (!hIcon) hIcon = gpsi->hIconWindows; // Reg size.
1110 }
1111 return hIcon;
1112 }
1113
1114 DWORD FASTCALL
1115 GetNCHitEx(PWND pWnd, POINT pt)
1116 {
1117 RECT rcWindow, rcClient;
1118 DWORD Style, ExStyle;
1119
1120 if (!pWnd) return HTNOWHERE;
1121
1122 if (pWnd == UserGetDesktopWindow()) // pWnd->fnid == FNID_DESKTOP)
1123 {
1124 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0;
1125 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN);
1126 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1127 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN);
1128 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1129 }
1130 else
1131 {
1132 rcClient = pWnd->rcClient;
1133 rcWindow = pWnd->rcWindow;
1134 }
1135
1136 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE;
1137
1138 Style = pWnd->style;
1139 ExStyle = pWnd->ExStyle;
1140
1141 if (Style & WS_MINIMIZE) return HTCAPTION;
1142
1143 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT;
1144
1145 /* Check borders */
1146 if (HAS_THICKFRAME( Style, ExStyle ))
1147 {
1148 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
1149 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y ))
1150 {
1151 /* Check top sizing border */
1152 if (pt.y < rcWindow.top)
1153 {
1154 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
1155 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
1156 return HTTOP;
1157 }
1158 /* Check bottom sizing border */
1159 if (pt.y >= rcWindow.bottom)
1160 {
1161 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
1162 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
1163 return HTBOTTOM;
1164 }
1165 /* Check left sizing border */
1166 if (pt.x < rcWindow.left)
1167 {
1168 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
1169 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
1170 return HTLEFT;
1171 }
1172 /* Check right sizing border */
1173 if (pt.x >= rcWindow.right)
1174 {
1175 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
1176 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
1177 return HTRIGHT;
1178 }
1179 }
1180 }
1181 else /* No thick frame */
1182 {
1183 if (HAS_DLGFRAME( Style, ExStyle ))
1184 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
1185 else if (HAS_THINFRAME( Style, ExStyle ))
1186 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
1187 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER;
1188 }
1189
1190 /* Check caption */
1191
1192 if ((Style & WS_CAPTION) == WS_CAPTION)
1193 {
1194 if (ExStyle & WS_EX_TOOLWINDOW)
1195 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
1196 else
1197 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1;
1198 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y ))
1199 {
1200 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
1201 if (ExStyle & WS_EX_LAYOUTRTL)
1202 {
1203 /* Check system menu */
1204 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
1205 {
1206 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
1207 if (pt.x > rcWindow.right) return HTSYSMENU;
1208 }
1209
1210 /* Check close button */
1211 if (Style & WS_SYSMENU)
1212 {
1213 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION);
1214 if (pt.x < rcWindow.left) return HTCLOSE;
1215 }
1216
1217 /* Check maximize box */
1218 /* In Win95 there is automatically a Maximize button when there is a minimize one */
1219 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1220 {
1221 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
1222 if (pt.x < rcWindow.left) return HTMAXBUTTON;
1223 }
1224
1225 /* Check minimize box */
1226 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1227 {
1228 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
1229 if (pt.x < rcWindow.left) return HTMINBUTTON;
1230 }
1231 }
1232 else
1233 {
1234 /* Check system menu */
1235 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
1236 {
1237 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1;
1238 if (pt.x < rcWindow.left) return HTSYSMENU;
1239 }
1240
1241 /* Check close button */
1242 if (Style & WS_SYSMENU)
1243 {
1244 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION);
1245 if (pt.x > rcWindow.right) return HTCLOSE;
1246 }
1247
1248 /* Check maximize box */
1249 /* In Win95 there is automatically a Maximize button when there is a minimize one */
1250 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1251 {
1252 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
1253 if (pt.x > rcWindow.right) return HTMAXBUTTON;
1254 }
1255
1256 /* Check minimize box */
1257 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1258 {
1259 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
1260 if (pt.x > rcWindow.right) return HTMINBUTTON;
1261 }
1262 }
1263 return HTCAPTION;
1264 }
1265 }
1266
1267 /* Check menu bar */
1268
1269 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) &&
1270 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
1271 return HTMENU;
1272
1273 /* Check vertical scroll bar */
1274
1275 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR;
1276 if (Style & WS_VSCROLL)
1277 {
1278 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1279 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL);
1280 else
1281 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL);
1282 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL;
1283 }
1284
1285 /* Check horizontal scroll bar */
1286
1287 if (Style & WS_HSCROLL)
1288 {
1289 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL);
1290 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y ))
1291 {
1292 /* Check size box */
1293 if ((Style & WS_VSCROLL) &&
1294 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) ||
1295 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL)))))
1296 return HTSIZE;
1297 return HTHSCROLL;
1298 }
1299 }
1300
1301 /* Has to return HTNOWHERE if nothing was found
1302 Could happen when a window has a customized non client area */
1303 return HTNOWHERE;
1304 }
1305
1306 /* EOF */