[Win32SS]
[reactos.git] / reactos / win32ss / user / ntuser / nonclient.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Miscellaneous User functions
5 * FILE: win32ss/user/ntuser/nonclient.c
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10 #include <windowsx.h>
11
12 DBG_DEFAULT_CHANNEL(UserDefwnd);
13
14 #define UserHasDlgFrameStyle(Style, ExStyle) \
15 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
16 (((Style) & WS_DLGFRAME) && (!((Style) & WS_THICKFRAME))))
17
18 #define UserHasThickFrameStyle(Style, ExStyle) \
19 (((Style) & WS_THICKFRAME) && \
20 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
21
22 #define UserHasThinFrameStyle(Style, ExStyle) \
23 (((Style) & WS_BORDER) || (!((Style) & (WS_CHILD | WS_POPUP))))
24
25 #define ON_LEFT_BORDER(hit) \
26 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
27 #define ON_RIGHT_BORDER(hit) \
28 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
29 #define ON_TOP_BORDER(hit) \
30 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
31 #define ON_BOTTOM_BORDER(hit) \
32 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
33
34
35 VOID FASTCALL
36 UserDrawWindowFrame(HDC hdc,
37 RECTL *rect,
38 ULONG width,
39 ULONG height)
40 {
41 HBRUSH hbrush = NtGdiSelectBrush( hdc, gpsi->hbrGray );
42 NtGdiPatBlt( hdc, rect->left, rect->top, rect->right - rect->left - width, height, PATINVERT );
43 NtGdiPatBlt( hdc, rect->left, rect->top + height, width, rect->bottom - rect->top - height, PATINVERT );
44 NtGdiPatBlt( hdc, rect->left + width, rect->bottom - 1, rect->right - rect->left - width, -(LONG)height, PATINVERT );
45 NtGdiPatBlt( hdc, rect->right - 1, rect->top, -(LONG)width, rect->bottom - rect->top - height, PATINVERT );
46 NtGdiSelectBrush( hdc, hbrush );
47 }
48
49 VOID FASTCALL
50 UserDrawMovingFrame(HDC hdc,
51 RECTL *rect,
52 BOOL thickframe)
53 {
54 if (thickframe) UserDrawWindowFrame(hdc, rect, UserGetSystemMetrics(SM_CXFRAME), UserGetSystemMetrics(SM_CYFRAME));
55 else UserDrawWindowFrame(hdc, rect, 1, 1);
56 }
57
58 /***********************************************************************
59 * NC_GetInsideRect
60 *
61 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
62 * but without the borders (if any).
63 */
64 void FASTCALL
65 NC_GetInsideRect(PWND Wnd, RECT *rect)
66 {
67 ULONG Style;
68 ULONG ExStyle;
69
70 Style = Wnd->style;
71 ExStyle = Wnd->ExStyle;
72
73 rect->top = rect->left = 0;
74 rect->right = Wnd->rcWindow.right - Wnd->rcWindow.left;
75 rect->bottom = Wnd->rcWindow.bottom - Wnd->rcWindow.top;
76
77 if (Style & WS_ICONIC) return;
78
79 /* Remove frame from rectangle */
80 if (UserHasThickFrameStyle(Style, ExStyle ))
81 {
82 RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME));
83 }
84 else
85 {
86 if (UserHasDlgFrameStyle(Style, ExStyle ))
87 {
88 RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
89 /* FIXME: this isn't in NC_AdjustRect? why not? */
90 if (ExStyle & WS_EX_DLGMODALFRAME)
91 RECTL_vInflateRect( rect, -1, 0 );
92 }
93 else
94 {
95 if (UserHasThinFrameStyle(Style, ExStyle))
96 {
97 RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
98 }
99 }
100 }
101 /* We have additional border information if the window
102 * is a child (but not an MDI child) */
103 if ((Style & WS_CHILD) && !(ExStyle & WS_EX_MDICHILD))
104 {
105 if (ExStyle & WS_EX_CLIENTEDGE)
106 RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
107 if (ExStyle & WS_EX_STATICEDGE)
108 RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
109 }
110 }
111
112 LONG FASTCALL
113 DefWndStartSizeMove(PWND Wnd, WPARAM wParam, POINT *capturePoint)
114 {
115 LONG hittest = 0;
116 POINT pt;
117 MSG msg;
118 RECT rectWindow;
119 ULONG Style = Wnd->style;
120 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
121
122 rectWindow = Wnd->rcWindow;
123
124 if ((wParam & 0xfff0) == SC_MOVE)
125 {
126 /* Move pointer at the center of the caption */
127 RECT rect = rectWindow;
128 /* Note: to be exactly centered we should take the different types
129 * of border into account, but it shouldn't make more than a few pixels
130 * of difference so let's not bother with that */
131 if (Style & WS_SYSMENU)
132 rect.left += UserGetSystemMetrics(SM_CXSIZE) + 1;
133 if (Style & WS_MINIMIZEBOX)
134 rect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
135 if (Style & WS_MAXIMIZEBOX)
136 rect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
137 pt.x = (rect.right + rect.left) / 2;
138 pt.y = rect.top + UserGetSystemMetrics(SM_CYSIZE)/2;
139 hittest = HTCAPTION;
140 *capturePoint = pt;
141 }
142 else /* SC_SIZE */
143 {
144 pt.x = pt.y = 0;
145 while (!hittest)
146 {
147 if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) return 0;
148 if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue;
149
150 switch(msg.message)
151 {
152 case WM_MOUSEMOVE:
153 //// Clamp the mouse position to the window rectangle when starting a window resize.
154 pt.x = min( max( msg.pt.x, rectWindow.left ), rectWindow.right - 1 );
155 pt.y = min( max( msg.pt.y, rectWindow.top ), rectWindow.bottom - 1 );
156 hittest = GetNCHitEx(Wnd, pt);
157 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
158 break;
159
160 case WM_LBUTTONUP:
161 return 0;
162
163 case WM_KEYDOWN:
164 switch (msg.wParam)
165 {
166 case VK_UP:
167 hittest = HTTOP;
168 pt.x = (rectWindow.left+rectWindow.right)/2;
169 pt.y = rectWindow.top + UserGetSystemMetrics(SM_CYFRAME) / 2;
170 break;
171 case VK_DOWN:
172 hittest = HTBOTTOM;
173 pt.x = (rectWindow.left+rectWindow.right)/2;
174 pt.y = rectWindow.bottom - UserGetSystemMetrics(SM_CYFRAME) / 2;
175 break;
176 case VK_LEFT:
177 hittest = HTLEFT;
178 pt.x = rectWindow.left + UserGetSystemMetrics(SM_CXFRAME) / 2;
179 pt.y = (rectWindow.top+rectWindow.bottom)/2;
180 break;
181 case VK_RIGHT:
182 hittest = HTRIGHT;
183 pt.x = rectWindow.right - UserGetSystemMetrics(SM_CXFRAME) / 2;
184 pt.y = (rectWindow.top+rectWindow.bottom)/2;
185 break;
186 case VK_RETURN:
187 case VK_ESCAPE:
188 return 0;
189 }
190 default:
191 IntTranslateKbdMessage( &msg, 0 );
192 pti->TIF_flags |= TIF_MOVESIZETRACKING;
193 IntDispatchMessage( &msg );
194 pti->TIF_flags |= TIF_MOVESIZETRACKING;
195 break;
196 }
197 }
198 *capturePoint = pt;
199 }
200 UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
201 co_IntSendMessage(UserHMGetHandle(Wnd), WM_SETCURSOR, (WPARAM)UserHMGetHandle(Wnd), MAKELONG(hittest, WM_MOUSEMOVE));
202 return hittest;
203 }
204
205 //
206 // System Command Size and Move
207 //
208 // Perform SC_MOVE and SC_SIZE commands.
209 //
210 VOID FASTCALL
211 DefWndDoSizeMove(PWND pwnd, WORD wParam)
212 {
213 MSG msg;
214 RECT sizingRect, mouseRect, origRect, unmodRect;
215 HDC hdc;
216 LONG hittest = (LONG)(wParam & 0x0f);
217 PCURICON_OBJECT DragCursor = NULL, OldCursor = NULL;
218 POINT minTrack, maxTrack;
219 POINT capturePoint, pt;
220 ULONG Style, ExStyle;
221 BOOL thickframe;
222 BOOL iconic;
223 BOOL moved = FALSE;
224 BOOL DragFullWindows = FALSE;
225 PWND pWndParent = NULL;
226 WPARAM syscommand = (wParam & 0xfff0);
227 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
228 //PMONITOR mon = 0; Don't port sync from wine!!! This breaks explorer task bar sizing!!
229 // The task bar can grow in size and can not reduce due to the change
230 // in the work area.
231
232 Style = pwnd->style;
233 ExStyle = pwnd->ExStyle;
234 iconic = (Style & WS_MINIMIZE) != 0;
235
236 if ((Style & WS_MAXIMIZE) || !IntIsWindowVisible(pwnd)) return;
237
238 thickframe = UserHasThickFrameStyle(Style, ExStyle) && !iconic;
239
240 //
241 // Show window contents while dragging the window, get flag from registry data.
242 //
243 UserSystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
244
245 pt.x = pti->ptLast.x;
246 pt.y = pti->ptLast.y;
247 capturePoint = pt;
248 UserClipCursor( NULL );
249
250 TRACE("pwnd %p command %04lx, hittest %d, pos %d,%d\n",
251 pwnd, syscommand, hittest, pt.x, pt.y);
252
253 if (syscommand == SC_MOVE)
254 {
255 if (!hittest) hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
256 if (!hittest) return;
257 }
258 else /* SC_SIZE */
259 {
260 if (!thickframe) return;
261 if (hittest && (syscommand != SC_MOUSEMENU))
262 {
263 hittest += (HTLEFT - WMSZ_LEFT);
264 }
265 else
266 {
267 co_UserSetCapture(UserHMGetHandle(pwnd));
268 hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
269 if (!hittest)
270 {
271 IntReleaseCapture();
272 return;
273 }
274 }
275 }
276
277 /* Get min/max info */
278
279 co_WinPosGetMinMaxInfo(pwnd, NULL, NULL, &minTrack, &maxTrack);
280 sizingRect = pwnd->rcWindow;
281 origRect = sizingRect;
282 if (Style & WS_CHILD)
283 {
284 pWndParent = IntGetParent(pwnd);
285 IntGetClientRect( pWndParent, &mouseRect );
286 IntMapWindowPoints( pWndParent, 0, (LPPOINT)&mouseRect, 2 );
287 IntMapWindowPoints( 0, pWndParent, (LPPOINT)&sizingRect, 2 );
288 unmodRect = sizingRect;
289 }
290 else
291 {
292 if (!(ExStyle & WS_EX_TOPMOST))
293 {
294 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0);
295 }
296 else
297 {
298 RECTL_vSetRect(&mouseRect, 0, 0, UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN));
299 }
300 unmodRect = sizingRect;
301 }
302
303 if (ON_LEFT_BORDER(hittest))
304 {
305 mouseRect.left = max( mouseRect.left, sizingRect.right-maxTrack.x+capturePoint.x-sizingRect.left );
306 mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x+capturePoint.x-sizingRect.left );
307 }
308 else if (ON_RIGHT_BORDER(hittest))
309 {
310 mouseRect.left = max( mouseRect.left, sizingRect.left+minTrack.x+capturePoint.x-sizingRect.right );
311 mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x+capturePoint.x-sizingRect.right );
312 }
313 if (ON_TOP_BORDER(hittest))
314 {
315 mouseRect.top = max( mouseRect.top, sizingRect.bottom-maxTrack.y+capturePoint.y-sizingRect.top );
316 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y+capturePoint.y-sizingRect.top);
317 }
318 else if (ON_BOTTOM_BORDER(hittest))
319 {
320 mouseRect.top = max( mouseRect.top, sizingRect.top+minTrack.y+capturePoint.y-sizingRect.bottom );
321 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y+capturePoint.y-sizingRect.bottom );
322 }
323
324 hdc = UserGetDCEx( pWndParent, 0, DCX_CACHE );
325 if (iconic)
326 {
327 DragCursor = pwnd->pcls->spicn;
328 if (DragCursor)
329 {
330 UserReferenceObject(DragCursor);
331 }
332 else
333 {
334 HCURSOR CursorHandle = (HCURSOR)co_IntSendMessage( UserHMGetHandle(pwnd), WM_QUERYDRAGICON, 0, 0 );
335 if (CursorHandle)
336 {
337 DragCursor = UserGetCurIconObject(CursorHandle);
338 }
339 else
340 {
341 iconic = FALSE;
342 }
343 }
344 }
345
346 /* repaint the window before moving it around */
347 co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
348
349 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZESTART, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
350
351 co_IntSendMessage( UserHMGetHandle(pwnd), WM_ENTERSIZEMOVE, 0, 0 );
352
353 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, UserHMGetHandle(pwnd));
354
355 if (IntGetCapture() != UserHMGetHandle(pwnd)) co_UserSetCapture( UserHMGetHandle(pwnd) );
356
357 pwnd->head.pti->TIF_flags |= TIF_MOVESIZETRACKING;
358
359 for(;;)
360 {
361 int dx = 0, dy = 0;
362
363 if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) break;
364 if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue;
365
366 /* Exit on button-up, Return, or Esc */
367 if ((msg.message == WM_LBUTTONUP) ||
368 ((msg.message == WM_KEYDOWN) &&
369 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
370
371 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
372 {
373 IntTranslateKbdMessage( &msg , 0 );
374 IntDispatchMessage( &msg );
375 continue; /* We are not interested in other messages */
376 }
377
378 pt = msg.pt;
379
380 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
381 {
382 case VK_UP: pt.y -= 8; break;
383 case VK_DOWN: pt.y += 8; break;
384 case VK_LEFT: pt.x -= 8; break;
385 case VK_RIGHT: pt.x += 8; break;
386 }
387
388 pt.x = max( pt.x, mouseRect.left );
389 pt.x = min( pt.x, mouseRect.right - 1 );
390 pt.y = max( pt.y, mouseRect.top );
391 pt.y = min( pt.y, mouseRect.bottom - 1 );
392
393 dx = pt.x - capturePoint.x;
394 dy = pt.y - capturePoint.y;
395
396 if (dx || dy)
397 {
398 if ( !moved )
399 {
400 moved = TRUE;
401 if ( iconic ) /* ok, no system popup tracking */
402 {
403 OldCursor = UserSetCursor(DragCursor, FALSE);
404 UserShowCursor( TRUE );
405 }
406 else if(!DragFullWindows)
407 UserDrawMovingFrame( hdc, &sizingRect, thickframe );
408 }
409
410 if (msg.message == WM_KEYDOWN) UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
411 else
412 {
413 RECT newRect = unmodRect;
414
415 if (!iconic && !DragFullWindows) UserDrawMovingFrame( hdc, &sizingRect, thickframe );
416 if (hittest == HTCAPTION) RECTL_vOffsetRect( &newRect, dx, dy );
417 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
418 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
419 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
420 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
421 capturePoint = pt;
422
423 //
424 // Save the new position to the unmodified rectangle. This allows explorer task bar
425 // sizing. Explorer will forces back the position unless a certain amount of sizing
426 // has occurred.
427 //
428 unmodRect = newRect;
429
430 /* determine the hit location */
431 if (syscommand == SC_SIZE)
432 {
433 WPARAM wpSizingHit = 0;
434
435 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
436 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
437 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SIZING, wpSizingHit, (LPARAM)&newRect );
438 }
439 else
440 co_IntSendMessage( UserHMGetHandle(pwnd), WM_MOVING, 0, (LPARAM)&newRect );
441
442 if (!iconic)
443 {
444 if (!DragFullWindows)
445 UserDrawMovingFrame( hdc, &newRect, thickframe );
446 else
447 { // Moving the whole window now!
448 PWND pwndTemp;
449 //// This causes the mdi child window to jump up when it is moved.
450 //IntMapWindowPoints( 0, pWndParent, (POINT *)&rect, 2 );
451 co_WinPosSetWindowPos( pwnd,
452 0,
453 newRect.left,
454 newRect.top,
455 newRect.right - newRect.left,
456 newRect.bottom - newRect.top,
457 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
458
459 // Update all the windows after the move or size, including this window.
460 for ( pwndTemp = pwnd->head.rpdesk->pDeskInfo->spwnd->spwndChild;
461 pwndTemp;
462 pwndTemp = pwndTemp->spwndNext )
463 {
464 RECTL rect;
465 // Only the windows that overlap will be redrawn.
466 if (RECTL_bIntersectRect( &rect, &pwnd->rcWindow, &pwndTemp->rcWindow ))
467 {
468 co_UserRedrawWindow( pwndTemp, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN);
469 }
470 }
471 }
472 }
473 sizingRect = newRect;
474 }
475 }
476 }
477
478 pwnd->head.pti->TIF_flags &= ~TIF_MOVESIZETRACKING;
479
480 IntReleaseCapture();
481
482 if ( iconic )
483 {
484 if ( moved ) /* restore cursors, show icon title later on */
485 {
486 UserShowCursor( FALSE );
487 OldCursor = UserSetCursor(OldCursor, FALSE);
488 }
489
490 /* It could be that the cursor was already changed while we were proceeding,
491 * so we must unreference whatever cursor was current at the time we restored the old one.
492 * Maybe it is DragCursor, but maybe it is another one and DragCursor got already freed.
493 */
494 if (OldCursor) UserDereferenceObject(OldCursor);
495 }
496 else if ( moved && !DragFullWindows )
497 UserDrawMovingFrame( hdc, &sizingRect, thickframe );
498
499 UserReleaseDC(NULL, hdc, FALSE);
500
501 //// This causes the mdi child window to jump up when it is moved.
502 //if (pWndParent) IntMapWindowPoints( 0, pWndParent, (POINT *)&sizingRect, 2 );
503
504 if (co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)UserHMGetHandle(pwnd), (LPARAM)&sizingRect))
505 {
506 ERR("DoSizeMove : WH_CBT Call Hook return!\n");
507 moved = FALSE;
508 }
509
510 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZEEND, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
511
512 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
513
514 co_IntSendMessage( UserHMGetHandle(pwnd), WM_EXITSIZEMOVE, 0, 0 );
515 //// wine mdi hack
516 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SETVISIBLE, !!(pwnd->style & WS_MINIMIZE), 0L);
517 ////
518 /* window moved or resized */
519 if (moved)
520 {
521 /* if the moving/resizing isn't canceled call SetWindowPos
522 * with the new position or the new size of the window
523 */
524 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
525 {
526 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
527 if (!DragFullWindows || iconic )
528 {
529 co_WinPosSetWindowPos( pwnd,
530 0,
531 sizingRect.left,
532 sizingRect.top,
533 sizingRect.right - sizingRect.left,
534 sizingRect.bottom - sizingRect.top,
535 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
536 }
537 }
538 else
539 { /* restore previous size/position */
540 if ( DragFullWindows )
541 {
542 co_WinPosSetWindowPos( pwnd,
543 0,
544 origRect.left,
545 origRect.top,
546 origRect.right - origRect.left,
547 origRect.bottom - origRect.top,
548 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
549 }
550 }
551 }
552
553 if ( IntIsWindow(UserHMGetHandle(pwnd)) )
554 {
555 if ( iconic )
556 {
557 /* Single click brings up the system menu when iconized */
558 if ( !moved )
559 {
560 if( Style & WS_SYSMENU )
561 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
562 }
563 }
564 }
565 }
566
567 PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND pWnd )
568 {
569 PCURICON_OBJECT pIcon = NULL;
570 HICON hIcon;
571
572 //FIXME: Some callers use this function as if it returns a boolean saying "this window has an icon".
573 //FIXME: Hence we must return a pointer with no reference count.
574 //FIXME: This is bad and we should feel bad.
575 //FIXME: Stop whining over wine code.
576
577 hIcon = UserGetProp(pWnd, gpsi->atomIconSmProp);
578 if (!hIcon) hIcon = UserGetProp(pWnd, gpsi->atomIconProp);
579
580 if (!hIcon && pWnd->pcls->spicnSm)
581 return pWnd->pcls->spicnSm;
582 if (!hIcon && pWnd->pcls->spicn)
583 return pWnd->pcls->spicn;
584
585 if (!hIcon && (pWnd->style & DS_MODALFRAME))
586 {
587 if (!hIcon) hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small
588 if (!hIcon) hIcon = gpsi->hIconWindows; // Reg size.
589 }
590 if (hIcon)
591 {
592 pIcon = UserGetCurIconObject(hIcon);
593 if (pIcon)
594 {
595 UserDereferenceObject(pIcon);
596 }
597 }
598 return pIcon;
599 }
600
601 DWORD FASTCALL
602 GetNCHitEx(PWND pWnd, POINT pt)
603 {
604 RECT rcWindow, rcClient;
605 DWORD Style, ExStyle;
606
607 if (!pWnd) return HTNOWHERE;
608
609 if (pWnd == UserGetDesktopWindow()) // pWnd->fnid == FNID_DESKTOP)
610 {
611 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0;
612 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN);
613 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN);
614 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN);
615 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN);
616 }
617 else
618 {
619 rcClient = pWnd->rcClient;
620 rcWindow = pWnd->rcWindow;
621 }
622
623 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE;
624
625 Style = pWnd->style;
626 ExStyle = pWnd->ExStyle;
627
628 if (Style & WS_MINIMIZE) return HTCAPTION;
629
630 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT;
631
632 /* Check borders */
633 if (HAS_THICKFRAME( Style, ExStyle ))
634 {
635 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
636 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y ))
637 {
638 /* Check top sizing border */
639 if (pt.y < rcWindow.top)
640 {
641 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
642 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
643 return HTTOP;
644 }
645 /* Check bottom sizing border */
646 if (pt.y >= rcWindow.bottom)
647 {
648 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
649 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
650 return HTBOTTOM;
651 }
652 /* Check left sizing border */
653 if (pt.x < rcWindow.left)
654 {
655 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
656 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
657 return HTLEFT;
658 }
659 /* Check right sizing border */
660 if (pt.x >= rcWindow.right)
661 {
662 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
663 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
664 return HTRIGHT;
665 }
666 }
667 }
668 else /* No thick frame */
669 {
670 if (HAS_DLGFRAME( Style, ExStyle ))
671 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
672 else if (HAS_THINFRAME( Style, ExStyle ))
673 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
674 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER;
675 }
676
677 /* Check caption */
678
679 if ((Style & WS_CAPTION) == WS_CAPTION)
680 {
681 if (ExStyle & WS_EX_TOOLWINDOW)
682 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
683 else
684 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1;
685 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y ))
686 {
687 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
688 if (ExStyle & WS_EX_LAYOUTRTL)
689 {
690 /* Check system menu */
691 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
692 {
693 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
694 if (pt.x > rcWindow.right) return HTSYSMENU;
695 }
696
697 /* Check close button */
698 if (Style & WS_SYSMENU)
699 {
700 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION);
701 if (pt.x < rcWindow.left) return HTCLOSE;
702 }
703
704 /* Check maximize box */
705 /* In Win95 there is automatically a Maximize button when there is a minimize one */
706 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
707 {
708 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
709 if (pt.x < rcWindow.left) return HTMAXBUTTON;
710 }
711
712 /* Check minimize box */
713 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
714 {
715 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
716 if (pt.x < rcWindow.left) return HTMINBUTTON;
717 }
718 }
719 else
720 {
721 /* Check system menu */
722 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
723 {
724 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1;
725 if (pt.x < rcWindow.left) return HTSYSMENU;
726 }
727
728 /* Check close button */
729 if (Style & WS_SYSMENU)
730 {
731 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION);
732 if (pt.x > rcWindow.right) return HTCLOSE;
733 }
734
735 /* Check maximize box */
736 /* In Win95 there is automatically a Maximize button when there is a minimize one */
737 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
738 {
739 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
740 if (pt.x > rcWindow.right) return HTMAXBUTTON;
741 }
742
743 /* Check minimize box */
744 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
745 {
746 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
747 if (pt.x > rcWindow.right) return HTMINBUTTON;
748 }
749 }
750 return HTCAPTION;
751 }
752 }
753
754 /* Check menu bar */
755
756 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) &&
757 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
758 return HTMENU;
759
760 /* Check vertical scroll bar */
761
762 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR;
763 if (Style & WS_VSCROLL)
764 {
765 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
766 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL);
767 else
768 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL);
769 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL;
770 }
771
772 /* Check horizontal scroll bar */
773
774 if (Style & WS_HSCROLL)
775 {
776 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL);
777 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y ))
778 {
779 /* Check size box */
780 if ((Style & WS_VSCROLL) &&
781 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) ||
782 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL)))))
783 return HTSIZE;
784 return HTHSCROLL;
785 }
786 }
787
788 /* Has to return HTNOWHERE if nothing was found
789 Could happen when a window has a customized non client area */
790 return HTNOWHERE;
791 }
792
793 /* EOF */