Release 950216
[wine.git] / windows / winpos.c
blob5f71349cf0d18dc97f86b3b98d013c3642a69428
1 /*
2 * Window position related functions.
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
5 */
7 #include "sysmetrics.h"
8 #include "user.h"
9 #include "win.h"
10 #include "message.h"
11 #include "winpos.h"
12 #include "nonclient.h"
13 #include "stddebug.h"
14 /* #define DEBUG_WIN */
15 #include "debug.h"
17 static HWND hwndActive = 0; /* Currently active window */
20 /***********************************************************************
21 * WINPOS_FindIconPos
23 * Find a suitable place for an iconic window.
24 * The new position is stored into wndPtr->ptIconPos.
26 static void WINPOS_FindIconPos( HWND hwnd )
28 RECT rectParent;
29 short x, y, xspacing, yspacing;
30 WND * wndPtr = WIN_FindWndPtr( hwnd );
32 if (!wndPtr) return;
33 GetClientRect( wndPtr->hwndParent, &rectParent );
34 if ((wndPtr->ptIconPos.x >= rectParent.left) &&
35 (wndPtr->ptIconPos.x + SYSMETRICS_CXICON < rectParent.right) &&
36 (wndPtr->ptIconPos.y >= rectParent.top) &&
37 (wndPtr->ptIconPos.y + SYSMETRICS_CYICON < rectParent.bottom))
38 return; /* The icon already has a suitable position */
40 xspacing = yspacing = 70; /* FIXME: This should come from WIN.INI */
41 y = rectParent.bottom;
42 for (;;)
44 for (x = rectParent.left; x<=rectParent.right-xspacing; x += xspacing)
46 /* Check if another icon already occupies this spot */
47 HWND hwndChild = GetWindow( wndPtr->hwndParent, GW_CHILD );
48 while (hwndChild)
50 WND *childPtr = WIN_FindWndPtr( hwndChild );
51 if ((childPtr->dwStyle & WS_MINIMIZE) && (hwndChild != hwnd))
53 if ((childPtr->rectWindow.left < x + xspacing) &&
54 (childPtr->rectWindow.right >= x) &&
55 (childPtr->rectWindow.top <= y) &&
56 (childPtr->rectWindow.bottom > y - yspacing))
57 break; /* There's a window in there */
60 hwndChild = childPtr->hwndNext;
62 if (!hwndChild)
64 /* No window was found, so it's OK for us */
65 wndPtr->ptIconPos.x = x + (xspacing - SYSMETRICS_CXICON) / 2;
66 wndPtr->ptIconPos.y = y - (yspacing + SYSMETRICS_CYICON) / 2;
67 return;
70 y -= yspacing;
75 /***********************************************************************
76 * ArrangeIconicWindows (USER.170)
78 WORD ArrangeIconicWindows( HWND parent )
80 RECT rectParent;
81 HWND hwndChild;
82 short x, y, xspacing, yspacing;
84 GetClientRect( parent, &rectParent );
85 x = rectParent.left;
86 y = rectParent.bottom;
87 xspacing = yspacing = 70; /* FIXME: This should come from WIN.INI */
88 hwndChild = GetWindow( parent, GW_CHILD );
89 while (hwndChild)
91 if (IsIconic( hwndChild ))
93 SetWindowPos( hwndChild, 0, x + (xspacing - SYSMETRICS_CXICON) / 2,
94 y - (yspacing + SYSMETRICS_CYICON) / 2, 0, 0,
95 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
96 if (x <= rectParent.right - xspacing) x += xspacing;
97 else
99 x = rectParent.left;
100 y -= yspacing;
103 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
105 return yspacing;
109 /***********************************************************************
110 * GetWindowRect (USER.32)
112 void GetWindowRect( HWND hwnd, LPRECT rect )
114 WND * wndPtr = WIN_FindWndPtr( hwnd );
115 if (!wndPtr) return;
117 *rect = wndPtr->rectWindow;
118 if (wndPtr->dwStyle & WS_CHILD)
119 MapWindowPoints( wndPtr->hwndParent, 0, (POINT *)rect, 2 );
123 /***********************************************************************
124 * GetClientRect (USER.33)
126 void GetClientRect( HWND hwnd, LPRECT rect )
128 WND * wndPtr = WIN_FindWndPtr( hwnd );
130 rect->left = rect->top = rect->right = rect->bottom = 0;
131 if (wndPtr)
133 rect->right = wndPtr->rectClient.right - wndPtr->rectClient.left;
134 rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
139 /*******************************************************************
140 * ClientToScreen (USER.28)
142 void ClientToScreen( HWND hwnd, LPPOINT lppnt )
144 MapWindowPoints( hwnd, 0, lppnt, 1 );
148 /*******************************************************************
149 * ScreenToClient (USER.29)
151 void ScreenToClient( HWND hwnd, LPPOINT lppnt )
153 MapWindowPoints( 0, hwnd, lppnt, 1 );
157 /*******************************************************************
158 * WindowFromPoint (USER.30)
160 HWND WindowFromPoint( POINT pt )
162 HWND hwndRet = 0;
163 HWND hwnd = GetDesktopWindow();
165 while(hwnd)
167 /* If point is in window, and window is visible, */
168 /* not disabled and not transparent, then explore */
169 /* its children. Otherwise, go to the next window. */
171 WND *wndPtr = WIN_FindWndPtr( hwnd );
172 if ((pt.x >= wndPtr->rectWindow.left) &&
173 (pt.x < wndPtr->rectWindow.right) &&
174 (pt.y >= wndPtr->rectWindow.top) &&
175 (pt.y < wndPtr->rectWindow.bottom) &&
176 !(wndPtr->dwStyle & WS_DISABLED) &&
177 (wndPtr->dwStyle & WS_VISIBLE) &&
178 !(wndPtr->dwExStyle & WS_EX_TRANSPARENT))
180 hwndRet = hwnd;
181 /* If window is minimized, ignore its children */
182 if (wndPtr->dwStyle & WS_MINIMIZE) break;
183 pt.x -= wndPtr->rectClient.left;
184 pt.y -= wndPtr->rectClient.top;
185 hwnd = wndPtr->hwndChild;
187 else hwnd = wndPtr->hwndNext;
189 return hwndRet;
193 /*******************************************************************
194 * ChildWindowFromPoint (USER.191)
196 HWND ChildWindowFromPoint( HWND hwndParent, POINT pt )
198 RECT rect;
199 HWND hwnd;
201 GetWindowRect( hwndParent, &rect );
202 if (!PtInRect( &rect, pt )) return 0;
203 hwnd = GetTopWindow( hwndParent );
204 while (hwnd)
206 GetWindowRect( hwnd, &rect );
207 if (PtInRect( &rect, pt )) return hwnd;
208 hwnd = GetWindow( hwnd, GW_HWNDNEXT );
210 return hwndParent;
214 /*******************************************************************
215 * MapWindowPoints (USER.258)
217 void MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, WORD count )
219 WND * wndPtr;
220 POINT * curpt;
221 POINT origin = { 0, 0 };
222 WORD i;
224 /* Translate source window origin to screen coords */
225 while(hwndFrom)
227 wndPtr = WIN_FindWndPtr( hwndFrom );
228 origin.x += wndPtr->rectClient.left;
229 origin.y += wndPtr->rectClient.top;
230 hwndFrom = (wndPtr->dwStyle & WS_CHILD) ? wndPtr->hwndParent : 0;
233 /* Translate origin to destination window coords */
234 while(hwndTo)
236 wndPtr = WIN_FindWndPtr( hwndTo );
237 origin.x -= wndPtr->rectClient.left;
238 origin.y -= wndPtr->rectClient.top;
239 hwndTo = (wndPtr->dwStyle & WS_CHILD) ? wndPtr->hwndParent : 0;
242 /* Translate points */
243 for (i = 0, curpt = lppt; i < count; i++, curpt++)
245 curpt->x += origin.x;
246 curpt->y += origin.y;
251 /***********************************************************************
252 * IsIconic (USER.31)
254 BOOL IsIconic(HWND hWnd)
256 WND * wndPtr = WIN_FindWndPtr(hWnd);
257 if (wndPtr == NULL) return FALSE;
258 return (wndPtr->dwStyle & WS_MINIMIZE) != 0;
262 /***********************************************************************
263 * IsZoomed (USER.272)
265 BOOL IsZoomed(HWND hWnd)
267 WND * wndPtr = WIN_FindWndPtr(hWnd);
268 if (wndPtr == NULL) return FALSE;
269 return (wndPtr->dwStyle & WS_MAXIMIZE) != 0;
273 /*******************************************************************
274 * GetActiveWindow (USER.60)
276 HWND GetActiveWindow()
278 return hwndActive;
282 /*******************************************************************
283 * SetActiveWindow (USER.59)
285 HWND SetActiveWindow( HWND hwnd )
287 HWND prev = hwndActive;
288 WND *wndPtr = WIN_FindWndPtr( hwnd );
289 if (!wndPtr || (wndPtr->dwStyle & WS_CHILD)) return 0;
290 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
291 return prev;
295 /***********************************************************************
296 * BringWindowToTop (USER.45)
298 BOOL BringWindowToTop( HWND hwnd )
300 return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
304 /***********************************************************************
305 * MoveWindow (USER.56)
307 BOOL MoveWindow( HWND hwnd, short x, short y, short cx, short cy, BOOL repaint)
309 int flags = SWP_NOZORDER | SWP_NOACTIVATE;
310 if (!repaint) flags |= SWP_NOREDRAW;
311 dprintf_win(stddeb, "MoveWindow: %d %d,%d %dx%d %d\n",
312 hwnd, x, y, cx, cy, repaint );
313 return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
317 /***********************************************************************
318 * ShowWindow (USER.42)
320 BOOL ShowWindow( HWND hwnd, int cmd )
322 WND * wndPtr = WIN_FindWndPtr( hwnd );
323 BOOL wasVisible;
324 POINT maxSize;
325 int swpflags = 0;
326 short x = 0, y = 0, cx = 0, cy = 0;
328 if (!wndPtr) return FALSE;
330 dprintf_win(stddeb,"ShowWindow: hwnd=%04X, cmd=%d\n", hwnd, cmd);
332 wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
334 switch(cmd)
336 case SW_HIDE:
337 swpflags |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
338 SWP_NOACTIVATE | SWP_NOZORDER;
339 break;
341 case SW_SHOWMINNOACTIVE:
342 swpflags |= SWP_NOACTIVATE | SWP_NOZORDER;
343 /* fall through */
344 case SW_SHOWMINIMIZED:
345 swpflags |= SWP_SHOWWINDOW;
346 /* fall through */
347 case SW_MINIMIZE:
348 swpflags |= SWP_FRAMECHANGED;
349 if (!(wndPtr->dwStyle & WS_MINIMIZE))
351 if (wndPtr->dwStyle & WS_MAXIMIZE)
353 wndPtr->flags |= WIN_RESTORE_MAX;
354 wndPtr->dwStyle &= ~WS_MAXIMIZE;
356 else
358 wndPtr->flags &= ~WIN_RESTORE_MAX;
359 wndPtr->rectNormal = wndPtr->rectWindow;
361 wndPtr->dwStyle |= WS_MINIMIZE;
362 WINPOS_FindIconPos( hwnd );
363 x = wndPtr->ptIconPos.x;
364 y = wndPtr->ptIconPos.y;
365 cx = SYSMETRICS_CXICON;
366 cy = SYSMETRICS_CYICON;
368 else swpflags |= SWP_NOSIZE | SWP_NOMOVE;
369 break;
371 case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE: */
372 swpflags |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
373 if (!(wndPtr->dwStyle & WS_MAXIMIZE))
375 /* Store the current position and find the maximized size */
376 if (!(wndPtr->dwStyle & WS_MINIMIZE))
377 wndPtr->rectNormal = wndPtr->rectWindow;
378 NC_GetMinMaxInfo( hwnd, &maxSize,
379 &wndPtr->ptMaxPos, NULL, NULL );
380 x = wndPtr->ptMaxPos.x;
381 y = wndPtr->ptMaxPos.y;
382 cx = maxSize.x;
383 cy = maxSize.y;
384 wndPtr->dwStyle &= ~WS_MINIMIZE;
385 wndPtr->dwStyle |= WS_MAXIMIZE;
387 else swpflags |= SWP_NOSIZE | SWP_NOMOVE;
388 break;
390 case SW_SHOWNA:
391 swpflags |= SWP_NOACTIVATE | SWP_NOZORDER;
392 /* fall through */
393 case SW_SHOW:
394 swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
395 break;
397 case SW_SHOWNOACTIVATE:
398 swpflags |= SWP_NOZORDER;
399 if (GetActiveWindow()) swpflags |= SWP_NOACTIVATE;
400 /* fall through */
401 case SW_SHOWNORMAL: /* same as SW_NORMAL: */
402 case SW_RESTORE:
403 swpflags |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
404 if (wndPtr->dwStyle & WS_MINIMIZE)
406 wndPtr->ptIconPos.x = wndPtr->rectWindow.left;
407 wndPtr->ptIconPos.y = wndPtr->rectWindow.top;
408 wndPtr->dwStyle &= ~WS_MINIMIZE;
409 if (wndPtr->flags & WIN_RESTORE_MAX)
411 /* Restore to maximized position */
412 NC_GetMinMaxInfo( hwnd, &maxSize, &wndPtr->ptMaxPos,
413 NULL, NULL );
414 x = wndPtr->ptMaxPos.x;
415 y = wndPtr->ptMaxPos.y;
416 cx = maxSize.x;
417 cy = maxSize.y;
418 wndPtr->dwStyle |= WS_MAXIMIZE;
420 else /* Restore to normal position */
422 x = wndPtr->rectNormal.left;
423 y = wndPtr->rectNormal.top;
424 cx = wndPtr->rectNormal.right - wndPtr->rectNormal.left;
425 cy = wndPtr->rectNormal.bottom - wndPtr->rectNormal.top;
428 else if (wndPtr->dwStyle & WS_MAXIMIZE)
430 wndPtr->ptMaxPos.x = wndPtr->rectWindow.left;
431 wndPtr->ptMaxPos.y = wndPtr->rectWindow.top;
432 wndPtr->dwStyle &= ~WS_MAXIMIZE;
433 x = wndPtr->rectNormal.left;
434 y = wndPtr->rectNormal.top;
435 cx = wndPtr->rectNormal.right - wndPtr->rectNormal.left;
436 cy = wndPtr->rectNormal.bottom - wndPtr->rectNormal.top;
438 else swpflags |= SWP_NOSIZE | SWP_NOMOVE;
439 break;
442 SendMessage( hwnd, WM_SHOWWINDOW, (cmd != SW_HIDE), 0 );
443 SetWindowPos( hwnd, HWND_TOP, x, y, cx, cy, swpflags );
445 /* Send WM_SIZE and WM_MOVE messages if not already done */
446 if (!(wndPtr->flags & WIN_GOT_SIZEMSG))
448 int wParam = SIZE_RESTORED;
449 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
450 else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
451 wndPtr->flags |= WIN_GOT_SIZEMSG;
452 SendMessage( hwnd, WM_SIZE, wParam,
453 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
454 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
455 SendMessage( hwnd, WM_MOVE, 0,
456 MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
459 return wasVisible;
463 /***********************************************************************
464 * GetInternalWindowPos (USER.460)
466 WORD GetInternalWindowPos( HWND hwnd, LPRECT rectWnd, LPPOINT ptIcon )
468 WINDOWPLACEMENT wndpl;
469 if (!GetWindowPlacement( hwnd, &wndpl )) return 0;
470 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
471 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
472 return wndpl.showCmd;
476 /***********************************************************************
477 * SetInternalWindowPos (USER.461)
479 void SetInternalWindowPos( HWND hwnd, WORD showCmd, LPRECT rect, LPPOINT pt )
481 WINDOWPLACEMENT wndpl;
482 WND *wndPtr = WIN_FindWndPtr( hwnd );
484 wndpl.length = sizeof(wndpl);
485 wndpl.flags = (pt != NULL) ? WPF_SETMINPOSITION : 0;
486 wndpl.showCmd = showCmd;
487 if (pt) wndpl.ptMinPosition = *pt;
488 wndpl.rcNormalPosition = (rect != NULL) ? *rect : wndPtr->rectNormal;
489 wndpl.ptMaxPosition = wndPtr->ptMaxPos;
490 SetWindowPlacement( hwnd, &wndpl );
494 /***********************************************************************
495 * GetWindowPlacement (USER.370)
497 BOOL GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
499 WND *wndPtr = WIN_FindWndPtr( hwnd );
500 if (!wndPtr) return FALSE;
502 wndpl->length = sizeof(*wndpl);
503 wndpl->flags = 0;
504 wndpl->showCmd = IsZoomed(hwnd) ? SW_SHOWMAXIMIZED :
505 (IsIconic(hwnd) ? SW_SHOWMINIMIZED : SW_SHOWNORMAL);
506 wndpl->ptMinPosition = wndPtr->ptIconPos;
507 wndpl->ptMaxPosition = wndPtr->ptMaxPos;
508 wndpl->rcNormalPosition = wndPtr->rectNormal;
509 return TRUE;
513 /***********************************************************************
514 * SetWindowPlacement (USER.371)
516 BOOL SetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
518 WND *wndPtr = WIN_FindWndPtr( hwnd );
519 if (!wndPtr) return FALSE;
521 if (wndpl->flags & WPF_SETMINPOSITION)
522 wndPtr->ptIconPos = wndpl->ptMinPosition;
523 if ((wndpl->flags & WPF_RESTORETOMAXIMIZED) &&
524 (wndpl->showCmd == SW_SHOWMINIMIZED)) wndPtr->flags |= WIN_RESTORE_MAX;
525 wndPtr->ptMaxPos = wndpl->ptMaxPosition;
526 wndPtr->rectNormal = wndpl->rcNormalPosition;
527 ShowWindow( hwnd, wndpl->showCmd );
528 return TRUE;
532 /*******************************************************************
533 * WINPOS_NextWindowFromPoint
535 * Looks for next enabled window that is
536 * a) sibling of hwnd, later in Z-order and encloses pt, or
537 * b) parent of hwnd
539 HWND WINPOS_NextWindowFromPoint( HWND hwnd, POINT pt )
541 WND *wndPtr = WIN_FindWndPtr( hwnd );
543 if (!wndPtr->hwndParent) return hwnd; /* desktop window */
544 ScreenToClient( wndPtr->hwndParent, &pt ); /* make pt relative to parent */
545 for (;;)
547 if (!wndPtr->hwndNext) break; /* No more children */
548 hwnd = wndPtr->hwndNext;
549 wndPtr = WIN_FindWndPtr( hwnd );
550 if ((wndPtr->dwStyle & WS_VISIBLE) &&
551 !(wndPtr->dwStyle & WS_DISABLED) &&
552 PtInRect( &wndPtr->rectWindow, pt )) return hwnd;
554 return wndPtr->hwndParent;
558 /*******************************************************************
559 * WINPOS_ChangeActiveWindow
561 * Change the active window and send the corresponding messages.
563 HWND WINPOS_ChangeActiveWindow( HWND hwnd, BOOL mouseMsg )
565 HWND prevActive = hwndActive;
566 if (hwnd == hwndActive) return 0;
567 if (hwndActive)
569 if (!SendMessage( hwndActive, WM_NCACTIVATE, FALSE, 0 )) return 0;
570 SendMessage( hwndActive, WM_ACTIVATE, WA_INACTIVE,
571 MAKELONG( IsIconic(hwndActive), hwnd ) );
572 /* Send WM_ACTIVATEAPP here */
575 hwndActive = hwnd;
576 if (hwndActive)
578 WND *wndPtr = WIN_FindWndPtr( hwndActive );
579 wndPtr->hwndPrevActive = prevActive;
581 /* Send WM_ACTIVATEAPP here */
582 SendMessage( hwnd, WM_NCACTIVATE, TRUE, 0 );
583 SendMessage( hwnd, WM_ACTIVATE, mouseMsg ? WA_CLICKACTIVE : WA_ACTIVE,
584 MAKELONG( IsIconic(hwnd), prevActive ) );
586 return prevActive;
590 /***********************************************************************
591 * WINPOS_SendNCCalcSize
593 * Send a WM_NCCALCSIZE message to a window.
594 * All parameters are read-only except newClientRect.
595 * oldWindowRect, oldClientRect and winpos must be non-NULL only
596 * when calcValidRect is TRUE.
598 LONG WINPOS_SendNCCalcSize( HWND hwnd, BOOL calcValidRect, RECT *newWindowRect,
599 RECT *oldWindowRect, RECT *oldClientRect,
600 WINDOWPOS *winpos, RECT *newClientRect )
602 NCCALCSIZE_PARAMS *params;
603 HANDLE hparams;
604 LONG result;
606 if (!(hparams = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(*params) )))
607 return 0;
608 params = (NCCALCSIZE_PARAMS *) USER_HEAP_ADDR( hparams );
609 params->rgrc[0] = *newWindowRect;
610 if (calcValidRect)
612 params->rgrc[1] = *oldWindowRect;
613 params->rgrc[2] = *oldClientRect;
614 params->lppos = winpos;
616 result = SendMessage( hwnd, WM_NCCALCSIZE, calcValidRect, (LONG)params);
617 *newClientRect = params->rgrc[0];
618 USER_HEAP_FREE( hparams );
619 return result;
623 /***********************************************************************
624 * WINPOS_HandleWindowPosChanging
626 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
628 LONG WINPOS_HandleWindowPosChanging( WINDOWPOS *winpos )
630 POINT maxSize;
631 WND *wndPtr = WIN_FindWndPtr( winpos->hwnd );
632 if (!wndPtr || (winpos->flags & SWP_NOSIZE)) return 0;
633 if ((wndPtr->dwStyle & WS_THICKFRAME) ||
634 (wndPtr->dwStyle & (WS_POPUP | WS_CHILD) == 0))
636 NC_GetMinMaxInfo( winpos->hwnd, &maxSize, NULL, NULL, NULL );
637 winpos->cx = min( winpos->cx, maxSize.x );
638 winpos->cy = min( winpos->cy, maxSize.y );
640 return 0;
644 /***********************************************************************
645 * WINPOS_MoveWindowZOrder
647 * Move a window in Z order, invalidating everything that needs it.
648 * Only necessary for windows without associated X window.
650 static void WINPOS_MoveWindowZOrder( HWND hwnd, HWND hwndAfter )
652 BOOL movingUp;
653 HWND hwndCur;
654 WND *wndPtr = WIN_FindWndPtr( hwnd );
656 /* We have two possible cases:
657 * - The window is moving up: we have to invalidate all areas
658 * of the window that were covered by other windows
659 * - The window is moving down: we have to invalidate areas
660 * of other windows covered by this one.
663 if (hwndAfter == HWND_TOP)
665 movingUp = TRUE;
667 else if (hwndAfter == HWND_BOTTOM)
669 if (!wndPtr->hwndNext) return; /* Already at the bottom */
670 movingUp = FALSE;
672 else
674 if (wndPtr->hwndNext == hwndAfter) return; /* Already placed right */
676 /* Determine which window we encounter first in Z-order */
677 hwndCur = GetWindow( wndPtr->hwndParent, GW_CHILD );
678 while ((hwndCur != hwnd) && (hwndCur != hwndAfter))
679 hwndCur = GetWindow( hwndCur, GW_HWNDNEXT );
680 movingUp = (hwndCur == hwndAfter);
683 if (movingUp)
685 HWND hwndPrevAfter = wndPtr->hwndNext;
686 WIN_UnlinkWindow( hwnd );
687 WIN_LinkWindow( hwnd, hwndAfter );
688 hwndCur = wndPtr->hwndNext;
689 while (hwndCur != hwndPrevAfter)
691 WND *curPtr = WIN_FindWndPtr( hwndCur );
692 RECT rect = curPtr->rectWindow;
693 OffsetRect( &rect, -wndPtr->rectClient.left,
694 -wndPtr->rectClient.top );
695 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN |
696 RDW_FRAME | RDW_ERASE );
697 hwndCur = curPtr->hwndNext;
700 else /* Moving down */
702 hwndCur = wndPtr->hwndNext;
703 WIN_UnlinkWindow( hwnd );
704 WIN_LinkWindow( hwnd, hwndAfter );
705 while (hwndCur != hwnd)
707 WND *curPtr = WIN_FindWndPtr( hwndCur );
708 RECT rect = wndPtr->rectWindow;
709 OffsetRect( &rect, -curPtr->rectClient.left,
710 -curPtr->rectClient.top );
711 RedrawWindow( hwndCur, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN |
712 RDW_FRAME | RDW_ERASE );
713 hwndCur = curPtr->hwndNext;
719 /***********************************************************************
720 * WINPOS_SetXWindosPos
722 * SetWindowPos() for an X window. Used by the real SetWindowPos().
724 static void WINPOS_SetXWindowPos( WINDOWPOS *winpos )
726 XWindowChanges winChanges;
727 int changeMask = 0;
728 WND *wndPtr = WIN_FindWndPtr( winpos->hwnd );
730 if (!(winpos->flags & SWP_NOSIZE))
732 winChanges.width = winpos->cx;
733 winChanges.height = winpos->cy;
734 changeMask |= CWWidth | CWHeight;
736 if (!(winpos->flags & SWP_NOMOVE))
738 winChanges.x = winpos->x;
739 winChanges.y = winpos->y;
740 changeMask |= CWX | CWY;
742 if (!(winpos->flags & SWP_NOZORDER))
744 if (winpos->hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
745 else winChanges.stack_mode = Below;
746 if ((winpos->hwndInsertAfter != HWND_TOP) &&
747 (winpos->hwndInsertAfter != HWND_BOTTOM))
749 WND * insertPtr = WIN_FindWndPtr( winpos->hwndInsertAfter );
750 winChanges.sibling = insertPtr->window;
751 changeMask |= CWSibling;
753 changeMask |= CWStackMode;
755 if (changeMask)
756 XConfigureWindow( display, wndPtr->window, changeMask, &winChanges );
760 /***********************************************************************
761 * WINPOS_InternalSetWindowPos
763 * Helper function for SetWindowPos.
765 static BOOL WINPOS_InternalSetWindowPos( WINDOWPOS *winpos )
767 HWND hwndAfter;
768 WND *wndPtr;
769 RECT newWindowRect, newClientRect;
770 int flags, result;
772 /* Send WM_WINDOWPOSCHANGING message */
774 if (!(winpos->flags & SWP_NOSENDCHANGING))
775 SendMessage( winpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LONG)winpos );
777 /* Check window handle */
779 if (winpos->hwnd == GetDesktopWindow()) return FALSE;
780 if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
782 /* Check dimensions */
784 if (winpos->cx <= 0) winpos->cx = 1;
785 if (winpos->cy <= 0) winpos->cy = 1;
787 /* Check flags */
789 if (winpos->hwnd == hwndActive)
790 winpos->flags |= SWP_NOACTIVATE; /* Already active */
791 if ((wndPtr->rectWindow.right-wndPtr->rectWindow.left == winpos->cx) &&
792 (wndPtr->rectWindow.bottom-wndPtr->rectWindow.top == winpos->cy))
793 winpos->flags |= SWP_NOSIZE; /* Already the right size */
794 if ((wndPtr->rectWindow.left == winpos->x) &&
795 (wndPtr->rectWindow.top == winpos->y))
796 winpos->flags |= SWP_NOMOVE; /* Already the right position */
797 flags = winpos->flags;
799 /* Check hwndAfter */
801 hwndAfter = winpos->hwndInsertAfter;
802 if (!(winpos->flags & (SWP_NOZORDER | SWP_NOACTIVATE)))
804 /* Ignore TOPMOST flags when activating a window */
805 /* _and_ moving it in Z order. */
806 if ((hwndAfter == HWND_TOPMOST) || (hwndAfter == HWND_NOTOPMOST))
807 hwndAfter = HWND_TOP;
809 /* TOPMOST not supported yet */
810 if ((hwndAfter == HWND_TOPMOST) || (hwndAfter == HWND_NOTOPMOST))
811 hwndAfter = HWND_TOP;
812 /* hwndAfter must be a sibling of the window */
813 if ((hwndAfter != HWND_TOP) && (hwndAfter != HWND_BOTTOM) &&
814 (GetParent(winpos->hwnd) != GetParent(hwndAfter))) return FALSE;
815 winpos->hwndInsertAfter = hwndAfter;
817 /* Calculate new position and size */
819 newWindowRect = wndPtr->rectWindow;
820 newClientRect = wndPtr->rectClient;
822 if (!(winpos->flags & SWP_NOSIZE))
824 newWindowRect.right = newWindowRect.left + winpos->cx;
825 newWindowRect.bottom = newWindowRect.top + winpos->cy;
827 if (!(winpos->flags & SWP_NOMOVE))
829 newWindowRect.left = winpos->x;
830 newWindowRect.top = winpos->y;
831 newWindowRect.right += winpos->x - wndPtr->rectWindow.left;
832 newWindowRect.bottom += winpos->y - wndPtr->rectWindow.top;
835 /* Reposition window in Z order */
837 if (!(winpos->flags & SWP_NOZORDER))
839 if (wndPtr->window)
841 WIN_UnlinkWindow( winpos->hwnd );
842 WIN_LinkWindow( winpos->hwnd, hwndAfter );
844 else WINPOS_MoveWindowZOrder( winpos->hwnd, hwndAfter );
847 /* Send WM_NCCALCSIZE message to get new client area */
849 result = WINPOS_SendNCCalcSize( winpos->hwnd, TRUE, &newWindowRect,
850 &wndPtr->rectWindow, &wndPtr->rectClient,
851 winpos, &newClientRect );
852 /* .... Should handle result here */
854 /* Perform the moving and resizing */
856 if (wndPtr->window)
858 WINPOS_SetXWindowPos( winpos );
859 wndPtr->rectWindow = newWindowRect;
860 wndPtr->rectClient = newClientRect;
862 else
864 RECT oldWindowRect = wndPtr->rectWindow;
866 wndPtr->rectWindow = newWindowRect;
867 wndPtr->rectClient = newClientRect;
869 if (!(flags & SWP_NOREDRAW) &&
870 (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE) ||
871 !(flags & SWP_NOZORDER)))
873 HRGN hrgn1 = CreateRectRgnIndirect( &oldWindowRect );
874 HRGN hrgn2 = CreateRectRgnIndirect( &wndPtr->rectWindow );
875 HRGN hrgn3 = CreateRectRgn( 0, 0, 0, 0 );
876 CombineRgn( hrgn3, hrgn1, hrgn2, RGN_DIFF );
877 RedrawWindow( wndPtr->hwndParent, NULL, hrgn3,
878 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE );
879 if ((oldWindowRect.left != wndPtr->rectWindow.left) ||
880 (oldWindowRect.top != wndPtr->rectWindow.top))
882 RedrawWindow( winpos->hwnd, NULL, 0, RDW_INVALIDATE |
883 RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE );
885 DeleteObject( hrgn1 );
886 DeleteObject( hrgn2 );
887 DeleteObject( hrgn3 );
891 if (flags & SWP_SHOWWINDOW)
893 wndPtr->dwStyle |= WS_VISIBLE;
894 if (wndPtr->window)
896 XMapWindow( display, wndPtr->window );
898 else
900 if (!(flags & SWP_NOREDRAW))
901 RedrawWindow( winpos->hwnd, NULL, 0,
902 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
905 else if (flags & SWP_HIDEWINDOW)
907 wndPtr->dwStyle &= ~WS_VISIBLE;
908 if (wndPtr->window)
910 XUnmapWindow( display, wndPtr->window );
912 else
914 if (!(flags & SWP_NOREDRAW))
915 RedrawWindow( wndPtr->hwndParent, &wndPtr->rectWindow, 0,
916 RDW_INVALIDATE | RDW_FRAME |
917 RDW_ALLCHILDREN | RDW_ERASE );
919 if ((winpos->hwnd == GetFocus()) || IsChild(winpos->hwnd, GetFocus()))
920 SetFocus( GetParent(winpos->hwnd) ); /* Revert focus to parent */
921 if (winpos->hwnd == hwndActive)
923 /* Activate previously active window if possible */
924 HWND newActive = wndPtr->hwndPrevActive;
925 if (!IsWindow(newActive) || (newActive == winpos->hwnd))
927 newActive = GetTopWindow(GetDesktopWindow());
928 if (newActive == winpos->hwnd) newActive = wndPtr->hwndNext;
930 WINPOS_ChangeActiveWindow( newActive, FALSE );
934 /* Activate the window */
936 if (!(flags & SWP_NOACTIVATE))
938 if (!(wndPtr->dwStyle & WS_CHILD))
939 WINPOS_ChangeActiveWindow( winpos->hwnd, FALSE );
942 /* Repaint the window */
944 if (wndPtr->window) MSG_Synchronize(); /* Wait for all expose events */
945 if ((flags & SWP_FRAMECHANGED) && !(flags & SWP_NOREDRAW))
946 RedrawWindow( winpos->hwnd, NULL, 0,
947 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
948 if (!(flags & SWP_DEFERERASE))
949 RedrawWindow( wndPtr->hwndParent, NULL, 0,
950 RDW_ALLCHILDREN | RDW_ERASENOW );
952 /* And last, send the WM_WINDOWPOSCHANGED message */
954 if (!(winpos->flags & SWP_NOSENDCHANGING))
955 SendMessage( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LONG)winpos );
956 return TRUE;
960 /***********************************************************************
961 * BeginDeferWindowPos (USER.259)
963 HDWP BeginDeferWindowPos( INT count )
965 HDWP handle;
966 DWP *pDWP;
968 if (count <= 0) return 0;
969 handle = USER_HEAP_ALLOC( GMEM_MOVEABLE,
970 sizeof(DWP) + (count-1)*sizeof(WINDOWPOS) );
971 if (!handle) return 0;
972 pDWP = (DWP *) USER_HEAP_ADDR( handle );
973 pDWP->actualCount = 0;
974 pDWP->suggestedCount = count;
975 pDWP->valid = TRUE;
976 pDWP->wMagic = DWP_MAGIC;
977 pDWP->hwndParent = 0;
978 return handle;
982 /***********************************************************************
983 * DeferWindowPos (USER.260)
985 HDWP DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter, INT x, INT y,
986 INT cx, INT cy, WORD flags )
988 DWP *pDWP;
989 int i;
990 HDWP newhdwp = hdwp;
992 pDWP = (DWP *) USER_HEAP_ADDR( hdwp );
993 if (!pDWP) return 0;
995 /* All the windows of a DeferWindowPos() must have the same parent */
997 if (pDWP->actualCount == 0) pDWP->hwndParent = GetParent( hwnd );
998 else if (GetParent( hwnd ) != pDWP->hwndParent)
1000 USER_HEAP_FREE( hdwp );
1001 return 0;
1004 for (i = 0; i < pDWP->actualCount; i++)
1006 if (pDWP->winPos[i].hwnd == hwnd)
1008 /* Merge with the other changes */
1009 if (!(flags & SWP_NOZORDER))
1011 pDWP->winPos[i].hwndInsertAfter = hwndAfter;
1013 if (!(flags & SWP_NOMOVE))
1015 pDWP->winPos[i].x = x;
1016 pDWP->winPos[i].y = y;
1018 if (!(flags & SWP_NOSIZE))
1020 pDWP->winPos[i].cx = cx;
1021 pDWP->winPos[i].cy = cy;
1023 pDWP->winPos[i].flags &= flags & (SWP_NOSIZE | SWP_NOMOVE |
1024 SWP_NOZORDER | SWP_NOREDRAW |
1025 SWP_NOACTIVATE | SWP_NOCOPYBITS |
1026 SWP_NOOWNERZORDER);
1027 pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
1028 SWP_FRAMECHANGED);
1029 return hdwp;
1032 if (pDWP->actualCount >= pDWP->suggestedCount)
1034 newhdwp = USER_HEAP_REALLOC( hdwp,
1035 sizeof(DWP) + pDWP->suggestedCount*sizeof(WINDOWPOS), 0);
1036 if (!newhdwp) return 0;
1037 pDWP = (DWP *) USER_HEAP_ADDR( newhdwp );
1038 pDWP->suggestedCount++;
1040 pDWP->winPos[pDWP->actualCount].hwnd = hwnd;
1041 pDWP->winPos[pDWP->actualCount].hwndInsertAfter = hwndAfter;
1042 pDWP->winPos[pDWP->actualCount].x = x;
1043 pDWP->winPos[pDWP->actualCount].y = y;
1044 pDWP->winPos[pDWP->actualCount].cx = cx;
1045 pDWP->winPos[pDWP->actualCount].cy = cy;
1046 pDWP->winPos[pDWP->actualCount].flags = flags;
1047 pDWP->actualCount++;
1048 return newhdwp;
1052 /***********************************************************************
1053 * EndDeferWindowPos (USER.261)
1055 BOOL EndDeferWindowPos( HDWP hdwp )
1057 DWP *pDWP;
1058 BOOL res = TRUE;
1059 int i;
1061 pDWP = (DWP *) USER_HEAP_ADDR( hdwp );
1062 if (!pDWP) return FALSE;
1063 for (i = 0; i < pDWP->actualCount; i++)
1065 if (!(res = WINPOS_InternalSetWindowPos( &pDWP->winPos[i] ))) break;
1067 USER_HEAP_FREE( hdwp );
1068 return res;
1072 /***********************************************************************
1073 * SetWindowPos (USER.232)
1075 BOOL SetWindowPos( HWND hwnd, HWND hwndInsertAfter, INT x, INT y,
1076 INT cx, INT cy, WORD flags )
1078 HDWP hdwp;
1080 dprintf_win(stddeb, "SetWindowPos: %04X %d %d,%d %dx%d 0x%x\n",
1081 hwnd, hwndInsertAfter, x, y, cx, cy, flags );
1082 if (!(hdwp = BeginDeferWindowPos( 1 ))) return FALSE;
1083 if (!(hdwp = DeferWindowPos( hdwp, hwnd, hwndInsertAfter,
1084 x, y, cx, cy, flags ))) return FALSE;
1085 return EndDeferWindowPos( hdwp );
1088 /***********************************************************************
1089 * TileChildWindows (USER.199)
1091 void TileChildWindows( HWND parent, WORD action )
1093 printf("STUB TileChildWindows(%04X, %d)\n", parent, action);
1096 /***********************************************************************
1097 * CascageChildWindows (USER.198)
1099 void CascadeChildWindows( HWND parent, WORD action )
1101 printf("STUB CascadeChildWindows(%04X, %d)\n", parent, action);