2 * Window position related functions.
4 * Copyright 1993 Alexandre Julliard
7 static char Copyright[] = "Copyright Alexandre Julliard, 1993";
9 #include "sysmetrics.h"
14 static HWND hwndActive = 0; /* Currently active window */
17 /***********************************************************************
18 * GetWindowRect (USER.32)
20 void GetWindowRect( HWND hwnd, LPRECT rect )
22 WND * wndPtr = WIN_FindWndPtr( hwnd );
25 *rect = wndPtr->rectWindow;
26 if (wndPtr->dwStyle & WS_CHILD)
27 MapWindowPoints( wndPtr->hwndParent, 0, (POINT *)rect, 2 );
31 /***********************************************************************
32 * GetClientRect (USER.33)
34 void GetClientRect( HWND hwnd, LPRECT rect )
36 WND * wndPtr = WIN_FindWndPtr( hwnd );
38 rect->left = rect->top = rect->right = rect->bottom = 0;
41 rect->right = wndPtr->rectClient.right - wndPtr->rectClient.left;
42 rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
47 /*******************************************************************
48 * ClientToScreen (USER.28)
50 void ClientToScreen( HWND hwnd, LPPOINT lppnt )
52 MapWindowPoints( hwnd, 0, lppnt, 1 );
56 /*******************************************************************
57 * ScreenToClient (USER.29)
59 void ScreenToClient( HWND hwnd, LPPOINT lppnt )
61 MapWindowPoints( 0, hwnd, lppnt, 1 );
65 /*******************************************************************
66 * WindowFromPoint (USER.30)
68 HWND WindowFromPoint( POINT pt )
71 HWND hwnd = GetDesktopWindow();
75 /* If point is in window, and window is visible, */
76 /* not disabled and not transparent, then explore */
77 /* its children. Otherwise, go to the next window. */
79 WND *wndPtr = WIN_FindWndPtr( hwnd );
80 if ((pt.x >= wndPtr->rectWindow.left) &&
81 (pt.x < wndPtr->rectWindow.right) &&
82 (pt.y >= wndPtr->rectWindow.top) &&
83 (pt.y < wndPtr->rectWindow.bottom) &&
84 !(wndPtr->dwStyle & WS_DISABLED) &&
85 (wndPtr->dwStyle & WS_VISIBLE) &&
86 !(wndPtr->dwExStyle & WS_EX_TRANSPARENT))
88 pt.x -= wndPtr->rectClient.left;
89 pt.y -= wndPtr->rectClient.top;
91 hwnd = wndPtr->hwndChild;
93 else hwnd = wndPtr->hwndNext;
99 /*******************************************************************
100 * ChildWindowFromPoint (USER.191)
102 HWND ChildWindowFromPoint( HWND hwndParent, POINT pt )
107 GetWindowRect( hwndParent, &rect );
108 if (!PtInRect( &rect, pt )) return 0;
109 hwnd = GetTopWindow( hwndParent );
112 GetWindowRect( hwnd, &rect );
113 if (PtInRect( &rect, pt )) return hwnd;
114 hwnd = GetWindow( hwnd, GW_HWNDNEXT );
120 /*******************************************************************
121 * MapWindowPoints (USER.258)
123 void MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, WORD count )
127 POINT origin = { 0, 0 };
130 /* Translate source window origin to screen coords */
133 wndPtr = WIN_FindWndPtr( hwndFrom );
134 origin.x += wndPtr->rectClient.left;
135 origin.y += wndPtr->rectClient.top;
136 hwndFrom = (wndPtr->dwStyle & WS_CHILD) ? wndPtr->hwndParent : 0;
139 /* Translate origin to destination window coords */
142 wndPtr = WIN_FindWndPtr( hwndTo );
143 origin.x -= wndPtr->rectClient.left;
144 origin.y -= wndPtr->rectClient.top;
145 hwndTo = (wndPtr->dwStyle & WS_CHILD) ? wndPtr->hwndParent : 0;
148 /* Translate points */
149 for (i = 0, curpt = lppt; i < count; i++, curpt++)
151 curpt->x += origin.x;
152 curpt->y += origin.y;
157 /***********************************************************************
160 BOOL IsIconic(HWND hWnd)
162 WND * wndPtr = WIN_FindWndPtr(hWnd);
163 if (wndPtr == NULL) return FALSE;
164 return (wndPtr->dwStyle & WS_MINIMIZE) != 0;
168 /***********************************************************************
169 * IsZoomed (USER.272)
171 BOOL IsZoomed(HWND hWnd)
173 WND * wndPtr = WIN_FindWndPtr(hWnd);
174 if (wndPtr == NULL) return FALSE;
175 return (wndPtr->dwStyle & WS_MAXIMIZE) != 0;
179 /*******************************************************************
180 * GetActiveWindow (USER.60)
182 HWND GetActiveWindow()
187 /*******************************************************************
188 * SetActiveWindow (USER.59)
190 HWND SetActiveWindow( HWND hwnd )
192 HWND prev = hwndActive;
193 WND *wndPtr = WIN_FindWndPtr( hwnd );
194 if (!wndPtr || (wndPtr->dwStyle & WS_CHILD)) return 0;
195 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
200 /***********************************************************************
201 * BringWindowToTop (USER.45)
203 BOOL BringWindowToTop( HWND hwnd )
205 return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
209 /***********************************************************************
210 * MoveWindow (USER.56)
212 BOOL MoveWindow( HWND hwnd, short x, short y, short cx, short cy, BOOL repaint)
214 int flags = SWP_NOZORDER | SWP_NOACTIVATE;
215 if (!repaint) flags |= SWP_NOREDRAW;
217 printf( "MoveWindow: %d %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint );
219 return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
223 /***********************************************************************
224 * ShowWindow (USER.42)
226 BOOL ShowWindow( HWND hwnd, int cmd )
228 WND * wndPtr = WIN_FindWndPtr( hwnd );
233 printf("ShowWindow: hwnd=%04X, cmd=%d\n", hwnd, cmd);
236 if (!wndPtr) return FALSE;
237 wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
241 if (!wasVisible) return FALSE; /* Nothing to do */
242 swpflags |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
243 SWP_NOACTIVATE | SWP_NOZORDER;
246 case SW_SHOWMINNOACTIVE:
247 case SW_SHOWMINIMIZED:
248 case SW_SHOWMAXIMIZED:
250 wndPtr->dwStyle |= WS_MINIMIZE;
251 swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE |
252 SWP_NOACTIVATE | SWP_NOZORDER;
258 swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
263 case SW_SHOWNOACTIVATE:
265 wndPtr->dwStyle &= ~WS_MINIMIZE;
266 wndPtr->dwStyle &= ~WS_MAXIMIZE;
267 swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
268 if (cmd == SW_SHOWNOACTIVATE)
270 swpflags |= SWP_NOZORDER;
271 if (GetActiveWindow()) swpflags |= SWP_NOACTIVATE;
275 SendMessage( hwnd, WM_SHOWWINDOW, (cmd != SW_HIDE), 0 );
276 SetWindowPos( hwnd, 0, 0, 0, 0, 0, swpflags );
278 /* Send WM_SIZE and WM_MOVE messages if not already done */
279 if (!(wndPtr->flags & WIN_GOT_SIZEMSG))
281 int wParam = SIZE_RESTORED;
282 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
283 else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
284 wndPtr->flags |= WIN_GOT_SIZEMSG;
285 SendMessage( hwnd, WM_SIZE, wParam,
286 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
287 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
288 SendMessage( hwnd, WM_MOVE, 0,
289 MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
295 /***********************************************************************
296 * GetInternalWindowPos (USER.460)
298 WORD GetInternalWindowPos( HWND hwnd, LPRECT rectWnd, LPPOINT ptIcon )
300 WINDOWPLACEMENT wndpl;
301 if (!GetWindowPlacement( hwnd, &wndpl )) return 0;
302 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
303 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
304 return wndpl.showCmd;
308 /***********************************************************************
309 * SetInternalWindowPos (USER.461)
311 void SetInternalWindowPos( HWND hwnd, WORD showCmd, LPRECT rect, LPPOINT pt )
313 WINDOWPLACEMENT wndpl;
314 WND *wndPtr = WIN_FindWndPtr( hwnd );
316 wndpl.length = sizeof(wndpl);
317 wndpl.flags = (pt != NULL) ? WPF_SETMINPOSITION : 0;
318 wndpl.showCmd = showCmd;
319 if (pt) wndpl.ptMinPosition = *pt;
320 wndpl.rcNormalPosition = (rect != NULL) ? *rect : wndPtr->rectNormal;
321 wndpl.ptMaxPosition = wndPtr->ptMaxPos;
322 SetWindowPlacement( hwnd, &wndpl );
326 /***********************************************************************
327 * GetWindowPlacement (USER.370)
329 BOOL GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
331 WND *wndPtr = WIN_FindWndPtr( hwnd );
332 if (!wndPtr) return FALSE;
334 wndpl->length = sizeof(*wndpl);
336 wndpl->showCmd = IsZoomed(hwnd) ? SW_SHOWMAXIMIZED :
337 (IsIconic(hwnd) ? SW_SHOWMINIMIZED : SW_SHOWNORMAL);
338 wndpl->ptMinPosition = wndPtr->ptIconPos;
339 wndpl->ptMaxPosition = wndPtr->ptMaxPos;
340 wndpl->rcNormalPosition = wndPtr->rectNormal;
345 /***********************************************************************
346 * SetWindowPlacement (USER.371)
348 BOOL SetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
350 WND *wndPtr = WIN_FindWndPtr( hwnd );
351 if (!wndPtr) return FALSE;
353 if (wndpl->flags & WPF_SETMINPOSITION)
354 wndPtr->ptIconPos = wndpl->ptMinPosition;
355 if ((wndpl->flags & WPF_RESTORETOMAXIMIZED) &&
356 (wndpl->showCmd == SW_SHOWMINIMIZED)) wndPtr->flags |= WIN_RESTORE_MAX;
357 wndPtr->ptMaxPos = wndpl->ptMaxPosition;
358 wndPtr->rectNormal = wndpl->rcNormalPosition;
359 ShowWindow( hwnd, wndpl->showCmd );
364 /*******************************************************************
365 * WINPOS_GetMinMaxInfo
367 * Send a WM_GETMINMAXINFO to the window.
369 void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos,
370 POINT *minTrack, POINT *maxTrack )
373 MINMAXINFO MinMax, *pMinMax;
374 WND *wndPtr = WIN_FindWndPtr( hwnd );
376 MinMax.ptMaxSize.x = SYSMETRICS_CXSCREEN;
377 MinMax.ptMaxSize.y = SYSMETRICS_CYSCREEN;
378 MinMax.ptMaxPosition = wndPtr->ptMaxPos;
379 MinMax.ptMinTrackSize.x = SYSMETRICS_CXMINTRACK;
380 MinMax.ptMinTrackSize.y = SYSMETRICS_CYMINTRACK;
381 MinMax.ptMaxTrackSize.x = SYSMETRICS_CXSCREEN;
382 MinMax.ptMaxTrackSize.y = SYSMETRICS_CYSCREEN;
384 minmaxHandle = USER_HEAP_ALLOC( LMEM_MOVEABLE, sizeof(MINMAXINFO) );
387 pMinMax = (MINMAXINFO *) USER_HEAP_ADDR( minmaxHandle );
388 memcpy( pMinMax, &MinMax, sizeof(MinMax) );
389 SendMessage( hwnd, WM_GETMINMAXINFO, 0, (LONG)pMinMax );
391 else pMinMax = &MinMax;
393 /* Some sanity checks */
395 pMinMax->ptMaxTrackSize.x = max( pMinMax->ptMaxTrackSize.x,
396 pMinMax->ptMinTrackSize.x );
397 pMinMax->ptMaxTrackSize.y = max( pMinMax->ptMaxTrackSize.y,
398 pMinMax->ptMinTrackSize.y );
400 if (maxSize) *maxSize = pMinMax->ptMaxSize;
401 if (maxPos) *maxPos = pMinMax->ptMaxPosition;
402 if (minTrack) *minTrack = pMinMax->ptMinTrackSize;
403 if (maxTrack) *maxTrack = pMinMax->ptMaxTrackSize;
404 if (minmaxHandle) USER_HEAP_FREE( minmaxHandle );
408 /*******************************************************************
409 * WINPOS_ChangeActiveWindow
411 * Change the active window and send the corresponding messages.
413 HWND WINPOS_ChangeActiveWindow( HWND hwnd, BOOL mouseMsg )
415 HWND prevActive = hwndActive;
416 if (hwnd == hwndActive) return 0;
419 if (!SendMessage( hwndActive, WM_NCACTIVATE, FALSE, 0 )) return 0;
420 SendMessage( hwndActive, WM_ACTIVATE, WA_INACTIVE,
421 MAKELONG( IsIconic(hwndActive), hwnd ) );
422 /* Send WM_ACTIVATEAPP here */
428 WND *wndPtr = WIN_FindWndPtr( hwndActive );
429 wndPtr->hwndPrevActive = prevActive;
431 /* Send WM_ACTIVATEAPP here */
432 SendMessage( hwnd, WM_NCACTIVATE, TRUE, 0 );
433 SendMessage( hwnd, WM_ACTIVATE, mouseMsg ? WA_CLICKACTIVE : WA_ACTIVE,
434 MAKELONG( IsIconic(hwnd), prevActive ) );
440 /***********************************************************************
441 * SetWindowPos (USER.232)
443 /* Note: all this code should be in the DeferWindowPos() routines,
444 * and SetWindowPos() should simply call them. This will be implemented
447 BOOL SetWindowPos( HWND hwnd, HWND hwndInsertAfter, short x, short y,
448 short cx, short cy, WORD flags )
452 RECT newWindowRect, newClientRect;
454 int calcsize_result = 0;
455 XWindowChanges winChanges;
459 printf( "SetWindowPos: %04X %d %d,%d %dx%d 0x%x\n",
460 hwnd, hwndInsertAfter, x, y, cx, cy, flags );
463 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
464 if (flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW))
465 flags |= SWP_NOMOVE | SWP_NOSIZE;
467 /* Send WM_WINDOWPOSCHANGING message */
469 if (!(hmem = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(WINDOWPOS) )))
471 winPos = (WINDOWPOS *)USER_HEAP_ADDR( hmem );
473 winPos->hwndInsertAfter = hwndInsertAfter;
478 winPos->flags = flags;
479 SendMessage( hwnd, WM_WINDOWPOSCHANGING, 0, (LONG)winPos );
480 hwndInsertAfter = winPos->hwndInsertAfter;
482 /* Some sanity checks */
484 if (!IsWindow( hwnd ) || (hwnd == GetDesktopWindow())) goto Abort;
485 if (flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW))
486 flags |= SWP_NOMOVE | SWP_NOSIZE;
487 if (!(flags & (SWP_NOZORDER | SWP_NOACTIVATE)))
489 if (hwnd != hwndActive) hwndInsertAfter = HWND_TOP;
490 else if ((hwndInsertAfter == HWND_TOPMOST) ||
491 (hwndInsertAfter == HWND_NOTOPMOST))
492 hwndInsertAfter = HWND_TOP;
495 /* Calculate new position and size */
497 newWindowRect = wndPtr->rectWindow;
498 newClientRect = wndPtr->rectClient;
500 if (!(winPos->flags & SWP_NOSIZE))
502 newWindowRect.right = newWindowRect.left + winPos->cx;
503 newWindowRect.bottom = newWindowRect.top + winPos->cy;
506 if (!(winPos->flags & SWP_NOMOVE))
508 newWindowRect.left = winPos->x;
509 newWindowRect.top = winPos->y;
510 newWindowRect.right += winPos->x - wndPtr->rectWindow.left;
511 newWindowRect.bottom += winPos->y - wndPtr->rectWindow.top;
514 /* Reposition window in Z order */
516 if (!(winPos->flags & SWP_NOZORDER))
518 /* TOPMOST not supported yet */
519 if ((hwndInsertAfter == HWND_TOPMOST) ||
520 (hwndInsertAfter == HWND_NOTOPMOST)) hwndInsertAfter = HWND_TOP;
522 /* Make sure hwndInsertAfter is a sibling of hwnd */
523 if ((hwndInsertAfter != HWND_TOP) && (hwndInsertAfter != HWND_BOTTOM))
524 if (GetParent(hwnd) != GetParent(hwndInsertAfter)) goto Abort;
526 WIN_UnlinkWindow( hwnd );
527 WIN_LinkWindow( hwnd, hwndInsertAfter );
530 /* Recalculate client area position */
532 if (winPos->flags & SWP_FRAMECHANGED)
534 /* Send WM_NCCALCSIZE message */
535 NCCALCSIZE_PARAMS *params;
538 if (!(hparams = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(*params) )))
540 params = (NCCALCSIZE_PARAMS *) USER_HEAP_ADDR( hparams );
541 params->rgrc[0] = newWindowRect;
542 params->rgrc[1] = wndPtr->rectWindow;
543 params->rgrc[2] = wndPtr->rectClient;
544 params->lppos = winPos;
545 calcsize_result = SendMessage(hwnd, WM_NCCALCSIZE, TRUE, (LONG)params);
546 USER_HEAP_FREE( hparams );
547 newClientRect = params->rgrc[0];
548 /* Handle result here */
552 newClientRect.left = newWindowRect.left + wndPtr->rectClient.left
553 - wndPtr->rectWindow.left;
554 newClientRect.top = newWindowRect.top + wndPtr->rectClient.top
555 - wndPtr->rectWindow.top;
556 newClientRect.right = newWindowRect.right + wndPtr->rectClient.right
557 - wndPtr->rectWindow.right;
558 newClientRect.bottom = newWindowRect.bottom + wndPtr->rectClient.bottom
559 - wndPtr->rectWindow.bottom;
562 /* Perform the moving and resizing */
564 if (!(winPos->flags & SWP_NOMOVE))
567 winChanges.x = newWindowRect.left;
568 winChanges.y = newWindowRect.top;
569 if (wndPtr->dwStyle & WS_CHILD)
571 parentPtr = WIN_FindWndPtr(wndPtr->hwndParent);
572 winChanges.x += parentPtr->rectClient.left-parentPtr->rectWindow.left;
573 winChanges.y += parentPtr->rectClient.top-parentPtr->rectWindow.top;
575 changeMask |= CWX | CWY;
577 if (!(winPos->flags & SWP_NOSIZE))
579 winChanges.width = newWindowRect.right - newWindowRect.left;
580 winChanges.height = newWindowRect.bottom - newWindowRect.top;
581 changeMask |= CWWidth | CWHeight;
583 if (!(winPos->flags & SWP_NOZORDER))
585 if (hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
586 else winChanges.stack_mode = Below;
587 if ((hwndInsertAfter != HWND_TOP) && (hwndInsertAfter != HWND_BOTTOM))
589 WND * insertPtr = WIN_FindWndPtr( hwndInsertAfter );
590 winChanges.sibling = insertPtr->window;
591 changeMask |= CWSibling;
593 changeMask |= CWStackMode;
595 if ((newWindowRect.right - newWindowRect.left) != 0 &&
596 (newWindowRect.bottom - newWindowRect.top) != 0)
597 if (changeMask) XConfigureWindow( display, wndPtr->window,
598 changeMask, &winChanges );
600 if ((newWindowRect.right - newWindowRect.left) != 0 &&
601 (newWindowRect.bottom - newWindowRect.top) != 0 &&
602 (winPos->flags & SWP_SHOWWINDOW))
604 wndPtr->dwStyle |= WS_VISIBLE;
605 XMapWindow( display, wndPtr->window );
607 if (winPos->flags & SWP_NOREDRAW)
608 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE );
610 else if (winPos->flags & SWP_HIDEWINDOW)
612 wndPtr->dwStyle &= ~WS_VISIBLE;
613 XUnmapWindow( display, wndPtr->window );
614 if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus() ))
615 SetFocus( GetParent(hwnd) ); /* Revert focus to parent (if any) */
616 if (hwnd == hwndActive)
618 /* Activate previously active window if possible */
619 HWND newActive = wndPtr->hwndPrevActive;
620 if (!IsWindow(newActive) || (newActive == hwnd))
622 newActive = GetTopWindow(GetDesktopWindow());
623 if (newActive == hwnd) newActive = wndPtr->hwndNext;
625 WINPOS_ChangeActiveWindow( newActive, FALSE );
629 if (!(winPos->flags & SWP_NOACTIVATE))
631 if (!(wndPtr->dwStyle & WS_CHILD))
632 WINPOS_ChangeActiveWindow( hwnd, FALSE );
635 /* Send WM_NCPAINT message if needed */
636 if ((winPos->flags & (SWP_FRAMECHANGED | SWP_SHOWWINDOW)) ||
637 (!(winPos->flags & SWP_NOSIZE)) ||
638 (!(winPos->flags & SWP_NOMOVE)) ||
639 (!(winPos->flags & SWP_NOACTIVATE)) ||
640 (!(winPos->flags & SWP_NOZORDER)))
641 SendMessage( hwnd, WM_NCPAINT, 1, 0L );
643 /* Finally send the WM_WINDOWPOSCHANGED message */
644 wndPtr->rectWindow = newWindowRect;
645 wndPtr->rectClient = newClientRect;
646 SendMessage( hwnd, WM_WINDOWPOSCHANGED, 0, (LONG)winPos );
647 USER_HEAP_FREE( hmem );
651 Abort: /* Fatal error encountered */
652 if (hmem) USER_HEAP_FREE( hmem );