* Sync up to trunk head (r65120).
[reactos.git] / 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 #ifdef NEW_CURSORICON
391 PCURICON_OBJECT DragCursor = NULL, OldCursor = NULL;
392 #else
393 HCURSOR hDragCursor = 0, hOldCursor = 0;
394 #endif
395 POINT minTrack, maxTrack;
396 POINT capturePoint, pt;
397 ULONG Style, ExStyle;
398 BOOL thickframe;
399 BOOL iconic;
400 BOOL moved = FALSE;
401 BOOL DragFullWindows = FALSE;
402 PWND pWndParent = NULL;
403 WPARAM syscommand = (wParam & 0xfff0);
404 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
405 //PMONITOR mon = 0; Don't port sync from wine!!! This breaks explorer task bar sizing!!
406 // The task bar can grow in size and can not reduce due to the change
407 // in the work area.
408
409 Style = pwnd->style;
410 ExStyle = pwnd->ExStyle;
411 iconic = (Style & WS_MINIMIZE) != 0;
412
413 if ((Style & WS_MAXIMIZE) || !IntIsWindowVisible(pwnd)) return;
414
415 thickframe = UserHasThickFrameStyle(Style, ExStyle) && !iconic;
416
417 //
418 // Show window contents while dragging the window, get flag from registry data.
419 //
420 UserSystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
421
422 pt.x = pti->ptLast.x;
423 pt.y = pti->ptLast.y;
424 capturePoint = pt;
425 UserClipCursor( NULL );
426
427 TRACE("pwnd %p command %04lx, hittest %d, pos %d,%d\n",
428 pwnd, syscommand, hittest, pt.x, pt.y);
429
430 if (syscommand == SC_MOVE)
431 {
432 if (!hittest) hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
433 if (!hittest) return;
434 }
435 else /* SC_SIZE */
436 {
437 if (!thickframe) return;
438 if (hittest && (syscommand != SC_MOUSEMENU))
439 {
440 hittest += (HTLEFT - WMSZ_LEFT);
441 }
442 else
443 {
444 co_UserSetCapture(UserHMGetHandle(pwnd));
445 hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
446 if (!hittest)
447 {
448 IntReleaseCapture();
449 return;
450 }
451 }
452 }
453
454 /* Get min/max info */
455
456 co_WinPosGetMinMaxInfo(pwnd, NULL, NULL, &minTrack, &maxTrack);
457 sizingRect = pwnd->rcWindow;
458 origRect = sizingRect;
459 if (Style & WS_CHILD)
460 {
461 pWndParent = IntGetParent(pwnd);
462 IntGetClientRect( pWndParent, &mouseRect );
463 IntMapWindowPoints( pWndParent, 0, (LPPOINT)&mouseRect, 2 );
464 IntMapWindowPoints( 0, pWndParent, (LPPOINT)&sizingRect, 2 );
465 unmodRect = sizingRect;
466 }
467 else
468 {
469 if (!(ExStyle & WS_EX_TOPMOST))
470 {
471 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0);
472 }
473 else
474 {
475 RECTL_vSetRect(&mouseRect, 0, 0, UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN));
476 }
477 unmodRect = sizingRect;
478 }
479
480 if (ON_LEFT_BORDER(hittest))
481 {
482 mouseRect.left = max( mouseRect.left, sizingRect.right-maxTrack.x+capturePoint.x-sizingRect.left );
483 mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x+capturePoint.x-sizingRect.left );
484 }
485 else if (ON_RIGHT_BORDER(hittest))
486 {
487 mouseRect.left = max( mouseRect.left, sizingRect.left+minTrack.x+capturePoint.x-sizingRect.right );
488 mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x+capturePoint.x-sizingRect.right );
489 }
490 if (ON_TOP_BORDER(hittest))
491 {
492 mouseRect.top = max( mouseRect.top, sizingRect.bottom-maxTrack.y+capturePoint.y-sizingRect.top );
493 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y+capturePoint.y-sizingRect.top);
494 }
495 else if (ON_BOTTOM_BORDER(hittest))
496 {
497 mouseRect.top = max( mouseRect.top, sizingRect.top+minTrack.y+capturePoint.y-sizingRect.bottom );
498 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y+capturePoint.y-sizingRect.bottom );
499 }
500
501 hdc = UserGetDCEx( pWndParent, 0, DCX_CACHE );
502 #ifdef NEW_CURSORICON
503 if (iconic)
504 {
505 DragCursor = pwnd->pcls->spicn;
506 if (DragCursor)
507 {
508 UserReferenceObject(DragCursor);
509 }
510 else
511 {
512 HCURSOR CursorHandle = (HCURSOR)co_IntSendMessage( UserHMGetHandle(pwnd), WM_QUERYDRAGICON, 0, 0 );
513 if (CursorHandle)
514 {
515 DragCursor = UserGetCurIconObject(CursorHandle);
516 }
517 else
518 {
519 iconic = FALSE;
520 }
521 }
522 }
523 #else
524 if ( iconic ) /* create a cursor for dragging */
525 {
526 hDragCursor = pwnd->pcls->hIcon;
527 if ( !hDragCursor ) hDragCursor = (HCURSOR)co_IntSendMessage( UserHMGetHandle(pwnd), WM_QUERYDRAGICON, 0, 0 );
528 if ( !hDragCursor ) iconic = FALSE;
529 }
530 #endif
531
532 /* repaint the window before moving it around */
533 co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
534
535 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZESTART, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
536
537 co_IntSendMessage( UserHMGetHandle(pwnd), WM_ENTERSIZEMOVE, 0, 0 );
538
539 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, UserHMGetHandle(pwnd));
540
541 if (IntGetCapture() != UserHMGetHandle(pwnd)) co_UserSetCapture( UserHMGetHandle(pwnd) );
542
543 pwnd->head.pti->TIF_flags |= TIF_MOVESIZETRACKING;
544
545 for(;;)
546 {
547 int dx = 0, dy = 0;
548
549 if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) break;
550 if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue;
551
552 /* Exit on button-up, Return, or Esc */
553 if ((msg.message == WM_LBUTTONUP) ||
554 ((msg.message == WM_KEYDOWN) &&
555 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
556
557 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
558 {
559 IntTranslateKbdMessage( &msg , 0 );
560 IntDispatchMessage( &msg );
561 continue; /* We are not interested in other messages */
562 }
563
564 pt = msg.pt;
565
566 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
567 {
568 case VK_UP: pt.y -= 8; break;
569 case VK_DOWN: pt.y += 8; break;
570 case VK_LEFT: pt.x -= 8; break;
571 case VK_RIGHT: pt.x += 8; break;
572 }
573
574 pt.x = max( pt.x, mouseRect.left );
575 pt.x = min( pt.x, mouseRect.right - 1 );
576 pt.y = max( pt.y, mouseRect.top );
577 pt.y = min( pt.y, mouseRect.bottom - 1 );
578
579 dx = pt.x - capturePoint.x;
580 dy = pt.y - capturePoint.y;
581
582 if (dx || dy)
583 {
584 if ( !moved )
585 {
586 moved = TRUE;
587 if ( iconic ) /* ok, no system popup tracking */
588 {
589 #ifdef NEW_CURSORICON
590 OldCursor = UserSetCursor(DragCursor, FALSE);
591 #else
592 hOldCursor = IntSetCursor(hDragCursor);
593 #endif
594 UserShowCursor( TRUE );
595 }
596 else if(!DragFullWindows)
597 UserDrawMovingFrame( hdc, &sizingRect, thickframe );
598 }
599
600 if (msg.message == WM_KEYDOWN) UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
601 else
602 {
603 RECT newRect = unmodRect;
604
605 if (!iconic && !DragFullWindows) UserDrawMovingFrame( hdc, &sizingRect, thickframe );
606 if (hittest == HTCAPTION) RECTL_vOffsetRect( &newRect, dx, dy );
607 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
608 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
609 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
610 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
611 capturePoint = pt;
612
613 //
614 // Save the new position to the unmodified rectangle. This allows explorer task bar
615 // sizing. Explorer will forces back the position unless a certain amount of sizing
616 // has occurred.
617 //
618 unmodRect = newRect;
619
620 /* determine the hit location */
621 if (syscommand == SC_SIZE)
622 {
623 WPARAM wpSizingHit = 0;
624
625 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
626 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
627 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SIZING, wpSizingHit, (LPARAM)&newRect );
628 }
629 else
630 co_IntSendMessage( UserHMGetHandle(pwnd), WM_MOVING, 0, (LPARAM)&newRect );
631
632 if (!iconic)
633 {
634 if (!DragFullWindows)
635 UserDrawMovingFrame( hdc, &newRect, thickframe );
636 else
637 { // Moving the whole window now!
638 PWND pwndTemp;
639 //// This causes the mdi child window to jump up when it is moved.
640 //IntMapWindowPoints( 0, pWndParent, (POINT *)&rect, 2 );
641 co_WinPosSetWindowPos( pwnd,
642 0,
643 newRect.left,
644 newRect.top,
645 newRect.right - newRect.left,
646 newRect.bottom - newRect.top,
647 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
648
649 // Update all the windows after the move or size, including this window.
650 for ( pwndTemp = pwnd->head.rpdesk->pDeskInfo->spwnd->spwndChild;
651 pwndTemp;
652 pwndTemp = pwndTemp->spwndNext )
653 {
654 RECTL rect;
655 // Only the windows that overlap will be redrawn.
656 if (RECTL_bIntersectRect( &rect, &pwnd->rcWindow, &pwndTemp->rcWindow ))
657 {
658 co_UserRedrawWindow( pwndTemp, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN);
659 }
660 }
661 }
662 }
663 sizingRect = newRect;
664 }
665 }
666 }
667
668 pwnd->head.pti->TIF_flags &= ~TIF_MOVESIZETRACKING;
669
670 IntReleaseCapture();
671
672 if ( iconic )
673 {
674 if ( moved ) /* restore cursors, show icon title later on */
675 {
676 UserShowCursor( FALSE );
677 #ifdef NEW_CURSORICON
678 OldCursor = UserSetCursor(OldCursor, FALSE);
679 #else
680 IntSetCursor( hOldCursor );
681 #endif
682 }
683 #ifdef NEW_CURSORICON
684 /* It could be that the cursor was already changed while we were proceeding,
685 * so we must unreference whatever cursor was current at the time we restored the old one.
686 * Maybe it is DragCursor, but maybe it is another one and DragCursor got already freed.
687 */
688 UserDereferenceObject(OldCursor);
689 #else
690 IntDestroyCursor( hDragCursor, FALSE );
691 #endif
692 }
693 else if ( moved && !DragFullWindows )
694 UserDrawMovingFrame( hdc, &sizingRect, thickframe );
695
696 UserReleaseDC(NULL, hdc, FALSE);
697
698 //// This causes the mdi child window to jump up when it is moved.
699 //if (pWndParent) IntMapWindowPoints( 0, pWndParent, (POINT *)&sizingRect, 2 );
700
701 if (co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)UserHMGetHandle(pwnd), (LPARAM)&sizingRect))
702 {
703 ERR("DoSizeMove : WH_CBT Call Hook return!\n");
704 moved = FALSE;
705 }
706
707 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZEEND, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
708
709 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
710
711 co_IntSendMessage( UserHMGetHandle(pwnd), WM_EXITSIZEMOVE, 0, 0 );
712 //// wine mdi hack
713 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SETVISIBLE, !!(pwnd->style & WS_MINIMIZE), 0L);
714 ////
715 /* window moved or resized */
716 if (moved)
717 {
718 /* if the moving/resizing isn't canceled call SetWindowPos
719 * with the new position or the new size of the window
720 */
721 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
722 {
723 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
724 if (!DragFullWindows || iconic )
725 {
726 co_WinPosSetWindowPos( pwnd,
727 0,
728 sizingRect.left,
729 sizingRect.top,
730 sizingRect.right - sizingRect.left,
731 sizingRect.bottom - sizingRect.top,
732 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
733 }
734 }
735 else
736 { /* restore previous size/position */
737 if ( DragFullWindows )
738 {
739 co_WinPosSetWindowPos( pwnd,
740 0,
741 origRect.left,
742 origRect.top,
743 origRect.right - origRect.left,
744 origRect.bottom - origRect.top,
745 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
746 }
747 }
748 }
749
750 if ( IntIsWindow(UserHMGetHandle(pwnd)) )
751 if ( iconic )
752 {
753 /* Single click brings up the system menu when iconized */
754 if ( !moved )
755 {
756 if( Style & WS_SYSMENU )
757 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
758 }
759 }
760 }
761
762 //
763 // Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
764 //
765 LRESULT FASTCALL
766 DefWndHandleSysCommand(PWND pWnd, WPARAM wParam, LPARAM lParam)
767 {
768 LRESULT lResult = 0;
769 BOOL Hook = FALSE;
770
771 if (ISITHOOKED(WH_CBT) || (pWnd->head.rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)))
772 {
773 Hook = TRUE;
774 lResult = co_HOOK_CallHooks(WH_CBT, HCBT_SYSCOMMAND, wParam, lParam);
775
776 if (lResult) return lResult;
777 }
778
779 switch (wParam & 0xfff0)
780 {
781 case SC_MOVE:
782 case SC_SIZE:
783 DefWndDoSizeMove(pWnd, wParam);
784 break;
785
786 case SC_MINIMIZE:
787 if (UserHMGetHandle(pWnd) == UserGetActiveWindow())
788 IntShowOwnedPopups(pWnd,FALSE); // This is done in ShowWindow! Need to retest!
789 co_WinPosShowWindow( pWnd, SW_MINIMIZE );
790 break;
791
792 case SC_MAXIMIZE:
793 if (((pWnd->style & WS_MINIMIZE) != 0) && UserHMGetHandle(pWnd) == UserGetActiveWindow())
794 IntShowOwnedPopups(pWnd,TRUE);
795 co_WinPosShowWindow( pWnd, SW_MAXIMIZE );
796 break;
797
798 case SC_RESTORE:
799 if (((pWnd->style & WS_MINIMIZE) != 0) && UserHMGetHandle(pWnd) == UserGetActiveWindow())
800 IntShowOwnedPopups(pWnd,TRUE);
801 co_WinPosShowWindow( pWnd, SW_RESTORE );
802 break;
803
804 case SC_CLOSE:
805 return co_IntSendMessage(UserHMGetHandle(pWnd), WM_CLOSE, 0, 0);
806
807 case SC_SCREENSAVE:
808 ERR("Screensaver Called!\n");
809 UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_START_SCREENSAVE, 0); // always lParam 0 == not Secure
810 break;
811
812 case SC_HOTKEY:
813 {
814 USER_REFERENCE_ENTRY Ref;
815
816 pWnd = ValidateHwndNoErr((HWND)lParam);
817 if (pWnd)
818 {
819 if (pWnd->spwndLastActive)
820 {
821 pWnd = pWnd->spwndLastActive;
822 }
823 UserRefObjectCo(pWnd, &Ref);
824 co_IntSetForegroundWindow(pWnd);
825 UserDerefObjectCo(pWnd);
826 if (pWnd->style & WS_MINIMIZE)
827 {
828 UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_RESTORE, 0);
829 }
830 }
831 }
832 break;
833
834
835 default:
836 // We do not support anything else here so we should return normal even when sending a hook.
837 return 0;
838 }
839
840 return(Hook ? 1 : 0); // Don't call us again from user space.
841 }
842
843 VOID FASTCALL DefWndPrint( PWND pwnd, HDC hdc, ULONG uFlags)
844 {
845 /*
846 * Visibility flag.
847 */
848 if ( (uFlags & PRF_CHECKVISIBLE) &&
849 !IntIsWindowVisible(pwnd) )
850 return;
851
852 /*
853 * Unimplemented flags.
854 */
855 if ( (uFlags & PRF_CHILDREN) ||
856 (uFlags & PRF_OWNED) ||
857 (uFlags & PRF_NONCLIENT) )
858 {
859 FIXME("WM_PRINT message with unsupported flags\n");
860 }
861
862 /*
863 * Background
864 */
865 if ( uFlags & PRF_ERASEBKGND)
866 co_IntSendMessage(UserHMGetHandle(pwnd), WM_ERASEBKGND, (WPARAM)hdc, 0);
867
868 /*
869 * Client area
870 */
871 if ( uFlags & PRF_CLIENT)
872 co_IntSendMessage(UserHMGetHandle(pwnd), WM_PRINTCLIENT, (WPARAM)hdc, uFlags);
873 }
874
875
876 /*
877 Win32k counterpart of User DefWindowProc
878 */
879 LRESULT FASTCALL
880 IntDefWindowProc(
881 PWND Wnd,
882 UINT Msg,
883 WPARAM wParam,
884 LPARAM lParam,
885 BOOL Ansi)
886 {
887 LRESULT lResult = 0;
888 USER_REFERENCE_ENTRY Ref;
889
890 if (Msg > WM_USER) return 0;
891
892 switch (Msg)
893 {
894 case WM_SYSCOMMAND:
895 {
896 ERR("hwnd %p WM_SYSCOMMAND %lx %lx\n", Wnd->head.h, wParam, lParam );
897 lResult = DefWndHandleSysCommand(Wnd, wParam, lParam);
898 break;
899 }
900 case WM_SHOWWINDOW:
901 {
902 if ((Wnd->style & WS_VISIBLE) && wParam) break;
903 if (!(Wnd->style & WS_VISIBLE) && !wParam) break;
904 if (!Wnd->spwndOwner) break;
905 if (LOWORD(lParam))
906 {
907 if (wParam)
908 {
909 if (!(Wnd->state & WNDS_HIDDENPOPUP)) break;
910 Wnd->state &= ~WNDS_HIDDENPOPUP;
911 }
912 else
913 Wnd->state |= WNDS_HIDDENPOPUP;
914
915 co_WinPosShowWindow(Wnd, wParam ? SW_SHOWNOACTIVATE : SW_HIDE);
916 }
917 }
918 break;
919 case WM_CLIENTSHUTDOWN:
920 return IntClientShutdown(Wnd, wParam, lParam);
921
922 case WM_APPCOMMAND:
923 ERR("WM_APPCOMMAND\n");
924 if ( (Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
925 Wnd != co_GetDesktopWindow(Wnd) )
926 {
927 if (!co_HOOK_CallHooks(WH_SHELL, HSHELL_APPCOMMAND, wParam, lParam))
928 co_IntShellHookNotify(HSHELL_APPCOMMAND, wParam, lParam);
929 break;
930 }
931 UserRefObjectCo(Wnd->spwndParent, &Ref);
932 lResult = co_IntSendMessage(UserHMGetHandle(Wnd->spwndParent), WM_APPCOMMAND, wParam, lParam);
933 UserDerefObjectCo(Wnd->spwndParent);
934 break;
935
936 case WM_CLOSE:
937 co_UserDestroyWindow(Wnd);
938 break;
939
940 case WM_CTLCOLORMSGBOX:
941 case WM_CTLCOLOREDIT:
942 case WM_CTLCOLORLISTBOX:
943 case WM_CTLCOLORBTN:
944 case WM_CTLCOLORDLG:
945 case WM_CTLCOLORSTATIC:
946 case WM_CTLCOLORSCROLLBAR:
947 return (LRESULT) DefWndControlColor((HDC)wParam, Msg - WM_CTLCOLORMSGBOX);
948
949 case WM_CTLCOLOR:
950 return (LRESULT) DefWndControlColor((HDC)wParam, HIWORD(lParam));
951
952 case WM_ACTIVATE:
953 /* The default action in Windows is to set the keyboard focus to
954 * the window, if it's being activated and not minimized */
955 if (LOWORD(wParam) != WA_INACTIVE &&
956 !(Wnd->style & WS_MINIMIZE))
957 {
958 //ERR("WM_ACTIVATE %p\n",hWnd);
959 co_UserSetFocus(Wnd);
960 }
961 break;
962
963 case WM_MOUSEWHEEL:
964 if (Wnd->style & WS_CHILD)
965 {
966 HWND hwndParent;
967 PWND pwndParent = IntGetParent(Wnd);
968 hwndParent = pwndParent ? UserHMGetHandle(pwndParent) : NULL;
969 return co_IntSendMessage( hwndParent, WM_MOUSEWHEEL, wParam, lParam);
970 }
971 break;
972
973 case WM_ERASEBKGND:
974 case WM_ICONERASEBKGND:
975 {
976 RECT Rect;
977 HBRUSH hBrush = Wnd->pcls->hbrBackground;
978 if (!hBrush) return 0;
979 if (hBrush <= (HBRUSH)COLOR_MENUBAR)
980 {
981 hBrush = IntGetSysColorBrush((INT)hBrush);
982 }
983 if (Wnd->pcls->style & CS_PARENTDC)
984 {
985 /* can't use GetClipBox with a parent DC or we fill the whole parent */
986 IntGetClientRect(Wnd, &Rect);
987 GreDPtoLP((HDC)wParam, (LPPOINT)&Rect, 2);
988 }
989 else
990 {
991 GdiGetClipBox((HDC)wParam, &Rect);
992 }
993 FillRect((HDC)wParam, &Rect, hBrush);
994 return (1);
995 }
996
997 case WM_GETHOTKEY:
998 //ERR("WM_GETHOTKEY\n");
999 return DefWndGetHotKey(Wnd);
1000 case WM_SETHOTKEY:
1001 //ERR("WM_SETHOTKEY\n");
1002 return DefWndSetHotKey(Wnd, wParam);
1003
1004 case WM_NCHITTEST:
1005 {
1006 POINT Point;
1007 Point.x = GET_X_LPARAM(lParam);
1008 Point.y = GET_Y_LPARAM(lParam);
1009 return GetNCHitEx(Wnd, Point);
1010 }
1011
1012 case WM_PRINT:
1013 {
1014 DefWndPrint(Wnd, (HDC)wParam, lParam);
1015 return (0);
1016 }
1017
1018 case WM_PAINTICON:
1019 case WM_PAINT:
1020 {
1021 PAINTSTRUCT Ps;
1022 HDC hDC;
1023
1024 /* If already in Paint and Client area is not empty just return. */
1025 if (Wnd->state2 & WNDS2_STARTPAINT && !RECTL_bIsEmptyRect(&Wnd->rcClient))
1026 {
1027 ERR("In Paint and Client area is not empty!\n");
1028 return 0;
1029 }
1030
1031 hDC = IntBeginPaint(Wnd, &Ps);
1032 if (hDC)
1033 {
1034 #ifdef NEW_CURSORICON
1035 if (((Wnd->style & WS_MINIMIZE) != 0) && (Wnd->pcls->spicn))
1036 {
1037 RECT ClientRect;
1038 INT x, y;
1039
1040 ERR("Doing Paint and Client area is empty!\n");
1041 IntGetClientRect(Wnd, &ClientRect);
1042 x = (ClientRect.right - ClientRect.left - UserGetSystemMetrics(SM_CXICON)) / 2;
1043 y = (ClientRect.bottom - ClientRect.top - UserGetSystemMetrics(SM_CYICON)) / 2;
1044 UserDrawIconEx(hDC, x, y, Wnd->pcls->spicn, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);
1045 }
1046 #else
1047 HICON hIcon;
1048 if (((Wnd->style & WS_MINIMIZE) != 0) && (hIcon = Wnd->pcls->hIcon))
1049 {
1050 RECT ClientRect;
1051 INT x, y;
1052 PCURICON_OBJECT pIcon;
1053 if (!(pIcon = UserGetCurIconObject(hIcon))) return 0;
1054 ERR("Doing Paint and Client area is empty!\n");
1055 IntGetClientRect(Wnd, &ClientRect);
1056 x = (ClientRect.right - ClientRect.left - UserGetSystemMetrics(SM_CXICON)) / 2;
1057 y = (ClientRect.bottom - ClientRect.top - UserGetSystemMetrics(SM_CYICON)) / 2;
1058 UserDrawIconEx( hDC, x, y, pIcon, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE );
1059 UserDereferenceObject(pIcon);
1060 }
1061 #endif
1062 IntEndPaint(Wnd, &Ps);
1063 }
1064 return (0);
1065 }
1066
1067 case WM_SYNCPAINT:
1068 {
1069 PREGION Rgn;
1070 Wnd->state &= ~WNDS_SYNCPAINTPENDING;
1071 ERR("WM_SYNCPAINT\n");
1072 Rgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1073 if (Rgn)
1074 {
1075 if (co_UserGetUpdateRgn(Wnd, Rgn, FALSE) != NULLREGION)
1076 {
1077 if (!wParam)
1078 wParam = (RDW_ERASENOW | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
1079 co_UserRedrawWindow(Wnd, NULL, Rgn, wParam);
1080 }
1081 REGION_Delete(Rgn);
1082 }
1083 return 0;
1084 }
1085
1086 case WM_SETREDRAW:
1087 ERR("WM_SETREDRAW\n");
1088 if (wParam)
1089 {
1090 if (!(Wnd->style & WS_VISIBLE))
1091 {
1092 IntSetStyle( Wnd, WS_VISIBLE, 0 );
1093 Wnd->state |= WNDS_SENDNCPAINT;
1094 }
1095 }
1096 else
1097 {
1098 if (Wnd->style & WS_VISIBLE)
1099 {
1100 co_UserRedrawWindow( Wnd, NULL, NULL, RDW_ALLCHILDREN | RDW_VALIDATE );
1101 IntSetStyle( Wnd, 0, WS_VISIBLE );
1102 }
1103 }
1104 return 0;
1105
1106 case WM_WINDOWPOSCHANGING:
1107 {
1108 return (DefWndHandleWindowPosChanging(Wnd, (WINDOWPOS*)lParam));
1109 }
1110
1111 case WM_WINDOWPOSCHANGED:
1112 {
1113 return (DefWndHandleWindowPosChanged(Wnd, (WINDOWPOS*)lParam));
1114 }
1115
1116 /* ReactOS only. */
1117 case WM_CBT:
1118 {
1119 switch (wParam)
1120 {
1121 case HCBT_MOVESIZE:
1122 {
1123 RECTL rt;
1124
1125 if (lParam)
1126 {
1127 _SEH2_TRY
1128 {
1129 ProbeForRead((PVOID)lParam,
1130 sizeof(RECT),
1131 1);
1132
1133 RtlCopyMemory(&rt,
1134 (PVOID)lParam,
1135 sizeof(RECT));
1136 }
1137 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1138 {
1139 lResult = 1;
1140 }
1141 _SEH2_END;
1142 }
1143 if (!lResult)
1144 lResult = co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)Wnd->head.h, lParam ? (LPARAM)&rt : 0);
1145 }
1146 break;
1147 }
1148 break;
1149 }
1150 break;
1151 }
1152 return lResult;
1153 }
1154
1155 PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND pWnd )
1156 {
1157 PCURICON_OBJECT pIcon = NULL;
1158 HICON hIcon;
1159 // First thing to do, init the Window Logo icons.
1160 if (!gpsi->hIconSmWindows) co_IntSetWndIcons();
1161
1162 //FIXME: Some callers use this function as if it returns a boolean saying "this window has an icon".
1163 //FIXME: Hence we must return a pointer with no reference count.
1164 //FIXME: This is bad and we should feel bad.
1165
1166 hIcon = UserGetProp(pWnd, gpsi->atomIconSmProp);
1167 if (!hIcon) hIcon = UserGetProp(pWnd, gpsi->atomIconProp);
1168 #ifdef NEW_CURSORICON
1169 if (!hIcon && pWnd->pcls->spicnSm)
1170 return pWnd->pcls->spicnSm;
1171 if (!hIcon && pWnd->pcls->spicn)
1172 return pWnd->pcls->spicn;
1173 #else
1174 if (!hIcon) hIcon = pWnd->pcls->hIconSm;
1175 if (!hIcon) hIcon = pWnd->pcls->hIcon;
1176 #endif
1177
1178 if (!hIcon && (pWnd->style & DS_MODALFRAME))
1179 {
1180 if (!hIcon) hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small
1181 if (!hIcon) hIcon = gpsi->hIconWindows; // Reg size.
1182 }
1183 if (hIcon)
1184 {
1185 pIcon = UserGetCurIconObject(hIcon);
1186 if (pIcon)
1187 {
1188 UserDereferenceObject(pIcon);
1189 }
1190 }
1191 return pIcon;
1192 }
1193
1194 DWORD FASTCALL
1195 GetNCHitEx(PWND pWnd, POINT pt)
1196 {
1197 RECT rcWindow, rcClient;
1198 DWORD Style, ExStyle;
1199
1200 if (!pWnd) return HTNOWHERE;
1201
1202 if (pWnd == UserGetDesktopWindow()) // pWnd->fnid == FNID_DESKTOP)
1203 {
1204 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0;
1205 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN);
1206 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1207 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN);
1208 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1209 }
1210 else
1211 {
1212 rcClient = pWnd->rcClient;
1213 rcWindow = pWnd->rcWindow;
1214 }
1215
1216 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE;
1217
1218 Style = pWnd->style;
1219 ExStyle = pWnd->ExStyle;
1220
1221 if (Style & WS_MINIMIZE) return HTCAPTION;
1222
1223 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT;
1224
1225 /* Check borders */
1226 if (HAS_THICKFRAME( Style, ExStyle ))
1227 {
1228 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
1229 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y ))
1230 {
1231 /* Check top sizing border */
1232 if (pt.y < rcWindow.top)
1233 {
1234 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
1235 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
1236 return HTTOP;
1237 }
1238 /* Check bottom sizing border */
1239 if (pt.y >= rcWindow.bottom)
1240 {
1241 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
1242 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
1243 return HTBOTTOM;
1244 }
1245 /* Check left sizing border */
1246 if (pt.x < rcWindow.left)
1247 {
1248 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
1249 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
1250 return HTLEFT;
1251 }
1252 /* Check right sizing border */
1253 if (pt.x >= rcWindow.right)
1254 {
1255 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
1256 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
1257 return HTRIGHT;
1258 }
1259 }
1260 }
1261 else /* No thick frame */
1262 {
1263 if (HAS_DLGFRAME( Style, ExStyle ))
1264 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
1265 else if (HAS_THINFRAME( Style, ExStyle ))
1266 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
1267 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER;
1268 }
1269
1270 /* Check caption */
1271
1272 if ((Style & WS_CAPTION) == WS_CAPTION)
1273 {
1274 if (ExStyle & WS_EX_TOOLWINDOW)
1275 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
1276 else
1277 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1;
1278 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y ))
1279 {
1280 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
1281 if (ExStyle & WS_EX_LAYOUTRTL)
1282 {
1283 /* Check system menu */
1284 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
1285 {
1286 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
1287 if (pt.x > rcWindow.right) return HTSYSMENU;
1288 }
1289
1290 /* Check close button */
1291 if (Style & WS_SYSMENU)
1292 {
1293 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION);
1294 if (pt.x < rcWindow.left) return HTCLOSE;
1295 }
1296
1297 /* Check maximize box */
1298 /* In Win95 there is automatically a Maximize button when there is a minimize one */
1299 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1300 {
1301 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
1302 if (pt.x < rcWindow.left) return HTMAXBUTTON;
1303 }
1304
1305 /* Check minimize box */
1306 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1307 {
1308 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
1309 if (pt.x < rcWindow.left) return HTMINBUTTON;
1310 }
1311 }
1312 else
1313 {
1314 /* Check system menu */
1315 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
1316 {
1317 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1;
1318 if (pt.x < rcWindow.left) return HTSYSMENU;
1319 }
1320
1321 /* Check close button */
1322 if (Style & WS_SYSMENU)
1323 {
1324 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION);
1325 if (pt.x > rcWindow.right) return HTCLOSE;
1326 }
1327
1328 /* Check maximize box */
1329 /* In Win95 there is automatically a Maximize button when there is a minimize one */
1330 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1331 {
1332 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
1333 if (pt.x > rcWindow.right) return HTMAXBUTTON;
1334 }
1335
1336 /* Check minimize box */
1337 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1338 {
1339 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
1340 if (pt.x > rcWindow.right) return HTMINBUTTON;
1341 }
1342 }
1343 return HTCAPTION;
1344 }
1345 }
1346
1347 /* Check menu bar */
1348
1349 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) &&
1350 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
1351 return HTMENU;
1352
1353 /* Check vertical scroll bar */
1354
1355 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR;
1356 if (Style & WS_VSCROLL)
1357 {
1358 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1359 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL);
1360 else
1361 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL);
1362 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL;
1363 }
1364
1365 /* Check horizontal scroll bar */
1366
1367 if (Style & WS_HSCROLL)
1368 {
1369 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL);
1370 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y ))
1371 {
1372 /* Check size box */
1373 if ((Style & WS_VSCROLL) &&
1374 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) ||
1375 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL)))))
1376 return HTSIZE;
1377 return HTHSCROLL;
1378 }
1379 }
1380
1381 /* Has to return HTNOWHERE if nothing was found
1382 Could happen when a window has a customized non client area */
1383 return HTNOWHERE;
1384 }
1385
1386 /* EOF */