Release 940201
[wine] / windows / winpos.c
1 /*
2  * Window position related functions.
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
8
9 #include "sysmetrics.h"
10 #include "user.h"
11 #include "win.h"
12
13 extern Display * display;
14
15 static HWND hwndActive = 0;  /* Currently active window */
16
17
18 /***********************************************************************
19  *           GetWindowRect   (USER.32)
20  */
21 void GetWindowRect( HWND hwnd, LPRECT rect ) 
22 {
23     WND * wndPtr = WIN_FindWndPtr( hwnd ); 
24     if (!wndPtr) return;
25     
26     *rect = wndPtr->rectWindow;
27     if (wndPtr->hwndParent)
28         MapWindowPoints( wndPtr->hwndParent, 0, (POINT *)rect, 2 );
29 }
30
31
32 /***********************************************************************
33  *           GetClientRect   (USER.33)
34  */
35 void GetClientRect( HWND hwnd, LPRECT rect ) 
36 {
37     WND * wndPtr = WIN_FindWndPtr( hwnd );
38
39     rect->left = rect->top = rect->right = rect->bottom = 0;
40     if (wndPtr) 
41     {
42         rect->right  = wndPtr->rectClient.right - wndPtr->rectClient.left;
43         rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
44     }
45 }
46
47
48 /*******************************************************************
49  *         ClientToScreen   (USER.28)
50  */
51 void ClientToScreen( HWND hwnd, LPPOINT lppnt )
52 {
53     MapWindowPoints( hwnd, 0, lppnt, 1 );
54 }
55
56
57 /*******************************************************************
58  *         ScreenToClient   (USER.29)
59  */
60 void ScreenToClient( HWND hwnd, LPPOINT lppnt )
61 {
62     MapWindowPoints( 0, hwnd, lppnt, 1 );
63 }
64
65
66 /*******************************************************************
67  *         WindowFromPoint   (USER.30)
68  */
69 HWND WindowFromPoint( POINT pt )
70 {
71     RECT rect;
72     HWND hwnd = firstWindow;
73     while (hwnd)
74     {
75         GetWindowRect( hwnd, &rect );
76         if (PtInRect( &rect, pt )) return hwnd;
77         hwnd = GetWindow( hwnd, GW_HWNDNEXT );
78     }
79     return 0;
80 }
81
82
83 /*******************************************************************
84  *         ChildWindowFromPoint   (USER.191)
85  */
86 HWND ChildWindowFromPoint( HWND hwndParent, POINT pt )
87 {
88     RECT rect;
89     HWND hwnd;
90     
91     GetWindowRect( hwndParent, &rect );
92     if (!PtInRect( &rect, pt )) return 0;
93     hwnd = GetTopWindow( hwndParent );
94     while (hwnd)
95     {
96         GetWindowRect( hwnd, &rect );
97         if (PtInRect( &rect, pt )) return hwnd;
98         hwnd = GetWindow( hwnd, GW_HWNDNEXT );
99     }
100     return 0;
101 }
102
103
104 /*******************************************************************
105  *         MapWindowPoints   (USER.258)
106  */
107 void MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, WORD count )
108 {
109     WND * wndPtr;
110     POINT * curpt;
111     POINT origin = { 0, 0 };
112     WORD i;
113
114       /* Translate source window origin to screen coords */
115     while(hwndFrom)
116     {
117         wndPtr = WIN_FindWndPtr( hwndFrom );
118         origin.x += wndPtr->rectClient.left;
119         origin.y += wndPtr->rectClient.top;
120         hwndFrom = wndPtr->hwndParent;
121     }
122
123       /* Translate origin to destination window coords */
124     while(hwndTo)
125     {
126         wndPtr = WIN_FindWndPtr( hwndTo );
127         origin.x -= wndPtr->rectClient.left;
128         origin.y -= wndPtr->rectClient.top;
129         hwndTo = wndPtr->hwndParent;
130     }    
131
132       /* Translate points */
133     for (i = 0, curpt = lppt; i < count; i++, curpt++)
134     {
135         curpt->x += origin.x;
136         curpt->y += origin.y;
137     }
138 }
139
140
141 /***********************************************************************
142  *           IsIconic   (USER.31)
143  */
144 BOOL IsIconic(HWND hWnd)
145 {
146     WND * wndPtr = WIN_FindWndPtr(hWnd);
147     if (wndPtr == NULL) return FALSE;
148     return (wndPtr->dwStyle & WS_MINIMIZE) != 0;
149 }
150  
151  
152 /***********************************************************************
153  *           IsZoomed   (USER.272)
154  */
155 BOOL IsZoomed(HWND hWnd)
156 {
157     WND * wndPtr = WIN_FindWndPtr(hWnd);
158     if (wndPtr == NULL) return FALSE;
159     return (wndPtr->dwStyle & WS_MAXIMIZE) != 0;
160 }
161
162
163 /*******************************************************************
164  *         GetActiveWindow    (USER.60)
165  */
166 HWND GetActiveWindow()
167 {
168     return hwndActive;
169 }
170
171
172 /*******************************************************************
173  *         SetActiveWindow    (USER.59)
174  */
175 HWND SetActiveWindow( HWND hwnd )
176 {
177     HWND prev = hwndActive;
178     WND *wndPtr = WIN_FindWndPtr( hwnd );
179     if (!wndPtr || (wndPtr->dwStyle & WS_CHILD)) return 0;
180     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
181     return prev;
182 }
183
184
185 /***********************************************************************
186  *           BringWindowToTop   (USER.45)
187  */
188 BOOL BringWindowToTop( HWND hwnd )
189 {
190     return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
191 }
192
193
194 /***********************************************************************
195  *           MoveWindow   (USER.56)
196  */
197 BOOL MoveWindow( HWND hwnd, short x, short y, short cx, short cy, BOOL repaint)
198 {    
199     int flags = SWP_NOZORDER | SWP_NOACTIVATE;
200     if (!repaint) flags |= SWP_NOREDRAW;
201 #ifdef DEBUG_WIN    
202     printf( "MoveWindow: %d %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint );
203 #endif
204     return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
205 }
206
207
208 /***********************************************************************
209  *           ShowWindow   (USER.42)
210  */
211 BOOL ShowWindow( HWND hwnd, int cmd ) 
212 {    
213     WND * wndPtr = WIN_FindWndPtr( hwnd );
214     BOOL wasVisible;
215     int swpflags = 0;
216
217 #ifdef DEBUG_WIN
218     printf("ShowWindow: hwnd=%d, cmd=%d\n", hwnd, cmd);
219 #endif
220     
221     if (!wndPtr) return FALSE;
222     wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
223     switch(cmd)
224     {
225         case SW_HIDE:
226             if (!wasVisible) return FALSE;  /* Nothing to do */
227             swpflags |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | 
228                         SWP_NOACTIVATE | SWP_NOZORDER;
229             break;
230
231         case SW_SHOWMINNOACTIVE:
232         case SW_SHOWMINIMIZED:
233         case SW_SHOWMAXIMIZED:
234         case SW_MINIMIZE:
235             wndPtr->dwStyle |= WS_MINIMIZE;
236             swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | 
237                         SWP_NOACTIVATE | SWP_NOZORDER;
238             break;
239
240         case SW_SHOWNA:
241         case SW_MAXIMIZE:
242         case SW_SHOW:
243             swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
244             break;
245
246         case SW_NORMAL:
247         case SW_SHOWNORMAL:
248         case SW_SHOWNOACTIVATE:
249         case SW_RESTORE:
250             wndPtr->dwStyle &= ~WS_MINIMIZE;
251             wndPtr->dwStyle &= ~WS_MAXIMIZE;
252             swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
253             if (cmd == SW_SHOWNOACTIVATE)
254             {
255                 swpflags |= SWP_NOZORDER;
256                 if (GetActiveWindow()) swpflags |= SWP_NOACTIVATE;
257             }
258             break;
259     }
260     SendMessage( hwnd, WM_SHOWWINDOW, (cmd != SW_HIDE), 0 );
261     SetWindowPos( hwnd, 0, 0, 0, 0, 0, swpflags );
262
263       /* Send WM_SIZE and WM_MOVE messages if not already done */
264     if (!(wndPtr->flags & WIN_GOT_SIZEMSG))
265     {
266         int wParam = SIZE_RESTORED;
267         if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
268         else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
269         wndPtr->flags |= WIN_GOT_SIZEMSG;
270         SendMessage( hwnd, WM_SIZE, wParam,
271                      MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
272                             wndPtr->rectClient.bottom-wndPtr->rectClient.top));
273         SendMessage( hwnd, WM_MOVE, 0,
274                    MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
275     }
276     return wasVisible;
277 }
278
279
280 /***********************************************************************
281  *           GetInternalWindowPos   (USER.460)
282  */
283 WORD GetInternalWindowPos( HWND hwnd, LPRECT rectWnd, LPPOINT ptIcon )
284 {
285     WINDOWPLACEMENT wndpl;
286     if (!GetWindowPlacement( hwnd, &wndpl )) return 0;
287     if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
288     if (ptIcon)  *ptIcon = wndpl.ptMinPosition;
289     return wndpl.showCmd;
290 }
291
292
293 /***********************************************************************
294  *           SetInternalWindowPos   (USER.461)
295  */
296 void SetInternalWindowPos( HWND hwnd, WORD showCmd, LPRECT rect, LPPOINT pt )
297 {
298     WINDOWPLACEMENT wndpl;
299     WND *wndPtr = WIN_FindWndPtr( hwnd );
300
301     wndpl.length  = sizeof(wndpl);
302     wndpl.flags   = (pt != NULL) ? WPF_SETMINPOSITION : 0;
303     wndpl.showCmd = showCmd;
304     if (pt) wndpl.ptMinPosition = *pt;
305     wndpl.rcNormalPosition = (rect != NULL) ? *rect : wndPtr->rectNormal;
306     wndpl.ptMaxPosition = wndPtr->ptMaxPos;
307     SetWindowPlacement( hwnd, &wndpl );
308 }
309
310
311 /***********************************************************************
312  *           GetWindowPlacement   (USER.370)
313  */
314 BOOL GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
315 {
316     WND *wndPtr = WIN_FindWndPtr( hwnd );
317     if (!wndPtr) return FALSE;
318
319     wndpl->length  = sizeof(*wndpl);
320     wndpl->flags   = 0;
321     wndpl->showCmd = IsZoomed(hwnd) ? SW_SHOWMAXIMIZED : 
322                      (IsIconic(hwnd) ? SW_SHOWMINIMIZED : SW_SHOWNORMAL);
323     wndpl->ptMinPosition = wndPtr->ptIconPos;
324     wndpl->ptMaxPosition = wndPtr->ptMaxPos;
325     wndpl->rcNormalPosition = wndPtr->rectNormal;
326     return TRUE;
327 }
328
329
330 /***********************************************************************
331  *           SetWindowPlacement   (USER.371)
332  */
333 BOOL SetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
334 {
335     WND *wndPtr = WIN_FindWndPtr( hwnd );
336     if (!wndPtr) return FALSE;
337
338     if (wndpl->flags & WPF_SETMINPOSITION)
339         wndPtr->ptIconPos = wndpl->ptMinPosition;
340     if ((wndpl->flags & WPF_RESTORETOMAXIMIZED) &&
341         (wndpl->showCmd == SW_SHOWMINIMIZED)) wndPtr->flags |= WIN_RESTORE_MAX;
342     wndPtr->ptMaxPos   = wndpl->ptMaxPosition;
343     wndPtr->rectNormal = wndpl->rcNormalPosition;
344     ShowWindow( hwnd, wndpl->showCmd );
345     return TRUE;
346 }
347
348
349 /*******************************************************************
350  *         WINPOS_GetMinMaxInfo
351  *
352  * Send a WM_GETMINMAXINFO to the window.
353  */
354 void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos,
355                            POINT *minTrack, POINT *maxTrack )
356 {
357     HANDLE minmaxHandle;
358     MINMAXINFO MinMax, *pMinMax;
359     WND *wndPtr = WIN_FindWndPtr( hwnd );
360
361     MinMax.ptMaxSize.x = SYSMETRICS_CXSCREEN;
362     MinMax.ptMaxSize.y = SYSMETRICS_CYSCREEN;
363     MinMax.ptMaxPosition = wndPtr->ptMaxPos;
364     MinMax.ptMinTrackSize.x = SYSMETRICS_CXMINTRACK;
365     MinMax.ptMinTrackSize.y = SYSMETRICS_CYMINTRACK;
366     MinMax.ptMaxTrackSize.x = SYSMETRICS_CXSCREEN;
367     MinMax.ptMaxTrackSize.y = SYSMETRICS_CYSCREEN;
368
369     minmaxHandle = USER_HEAP_ALLOC( LMEM_MOVEABLE, sizeof(MINMAXINFO) );
370     if (minmaxHandle)
371     {
372         pMinMax = (MINMAXINFO *) USER_HEAP_ADDR( minmaxHandle );
373         memcpy( pMinMax, &MinMax, sizeof(MinMax) );     
374         SendMessage( hwnd, WM_GETMINMAXINFO, 0, (LONG)pMinMax );
375     }
376     else pMinMax = &MinMax;
377
378     if (maxSize) *maxSize = pMinMax->ptMaxSize;
379     if (maxPos) *maxPos = pMinMax->ptMaxPosition;
380     if (minTrack) *minTrack = pMinMax->ptMinTrackSize;
381     if (maxTrack) *maxTrack = pMinMax->ptMaxTrackSize;
382     if (minmaxHandle) USER_HEAP_FREE( minmaxHandle );
383 }
384
385
386 /*******************************************************************
387  *         WINPOS_ChangeActiveWindow
388  *
389  * Change the active window and send the corresponding messages.
390  */
391 HWND WINPOS_ChangeActiveWindow( HWND hwnd, BOOL mouseMsg )
392 {
393     HWND prevActive = hwndActive;
394     if (hwnd == hwndActive) return 0;
395     if (hwndActive)
396     {
397         if (!SendMessage( hwndActive, WM_NCACTIVATE, FALSE, 0 )) return 0;
398         SendMessage( hwndActive, WM_ACTIVATE, WA_INACTIVE,
399                      MAKELONG( IsIconic(hwndActive), hwnd ) );
400         /* Send WM_ACTIVATEAPP here */
401     }
402
403     hwndActive = hwnd;
404     if (hwndActive)
405     {
406         /* Send WM_ACTIVATEAPP here */
407         SendMessage( hwnd, WM_NCACTIVATE, TRUE, 0 );
408         SendMessage( hwnd, WM_ACTIVATE, mouseMsg ? WA_CLICKACTIVE : WA_ACTIVE,
409                      MAKELONG( IsIconic(hwnd), prevActive ) );
410     }
411     return prevActive;
412 }
413
414
415 /***********************************************************************
416  *           SetWindowPos   (USER.232)
417  */
418 /* Unimplemented flags: SWP_NOREDRAW
419  */
420 /* Note: all this code should be in the DeferWindowPos() routines,
421  * and SetWindowPos() should simply call them.  This will be implemented
422  * some day...
423  */
424 BOOL SetWindowPos( HWND hwnd, HWND hwndInsertAfter, short x, short y,
425                    short cx, short cy, WORD flags )
426 {
427     WINDOWPOS *winPos;
428     HANDLE hmem = 0;
429     RECT newWindowRect, newClientRect;
430     WND *wndPtr;
431     int calcsize_result = 0;
432     XWindowChanges winChanges;
433     int changeMask = 0;
434
435 #ifdef DEBUG_WIN
436     printf( "SetWindowPos: %d %d %d,%d %dx%d 0x%x\n",
437             hwnd, hwndInsertAfter, x, y, cx, cy, flags );
438 #endif
439
440     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
441     if (flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW))
442         flags |= SWP_NOMOVE | SWP_NOSIZE;
443
444       /* Send WM_WINDOWPOSCHANGING message */
445
446     if (!(hmem = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(WINDOWPOS) )))
447         return FALSE;
448     winPos = (WINDOWPOS *)USER_HEAP_ADDR( hmem );
449     winPos->hwnd = hwnd;
450     winPos->hwndInsertAfter = hwndInsertAfter;
451     winPos->x = x;
452     winPos->y = y;
453     winPos->cx = cx;
454     winPos->cy = cy;
455     winPos->flags = flags;
456     SendMessage( hwnd, WM_WINDOWPOSCHANGING, 0, (LONG)winPos );
457
458       /* Calculate new position and size */
459
460     newWindowRect = wndPtr->rectWindow;
461     newClientRect = wndPtr->rectClient;
462
463     if (!(winPos->flags & SWP_NOSIZE))
464     {
465         newWindowRect.right  = newWindowRect.left + winPos->cx;
466         newWindowRect.bottom = newWindowRect.top + winPos->cy;
467     }
468
469     if (!(winPos->flags & SWP_NOMOVE))
470     {
471         newWindowRect.left    = winPos->x;
472         newWindowRect.top     = winPos->y;
473         newWindowRect.right  += winPos->x - wndPtr->rectWindow.left;
474         newWindowRect.bottom += winPos->y - wndPtr->rectWindow.top;
475     }
476
477       /* Reposition window in Z order */
478
479     if (!(winPos->flags & SWP_NOZORDER))
480     {
481         hwndInsertAfter = winPos->hwndInsertAfter;
482
483           /* TOPMOST not supported yet */
484         if ((hwndInsertAfter == HWND_TOPMOST) ||
485             (hwndInsertAfter == HWND_NOTOPMOST)) hwndInsertAfter = HWND_TOP;
486
487           /* Make sure hwndInsertAfter is a sibling of hwnd */
488         if ((hwndInsertAfter != HWND_TOP) && (hwndInsertAfter != HWND_BOTTOM))
489             if (wndPtr->hwndParent != GetParent(hwndInsertAfter)) goto Abort;
490
491         WIN_UnlinkWindow( hwnd );
492         WIN_LinkWindow( hwnd, hwndInsertAfter );
493     }
494
495       /* Recalculate client area position */
496
497     if (winPos->flags & SWP_FRAMECHANGED)
498     {
499           /* Send WM_NCCALCSIZE message */
500         NCCALCSIZE_PARAMS *params;
501         HANDLE hparams;
502         
503         if (!(hparams = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(*params) )))
504             goto Abort;
505         params = (NCCALCSIZE_PARAMS *) USER_HEAP_ADDR( hparams );
506         params->rgrc[0] = newWindowRect;
507         params->rgrc[1] = wndPtr->rectWindow;
508         params->rgrc[2] = wndPtr->rectClient;
509         params->lppos = winPos;
510         calcsize_result = SendMessage(hwnd, WM_NCCALCSIZE, TRUE, (LONG)params);
511         USER_HEAP_FREE( hparams );
512         newClientRect = params->rgrc[0];
513         /* Handle result here */
514     }
515     else
516     {
517         newClientRect.left   = newWindowRect.left + wndPtr->rectClient.left
518                                - wndPtr->rectWindow.left;
519         newClientRect.top    = newWindowRect.top + wndPtr->rectClient.top
520                                - wndPtr->rectWindow.top;
521         newClientRect.right  = newWindowRect.right + wndPtr->rectClient.right
522                                - wndPtr->rectWindow.right;
523         newClientRect.bottom = newWindowRect.bottom + wndPtr->rectClient.bottom
524                                - wndPtr->rectWindow.bottom;
525     }
526     
527       /* Perform the moving and resizing */
528
529     if (!(winPos->flags & SWP_NOMOVE))
530     {
531         WND * parentPtr;
532         winChanges.x = newWindowRect.left;
533         winChanges.y = newWindowRect.top;
534         if (wndPtr->hwndParent)
535         {
536             parentPtr = WIN_FindWndPtr(wndPtr->hwndParent);
537             winChanges.x += parentPtr->rectClient.left-parentPtr->rectWindow.left;
538             winChanges.y += parentPtr->rectClient.top-parentPtr->rectWindow.top;
539         }
540         changeMask |= CWX | CWY;
541     }
542     if (!(winPos->flags & SWP_NOSIZE))
543     {
544         winChanges.width  = newWindowRect.right - newWindowRect.left;
545         winChanges.height = newWindowRect.bottom - newWindowRect.top;
546         changeMask |= CWWidth | CWHeight;
547     }
548     if (!(winPos->flags & SWP_NOZORDER))
549     {
550         if (hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
551         else winChanges.stack_mode = Below;
552         if ((hwndInsertAfter != HWND_TOP) && (hwndInsertAfter != HWND_BOTTOM))
553         {
554             WND * insertPtr = WIN_FindWndPtr( hwndInsertAfter );
555             winChanges.sibling = insertPtr->window;
556             changeMask |= CWSibling;
557         }
558         changeMask |= CWStackMode;
559     }
560     if (changeMask) XConfigureWindow( display, wndPtr->window,
561                                       changeMask, &winChanges );
562
563     if (winPos->flags & SWP_SHOWWINDOW)
564     {
565         wndPtr->dwStyle |= WS_VISIBLE;
566         XMapWindow( display, wndPtr->window );
567     }
568     else if (winPos->flags & SWP_HIDEWINDOW)
569     {
570         wndPtr->dwStyle &= ~WS_VISIBLE;
571         XUnmapWindow( display, wndPtr->window );
572     }
573
574     if (!(winPos->flags & SWP_NOACTIVATE))
575     {
576         if (!(wndPtr->dwStyle & WS_CHILD))
577             WINPOS_ChangeActiveWindow( hwnd, FALSE );
578     }
579     
580       /* Send WM_NCPAINT message if needed */
581     if ((winPos->flags & (SWP_FRAMECHANGED | SWP_SHOWWINDOW)) ||
582         (!(winPos->flags & SWP_NOSIZE)) ||
583         (!(winPos->flags & SWP_NOMOVE)) ||
584         (!(winPos->flags & SWP_NOACTIVATE)) ||
585         (!(winPos->flags & SWP_NOZORDER)))
586             SendMessage( hwnd, WM_NCPAINT, 1, 0L );
587
588       /* Finally send the WM_WINDOWPOSCHANGED message */
589     wndPtr->rectWindow = newWindowRect;
590     wndPtr->rectClient = newClientRect;
591     SendMessage( hwnd, WM_WINDOWPOSCHANGED, 0, (LONG)winPos );
592     USER_HEAP_FREE( hmem );
593
594     return TRUE;
595
596  Abort:  /* Fatal error encountered */
597     if (hmem) USER_HEAP_FREE( hmem );
598     return FALSE;
599 }