source: trunk/src/user32/win32wbasepos.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 16.3 KB
Line 
1/* $Id: win32wbasepos.cpp,v 1.31 2003-05-15 12:40:20 sandervl Exp $ */
2/*
3 * Win32 Window Base Class for OS/2 (nonclient/position methods)
4 *
5 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
6 * Copyright 1999 Daniela Engert (dani@ngrt.de)
7 *
8 * Parts based on Wine Windows code (windows\win.c, windows\nonclient.c)
9 *
10 * Copyright 1993, 1994 Alexandre Julliard
11 *
12 * TODO: Not thread/process safe
13 *
14 * Wine code based on build 990815
15 *
16 * Project Odin Software License can be found in LICENSE.TXT
17 *
18 */
19#include <os2win.h>
20#include <win.h>
21#include <stdlib.h>
22#include <string.h>
23#include <stdarg.h>
24#include <assert.h>
25#include <misc.h>
26#include "win32wbase.h"
27#include <spy.h>
28#include "wndmsg.h"
29#include "oslibwin.h"
30#include "oslibutil.h"
31#include "oslibgdi.h"
32#include "oslibres.h"
33#include "oslibdos.h"
34#include "syscolor.h"
35#include "win32wndhandle.h"
36#include "dc.h"
37#include "win32wdesktop.h"
38#include <win/hook.h>
39
40#define DBG_LOCALLOG DBG_win32wbasepos
41#include "dbglocal.h"
42
43/*******************************************************************
44 * GetMinMaxInfo
45 *
46 * Get the minimized and maximized information for a window.
47 */
48void Win32BaseWindow::GetMinMaxInfo(POINT *maxSize, POINT *maxPos,
49 POINT *minTrack, POINT *maxTrack )
50{
51 MINMAXINFO MinMax;
52 INT xinc, yinc;
53
54 /* Compute default values */
55 MinMax.ptMaxPosition.x = 0;
56 MinMax.ptMaxPosition.y = 0;
57
58 if(!(getStyle() & (WS_POPUP | WS_CHILD))) {
59 RECT rect;
60 OSLibWinGetMaxPosition(getOS2FrameWindowHandle(), &rect);
61 MinMax.ptMaxPosition.x = rect.left;
62 MinMax.ptMaxPosition.y = rect.top;
63
64 MinMax.ptMaxSize.x = rect.right - rect.left;
65 MinMax.ptMaxSize.y = rect.bottom - rect.top;
66 MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
67 MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
68 MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXSCREEN);
69 MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYSCREEN);
70 }
71 else {
72 MinMax.ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN);
73 MinMax.ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN);
74 MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
75 MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
76 MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXSCREEN);
77 MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYSCREEN);
78 }
79
80 if (HAS_DLGFRAME( dwStyle, dwExStyle ))
81 {
82 xinc = GetSystemMetrics(SM_CXDLGFRAME);
83 yinc = GetSystemMetrics(SM_CYDLGFRAME);
84 }
85 else
86 {
87 xinc = yinc = 0;
88 if (HAS_THICKFRAME(dwStyle, dwExStyle))
89 {
90 xinc += GetSystemMetrics(SM_CXFRAME);
91 yinc += GetSystemMetrics(SM_CYFRAME);
92 }
93 //SvL: Wine has no 'else', but I'm seeing different behaviour in NT
94 // and it doesn't make much sense either as a window can have
95 // only one kind of border (see drawing code)
96 else
97 if (dwStyle & WS_BORDER)
98 {
99 xinc += GetSystemMetrics(SM_CXBORDER);
100 yinc += GetSystemMetrics(SM_CYBORDER);
101 }
102 }
103 MinMax.ptMaxSize.x += 2 * xinc;
104 MinMax.ptMaxSize.y += 2 * yinc;
105
106#if 0
107 lpPos = (LPINTERNALPOS)GetPropA( hwndSelf, atomInternalPos );
108 if( lpPos && !EMPTYPOINT(lpPos->ptMaxPos) )
109 CONV_POINT16TO32( &lpPos->ptMaxPos, &MinMax.ptMaxPosition );
110 else
111 {
112#endif
113 MinMax.ptMaxPosition.x -= xinc;
114 MinMax.ptMaxPosition.y -= yinc;
115// }
116
117 SendMessageA(getWindowHandle(), WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
118
119 /* Some sanity checks */
120
121 dprintf(("GetMinMaxInfo: %ld %ld / %ld %ld / %ld %ld / %ld %ld\n",
122 MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
123 MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
124 MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
125 MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y));
126 MinMax.ptMaxTrackSize.x = MAX( MinMax.ptMaxTrackSize.x,
127 MinMax.ptMinTrackSize.x );
128 MinMax.ptMaxTrackSize.y = MAX( MinMax.ptMaxTrackSize.y,
129 MinMax.ptMinTrackSize.y );
130
131 if (maxSize) *maxSize = MinMax.ptMaxSize;
132 if (maxPos) *maxPos = MinMax.ptMaxPosition;
133 if (minTrack) *minTrack = MinMax.ptMinTrackSize;
134 if (maxTrack) *maxTrack = MinMax.ptMaxTrackSize;
135}
136/***********************************************************************
137 * WINPOS_SendNCCalcSize
138 *
139 * Send a WM_NCCALCSIZE message to a window.
140 * All parameters are read-only except newClientRect.
141 * oldWindowRect, oldClientRect and winpos must be non-NULL only
142 * when calcValidRect is TRUE.
143 */
144LONG Win32BaseWindow::SendNCCalcSize(BOOL calcValidRect, RECT *newWindowRect,
145 RECT *oldWindowRect,
146 RECT *oldClientRect, WINDOWPOS *winpos,
147 RECT *newClientRect )
148{
149 NCCALCSIZE_PARAMS params;
150 WINDOWPOS winposCopy;
151 LONG result = 0;
152
153 /* Send WM_NCCALCSIZE message to get new client area */
154 params.rgrc[0] = *newWindowRect;
155 if(calcValidRect)
156 {
157 winposCopy = *winpos;
158 params.rgrc[1] = *oldWindowRect;
159 params.rgrc[2] = *oldClientRect;
160 //client rectangel must be in parent coordinates
161 OffsetRect(&params.rgrc[2], rectWindow.left, rectWindow.top);
162
163 params.lppos = &winposCopy;
164 }
165 result = SendMessageA(getWindowHandle(), WM_NCCALCSIZE, calcValidRect, (LPARAM)&params );
166
167 /* If the application send back garbage, ignore it */
168 if(params.rgrc[0].left <= params.rgrc[0].right && params.rgrc[0].top <= params.rgrc[0].bottom)
169 {
170 *newClientRect = params.rgrc[0];
171 //client rectangle now in parent coordinates; convert to 'frame' coordinates
172 OffsetRect(newClientRect, -rectWindow.left, -rectWindow.top);
173 }
174
175 /* FIXME: WVR_ALIGNxxx */
176 if(newClientRect->left != rectClient.left || newClientRect->top != rectClient.top)
177 winpos->flags &= ~SWP_NOCLIENTMOVE;
178
179 if((newClientRect->right - newClientRect->left != rectClient.right - rectClient.left) ||
180 (newClientRect->bottom - newClientRect->top != rectClient.bottom - rectClient.top))
181 winpos->flags &= ~SWP_NOCLIENTSIZE;
182
183 return result;
184}
185/***********************************************************************
186 * WINPOS_HandleWindowPosChanging
187 *
188 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
189 */
190LONG Win32BaseWindow::HandleWindowPosChanging(WINDOWPOS *winpos)
191{
192 POINT maxSize, maxTrack, minTrack;
193 if (winpos->flags & SWP_NOSIZE) return 0;
194
195 if ((dwStyle & WS_THICKFRAME) ||
196 ((dwStyle & (WS_POPUP | WS_CHILD)) == 0))
197 {
198 GetMinMaxInfo( &maxSize, NULL, &minTrack, &maxTrack );
199 winpos->cx = MIN( winpos->cx, MAX( maxSize.x, maxTrack.x) );
200 winpos->cy = MIN( winpos->cy, MAX( maxSize.y, maxTrack.y) );
201 if (!(dwStyle & WS_MINIMIZE))
202 {
203 if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x;
204 if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y;
205 }
206 }
207 return 0;
208}
209/***********************************************************************
210 * WINPOS_FindIconPos
211 *
212 * Find a suitable place for an iconic window.
213 */
214static void WINPOS_FindIconPos( HWND hwnd, POINT &pt )
215{
216 RECT rectParent;
217 int x, y, xspacing, yspacing;
218 HWND hwndChild, hwndParent;
219
220 hwndParent = GetParent(hwnd);
221 if(hwndParent == 0) {
222 dprintf(("WINPOS_FindIconPos: no parent found for window %x", hwnd));
223 return;
224 }
225
226 GetClientRect(hwndParent, &rectParent );
227 if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
228 (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
229 return; /* The icon already has a suitable position */
230
231 xspacing = GetSystemMetrics(SM_CXICONSPACING);
232 yspacing = GetSystemMetrics(SM_CYICONSPACING);
233
234 y = rectParent.bottom;
235 for (;;)
236 {
237 x = rectParent.left;
238 do
239 {
240 /* Check if another icon already occupies this spot */
241 hwndChild = GetWindow(hwndParent, GW_CHILD);
242
243 while(hwndChild)
244 {
245 Win32BaseWindow *child = NULL;
246 RECT *pRectWindow;
247
248 child = Win32BaseWindow::GetWindowFromHandle(hwndChild);
249 if(!child) {
250 dprintf(("ERROR: WINPOS_FindIconPos, child %x not found", hwndChild));
251 return;
252 }
253 if ((child->getStyle() & WS_MINIMIZE) && (child->getWindowHandle() != hwnd))
254 {
255 pRectWindow = child->getWindowRect();
256 if ((pRectWindow->left < x + xspacing) &&
257 (pRectWindow->right >= x) &&
258 (pRectWindow->top <= y) &&
259 (pRectWindow->bottom > y - yspacing))
260 break; /* There's a window in there */
261 }
262 RELEASE_WNDOBJ(child);
263 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
264 }
265
266 if (!hwndChild) /* No window was found, so it's OK for us */
267 {
268 pt.x = x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
269 pt.y = y - (yspacing + GetSystemMetrics(SM_CYICON)) / 2;
270 return;
271 }
272 x += xspacing;
273 } while(x <= rectParent.right-xspacing);
274
275 y -= yspacing;
276 }
277}
278/******************************************************************************
279 * WINPOS_MinMaximize
280 *
281 * Fill in lpRect and return additional flags to be used with SetWindowPos().
282 * This function assumes that 'cmd' is different from the current window
283 * state.
284 */
285UINT Win32BaseWindow::MinMaximize(UINT cmd, LPRECT lpRect)
286{
287 UINT swpFlags = 0;
288 POINT size, iconPos;
289
290 size.x = rectWindow.left;
291 size.y = rectWindow.top;
292
293 if(IsRectEmpty(&windowpos.rcNormalPosition)) {
294 CopyRect(&windowpos.rcNormalPosition, &rectWindow);
295 }
296 if(!HOOK_CallHooksA(WH_CBT, HCBT_MINMAX, getWindowHandle(), cmd))
297 {
298 if(getStyle() & WS_MINIMIZE )
299 {
300 if(!SendMessageA(getWindowHandle(), WM_QUERYOPEN, 0, 0L))
301 return (SWP_NOSIZE | SWP_NOMOVE);
302 }
303 switch( cmd )
304 {
305 case SW_MINIMIZE:
306 if( getStyle() & WS_MAXIMIZE)
307 {
308 setFlags(getFlags() | WIN_RESTORE_MAX);
309 setStyle(getStyle() & ~WS_MAXIMIZE);
310 }
311 else setFlags(getFlags() & ~WIN_RESTORE_MAX);
312
313 setStyle(getStyle() | WS_MINIMIZE);
314
315 if(getParent() == NULL) {
316// @@PF : for now disable windows style - it messes with WV minimize - will fix it soon
317// SetRect(lpRect, -32000, -32000, getWindowWidth(), getWindowHeight());
318// OSLibSetWindowStyle(getOS2FrameWindowHandle(), getOS2WindowHandle(), getStyle(), getExStyle());
319 }
320 else {
321 iconPos.x = windowpos.ptMinPosition.x;
322 iconPos.y = windowpos.ptMinPosition.y;
323 WINPOS_FindIconPos(getWindowHandle(), iconPos);
324 SetRect(lpRect, iconPos.x, iconPos.y, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
325 }
326 break;
327
328 case SW_MAXIMIZE:
329 GetMinMaxInfo(&size, &windowpos.ptMaxPosition, NULL, NULL );
330
331 if(getStyle() & WS_MINIMIZE )
332 {
333 setStyle(getStyle() & ~WS_MINIMIZE);
334 OSLibSetWindowStyle(getOS2FrameWindowHandle(), getOS2WindowHandle(), getStyle(), getExStyle(), getStyle());
335 }
336 setStyle(getStyle() | WS_MAXIMIZE);
337
338 SetRect(lpRect, windowpos.ptMaxPosition.x, windowpos.ptMaxPosition.y,
339 size.x, size.y );
340 break;
341
342 case SW_RESTORE:
343 if(getStyle() & WS_MINIMIZE)
344 {
345 setStyle(getStyle() & ~WS_MINIMIZE);
346 OSLibSetWindowStyle(getOS2FrameWindowHandle(), getOS2WindowHandle(), getStyle(), getExStyle(), getStyle());
347
348 if( getFlags() & WIN_RESTORE_MAX)
349 {
350 /* Restore to maximized position */
351 GetMinMaxInfo(&size, &windowpos.ptMaxPosition, NULL, NULL);
352 setStyle(getStyle() | WS_MAXIMIZE);
353 SetRect(lpRect, windowpos.ptMaxPosition.x, windowpos.ptMaxPosition.y, size.x, size.y);
354 break;
355 }
356 }
357 else
358 if( !(getStyle() & WS_MAXIMIZE) )
359 return 0;
360 else setStyle(getStyle() & ~WS_MAXIMIZE);
361
362 /* Restore to normal position */
363 *lpRect = windowpos.rcNormalPosition;
364 lpRect->right -= lpRect->left;
365 lpRect->bottom -= lpRect->top;
366 break;
367 }
368 }
369 else swpFlags |= SWP_NOSIZE | SWP_NOMOVE;
370
371 return swpFlags;
372}
373/***********************************************************************
374 * WIN_FixCoordinates
375 *
376 * Fix the coordinates - Helper for WIN_CreateWindowEx.
377 * returns default show mode in sw.
378 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
379 */
380void Win32BaseWindow::FixCoordinates( CREATESTRUCTA *cs, INT *sw)
381{
382 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
383 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
384 {
385 if (cs->style & (WS_CHILD | WS_POPUP))
386 {
387 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
388 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
389 }
390 else /* overlapped window */
391 {
392 STARTUPINFOA info;
393
394 GetStartupInfoA( &info );
395
396 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
397 {
398 /* Never believe Microsoft's documentation... CreateWindowEx doc says
399 * that if an overlapped window is created with WS_VISIBLE style bit
400 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
401 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
402 * reveals that
403 *
404 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
405 * 2) it does not ignore the y parameter as the docs claim; instead, it
406 * uses it as second parameter to ShowWindow() unless y is either
407 * CW_USEDEFAULT or CW_USEDEFAULT16.
408 *
409 * The fact that we didn't do 2) caused bogus windows pop up when wine
410 * was running apps that were using this obscure feature. Example -
411 * calc.exe that comes with Win98 (only Win98, it's different from
412 * the one that comes with Win95 and NT)
413 */
414 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
415 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
416 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
417 }
418
419 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
420 {
421 if (info.dwFlags & STARTF_USESIZE)
422 {
423 cs->cx = info.dwXSize;
424 cs->cy = info.dwYSize;
425 }
426 else /* if no other hint from the app, pick 3/4 of the screen real estate */
427 {
428 RECT r;
429 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
430 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
431 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
432 }
433 }
434 }
435 }
436 else
437 {
438 /* neither x nor cx are default. Check the y values .
439 * In the trace we see Outlook and Outlook Express using
440 * cy set to CW_USEDEFAULT when opening the address book.
441 */
442 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
443 RECT r;
444 dprintf(("Strange use of CW_USEDEFAULT in nHeight\n"));
445 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
446 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
447 }
448 }
449}
450//******************************************************************************
451//******************************************************************************
Note: See TracBrowser for help on using the repository browser.