source: trunk/src/gui/kernel/qwidget_pm.cpp@ 603

Last change on this file since 603 was 603, checked in by Dmitry A. Kuminov, 15 years ago

gui: Fixed assertion at #1125 in qwidget.cpp (due to an attempt to re-instantiate QDesktopWidget during application termination).

File size: 94.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** Copyright (C) 2009 netlabs.org. OS/2 parts.
8**
9** This file is part of the QtGui module of the Qt Toolkit.
10**
11** $QT_BEGIN_LICENSE:LGPL$
12** Commercial Usage
13** Licensees holding valid Qt Commercial licenses may use this file in
14** accordance with the Qt Commercial License Agreement provided with the
15** Software or, alternatively, in accordance with the terms contained in
16** a written agreement between you and Nokia.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 2.1 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 2.1 requirements
24** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** In addition, as a special exception, Nokia gives you certain additional
27** rights. These rights are described in the Nokia Qt LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** GNU General Public License Usage
31** Alternatively, this file may be used under the terms of the GNU
32** General Public License version 3.0 as published by the Free Software
33** Foundation and appearing in the file LICENSE.GPL included in the
34** packaging of this file. Please review the following information to
35** ensure the GNU General Public License version 3.0 requirements will be
36** met: http://www.gnu.org/copyleft/gpl.html.
37**
38** If you have questions regarding the use of this file, please contact
39** Nokia at [email protected].
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include "qt_os2.h"
45
46#include "qdebug.h"
47
48#include "qwidget.h"
49#include "qwidget_p.h"
50
51#include "qapplication.h"
52#include "qdesktopwidget.h"
53#include "qevent.h"
54
55#include "private/qapplication_p.h"
56#include "private/qbackingstore_p.h"
57#include "private/qwindowsurface_raster_p.h"
58
59//#define QT_DEBUGWINCREATEDESTROY
60//#define QT_DEBUGWIDGETMASK
61
62QT_BEGIN_NAMESPACE
63
64static QWidget *mouseGrb = 0;
65static QCursor *mouseGrbCur = 0;
66static QWidget *keyboardGrb = 0;
67
68// defined in qapplication_pm.cpp
69extern bool qt_nograb();
70extern MRESULT EXPENTRY QtWndProc(HWND, ULONG, MPARAM, MPARAM);
71extern PFNWP QtOldFrameProc;
72extern MRESULT EXPENTRY QtFrameProc(HWND, ULONG, MPARAM, MPARAM);
73extern PFNWP QtOldFrameCtlProcs[FID_HORZSCROLL - FID_SYSMENU + 1];
74extern MRESULT EXPENTRY QtFrameCtlProc(HWND, ULONG, MPARAM, MPARAM);
75
76#if !defined(QT_NO_SESSIONMANAGER)
77bool qt_about_to_destroy_wnd = false;
78#endif
79
80typedef QSet<QString> WinClassNameHash;
81Q_GLOBAL_STATIC(WinClassNameHash, winclassNames)
82
83// register window class
84static const QString qt_reg_winclass(QWidget *w)
85{
86 int flags = w->windowFlags();
87 int type = flags & Qt::WindowType_Mask;
88
89 QString cname;
90 ULONG style = 0;
91
92 if (type == Qt::Popup || type == Qt::ToolTip) {
93 cname = QLatin1String("QPopup");
94 style |= CS_SAVEBITS;
95 } else if (w->isWindow()) {
96 // this class is for top level widgets which are client HWNDs of a
97 // WC_FRAME parent HWND internally maintaned for them
98 cname = QLatin1String("QWindow");
99 } else {
100 cname = QLatin1String("QWidget");
101 }
102
103 if (winclassNames()->contains(cname)) // already registered in our list
104 return cname;
105
106 // QT_EXTRAWINDATASIZE is defined in qwindowdefs_pm.h
107 WinRegisterClass(0, cname.toLatin1(), QtWndProc, style, QT_EXTRAWINDATASIZE);
108
109 winclassNames()->insert(cname);
110 return cname;
111
112 // Note: there is no need to unregister private window classes registered by
113 // this function -- it is done automatically upon process termination.
114}
115
116/*!
117 \internal
118
119 Extended version of WinQueryClipRegion(). If the given window has a clip
120 region, the given region will receive a copy of the clip region clipped to
121 the current window rectangle. If there is no clip region, the given region
122 will contain only the window rectangle on return.
123 */
124void qt_WinQueryClipRegionOrRect(HWND hwnd, HRGN hrgn)
125{
126 RECTL rcl;
127 WinQueryWindowRect(hwnd, &rcl);
128
129 HPS hps = qt_display_ps();
130 GpiSetRegion(hps, hrgn, 1, &rcl);
131 if (WinQueryClipRegion(hwnd, 0) != QCRGN_NO_CLIP_REGION) {
132 HRGN hrgnTemp = GpiCreateRegion(hps, 0, NULL);
133 WinQueryClipRegion(hwnd, hrgnTemp);
134 GpiCombineRegion(hps, hrgn, hrgnTemp, hrgn, CRGN_AND);
135 GpiDestroyRegion(hps, hrgnTemp);
136 }
137}
138
139/*!
140 \internal
141
142 Extended version of WinInvalidateRegion(): invalidates the specified region
143 of the given window and regions of children from \a hwndFrom to \a hwndTo
144 if they intersect with the invalid region. If either of child window
145 handles is NULLHANDLE, children are not invalidated at all. Also, HWND_TOP
146 can be used as \a hwndFrom, HWND_BOTTOM \a can be used as \a hwndTo.
147 */
148static BOOL qt_WinInvalidateRegionEx(HWND hwnd, HRGN hrgn,
149 HWND hwndFrom, HWND hwndTo)
150{
151#if defined(QT_DEBUGWIDGETMASK)
152 qDebug("qt_WinInvalidateRegionEx: hwnd=%s hwndFrom=%08lX hwndTo=%08lX",
153 qStrHWND(hwnd).toUtf8().constData(), hwndFrom, hwndTo);
154#endif
155
156 if (hwndFrom == HWND_TOP)
157 hwndFrom = WinQueryWindow(hwnd, QW_TOP);
158 if (hwndTo == HWND_BOTTOM)
159 hwndTo = WinQueryWindow(hwnd, QW_BOTTOM);
160
161 if (hwndFrom == 0 || hwndTo == 0)
162 return WinInvalidateRegion(hwnd, hrgn, FALSE);
163
164 if (WinQueryWindow(hwndFrom, QW_PARENT) != hwnd ||
165 WinQueryWindow(hwndTo, QW_PARENT) != hwnd)
166 return FALSE;
167
168 HPS hps = qt_display_ps();
169
170 SWP swp;
171 HWND child = hwndFrom;
172 HRGN hrgnChild = GpiCreateRegion(hps, 0, NULL);
173 HRGN hrgnInv = GpiCreateRegion(hps, 0, NULL);
174 GpiCombineRegion(hps, hrgnInv, hrgn, 0, CRGN_COPY);
175
176 LONG cmplx = RGN_RECT;
177
178 while (child) {
179 WinQueryWindowPos(child, &swp);
180#if defined(QT_DEBUGWIDGETMASK)
181 qDebug(" child=%s [fl=%08lX]", qStrHWND(child).toUtf8().constData(),
182 swp.fl);
183#endif
184 // proceed only if not hidden
185 if (swp.fl & SWP_SHOW) {
186 // get sibling's bounds (clip region or rect)
187 qt_WinQueryClipRegionOrRect(child, hrgnChild);
188 // translate the region to the parent's coordinate system
189 POINTL ptl = { swp.x, swp.y };
190 GpiOffsetRegion(hps, hrgnChild, &ptl);
191 // intersect the child's region with the invalid one
192 // and invalidate if not NULL
193 cmplx = GpiCombineRegion(hps, hrgnChild, hrgnChild, hrgnInv,
194 CRGN_AND);
195 if (cmplx != RGN_NULL) {
196 POINTL ptl2 = { -swp.x, -swp.y };
197 GpiOffsetRegion(hps, hrgnChild, &ptl2);
198 WinInvalidateRegion(child, hrgnChild, TRUE);
199 GpiOffsetRegion(hps, hrgnChild, &ptl);
200 // substract the invalidated area from the widget's region
201 // (no need to invalidate it any more)
202 cmplx = GpiCombineRegion(hps, hrgnInv, hrgnInv, hrgnChild,
203 CRGN_DIFF);
204#if defined(QT_DEBUGWIDGETMASK)
205 qDebug(" processed");
206#endif
207 // finish if nothing left
208 if (cmplx == RGN_NULL)
209 break;
210 }
211 }
212 // iterate to the next window (below)
213 if (child == hwndTo)
214 break;
215 child = WinQueryWindow(child, QW_NEXT);
216 }
217
218 BOOL ok = (cmplx == RGN_NULL) || (child == hwndTo);
219
220 if (ok) {
221 // invalidate what's left invalid after substracting children
222 WinInvalidateRegion(hwnd, hrgnInv, FALSE);
223 }
224
225 GpiDestroyRegion(hps, hrgnInv);
226 GpiDestroyRegion(hps, hrgnChild);
227
228 return ok;
229}
230
231/** \internal flags for qt_WinProcessWindowObstacles() */
232enum {
233 PWO_Children = 0x01,
234 PWO_Sibings = 0x02,
235 PWO_Ancestors = 0x04,
236 PWO_Screen = 0x08,
237 PWO_TopLevel = 0x80000000,
238 // PWO_Default is suitable in most cases (for simple paint operations)
239 PWO_Default = PWO_Children | PWO_Sibings | PWO_Ancestors | PWO_Screen,
240};
241
242/*!
243 \internal
244
245 Helper function to collect all relative windows intersecting with the
246 given window and placed above it in z-order.
247
248 \param hwnd window in question
249 \param prcl rectangle (in window coordinates) to limit processing to
250 (if null, the whole window rectange is used)
251 \param hrgn region where to combine all obstacles
252 (if 0, obstacles are directly validated instead of collecting)
253 \param op region operation perfomed when combining obstacles (CRGN_*)
254 \param flags flags defining the scope (PWO_* ORed together)
255
256 \return complexity of the combined region (only when \a hrgn is not 0)
257 */
258static LONG qt_WinProcessWindowObstacles(HWND hwnd, PRECTL prcl, HRGN hrgn,
259 LONG op, LONG flags = PWO_Default)
260{
261 Q_ASSERT(hwnd);
262
263 HPS displayPS = qt_display_ps();
264
265#if defined(QT_DEBUGWIDGETMASK)
266 qDebug("qt_WinProcessWindowObstacles: hwnd=%s, prcl=%p "
267 "hrgn=%08lX, op=%ld flags=%08lX",
268 qStrHWND(hwnd).toUtf8().constData(), prcl, hrgn, op, flags);
269#endif
270
271 SWP swpSelf;
272 WinQueryWindowPos(hwnd, &swpSelf);
273
274 RECTL rclSelf = { 0, 0, swpSelf.cx, swpSelf.cy };
275 if (prcl)
276 rclSelf = *prcl;
277
278 HRGN whrgn = GpiCreateRegion(displayPS, 0, NULL);
279
280 LONG cmplx = RGN_NULL;
281 HWND relative;
282 SWP swp;
283
284 // first, process areas placed outside the screen bounds
285 if (flags & PWO_Screen) {
286 RECTL rclScr = { 0, 0, qt_display_width(), qt_display_height() };
287 WinMapWindowPoints(HWND_DESKTOP, hwnd, (PPOINTL) &rclScr, 2);
288 // rough check of whether some window part is outside bounds
289 if (rclSelf.xLeft < rclScr.xLeft ||
290 rclSelf.yBottom < rclScr.yBottom ||
291 rclSelf.xRight > rclScr.xRight ||
292 rclSelf.yTop > rclScr.yTop) {
293 GpiSetRegion(displayPS, whrgn, 1, &rclSelf);
294 HRGN hrgnScr = GpiCreateRegion(displayPS, 1, &rclScr);
295 // substract the screen region from this window's region
296 // to get parts placed outside
297 GpiCombineRegion(displayPS, whrgn, whrgn, hrgnScr, CRGN_DIFF);
298 GpiDestroyRegion(displayPS, hrgnScr);
299 // process the region
300 if (hrgn != NULLHANDLE) {
301 cmplx = GpiCombineRegion(displayPS, hrgn, hrgn, whrgn, op);
302 } else {
303 WinValidateRegion(hwnd, whrgn, FALSE);
304 }
305#if defined(QT_DEBUGWIDGETMASK)
306 qDebug(" collected areas outside screen bounds");
307#endif
308 }
309 }
310
311 // next, go through all children (in z-order)
312 if (flags & PWO_Children) {
313 relative = WinQueryWindow(hwnd, QW_BOTTOM);
314 if (relative != NULLHANDLE) {
315 for (; relative != HWND_TOP; relative = swp.hwndInsertBehind) {
316 WinQueryWindowPos(relative, &swp);
317#if defined(QT_DEBUGWIDGETMASK)
318 qDebug(" child=%s [fl=%08lX]",
319 qStrHWND(relative).toUtf8().constData(), swp.fl);
320#endif
321 // skip if hidden
322 if (!(swp.fl & SWP_SHOW))
323 continue;
324 // rough check for intersection
325 if (swp.x >= rclSelf.xRight || swp.y >= rclSelf.yTop ||
326 swp.x + swp.cx <= rclSelf.xLeft ||
327 swp.y + swp.cy <= rclSelf.yBottom)
328 continue;
329 // get the bounds (clip region or rect)
330 qt_WinQueryClipRegionOrRect(relative, whrgn);
331 // translate the region to this window's coordinate system
332 POINTL ptl = { swp.x, swp.y };
333 GpiOffsetRegion(displayPS, whrgn, &ptl);
334 // process the region
335 if (hrgn != NULLHANDLE) {
336 cmplx = GpiCombineRegion(displayPS, hrgn, hrgn, whrgn, op);
337 } else {
338 WinValidateRegion(hwnd, whrgn, FALSE);
339 }
340#if defined(QT_DEBUGWIDGETMASK)
341 qDebug(" collected");
342#endif
343 }
344 }
345 }
346
347 HWND desktop = WinQueryDesktopWindow(0, 0);
348 HWND parent = WinQueryWindow(hwnd, QW_PARENT);
349
350 // next, go through all siblings placed above (in z-order),
351 // but only if they are not top-level windows (that cannot be
352 // non-rectangular and thus are always correctly clipped by the system)
353 if ((flags & PWO_Sibings) && parent != desktop) {
354 for (relative = swpSelf.hwndInsertBehind;
355 relative != HWND_TOP; relative = swp.hwndInsertBehind) {
356 WinQueryWindowPos(relative, &swp);
357#if defined(QT_DEBUGWIDGETMASK)
358 qDebug(" sibling=%s [fl=%08lX]",
359 qStrHWND(relative).toUtf8().constData(), swp.fl);
360#endif
361 // skip if hidden
362 if (!(swp.fl & SWP_SHOW))
363 continue;
364 // rough check for intersection
365 if (swp.x >= swpSelf.x + rclSelf.xRight ||
366 swp.y >= swpSelf.y + rclSelf.yTop ||
367 swp.x + swp.cx <= swpSelf.x + rclSelf.xLeft ||
368 swp.y + swp.cy <= swpSelf.y + rclSelf.yBottom)
369 continue;
370 // get the bounds (clip region or rect)
371 qt_WinQueryClipRegionOrRect(relative, whrgn);
372 // translate the region to this window's coordinate system
373 POINTL ptl = { swp.x - swpSelf.x, swp.y - swpSelf.y };
374 GpiOffsetRegion(displayPS, whrgn, &ptl);
375 // process the region
376 if (hrgn != NULLHANDLE) {
377 cmplx = GpiCombineRegion(displayPS, hrgn, hrgn, whrgn, op);
378 } else {
379 WinValidateRegion(hwnd, whrgn, FALSE);
380 }
381#if defined(QT_DEBUGWIDGETMASK)
382 qDebug(" collected");
383#endif
384 }
385 }
386
387 // last, go through all siblings of our parent and its ancestors
388 // placed above (in z-order)
389 if (flags & PWO_Ancestors) {
390 POINTL delta = { swpSelf.x, swpSelf.y };
391 while (parent != desktop) {
392 HWND grandParent = WinQueryWindow(parent, QW_PARENT);
393 if (!(flags & PWO_TopLevel)) {
394 // When PWO_TopLevel is not specified, top-level windows
395 // (children of the desktop) are not processed. It makes sense
396 // when qt_WinProcessWindowObstacles() is used to clip out
397 // overlying windows during regular paint operations (WM_PAINT
398 // processing or drawing in a window directly through
399 // WinGetPS()): in this case, top-level windows are always
400 // correctly clipped out by the system (because they cannot be
401 // non-rectangular).
402 if (grandParent == desktop)
403 break;
404 }
405
406 WinQueryWindowPos(parent, &swp);
407#if defined(QT_DEBUGWIDGETMASK)
408 qDebug(" parent=%s [fl=%08lX]",
409 qStrHWND(parent).toUtf8().constData(), swp.fl);
410#endif
411 delta.x += swp.x;
412 delta.y += swp.y;
413 for (relative = swp.hwndInsertBehind;
414 relative != HWND_TOP; relative = swp.hwndInsertBehind) {
415 WinQueryWindowPos(relative, &swp);
416#if defined(QT_DEBUGWIDGETMASK)
417 qDebug(" ancestor=%s [fl=%08lX]",
418 qStrHWND(relative).toUtf8().constData(), swp.fl);
419#endif
420 // skip if hidden
421 if (!(swp.fl & SWP_SHOW))
422 continue;
423 // rough check for intersection
424 if (swp.x - delta.x >= rclSelf.xRight ||
425 swp.y - delta.y >= rclSelf.yTop ||
426 swp.x - delta.x + swp.cx <= rclSelf.xLeft ||
427 swp.y - delta.y + swp.cy <= rclSelf.yBottom)
428 continue;
429 // get the bounds (clip region or rect)
430 qt_WinQueryClipRegionOrRect(relative, whrgn);
431 // translate the region to this window's coordinate system
432 POINTL ptl = { swp.x - delta.x, swp.y - delta.y };
433 GpiOffsetRegion(displayPS, whrgn, &ptl);
434 // process the region
435 if (hrgn != NULLHANDLE) {
436 cmplx = GpiCombineRegion(displayPS, hrgn, hrgn, whrgn, op);
437 } else {
438 WinValidateRegion(hwnd, whrgn, FALSE);
439 }
440#if defined(QT_DEBUGWIDGETMASK)
441 qDebug(" collected");
442#endif
443 }
444 parent = grandParent;
445 }
446 }
447
448 GpiDestroyRegion(displayPS, whrgn);
449
450 return cmplx;
451}
452
453/*!
454 \internal
455
456 Partial reimplementation of the WinSetWindowPos() API that obeys window clip
457 regions. Currently supported flags are SWP_ZORDER, SWP_SHOW, SWP_HIDE,
458 SWP_ACTIVATE, SWP_MOVE, SWP_SIZE and SWP_NOREDRAW; other flags should no be
459 used.
460
461 Note that if the above restrictions are not met or if the given window is a
462 top-level window, this function acts exactly like the original
463 WinSetWindowPos() function.
464 */
465static BOOL qt_WinSetWindowPos(HWND hwnd, HWND hwndInsertBehind,
466 LONG x, LONG y, LONG cx, LONG cy,
467 ULONG fl)
468{
469#if defined(QT_DEBUGWIDGETMASK)
470 qDebug("qt_WinSetWindowPos: hwnd=%s fl=%08lX",
471 qStrHWND(hwnd).toUtf8().constData(), fl);
472#endif
473
474 HWND desktop = WinQueryDesktopWindow(0, 0);
475
476 Q_ASSERT(((fl & ~(SWP_ZORDER | SWP_SHOW | SWP_HIDE | SWP_ACTIVATE |
477 SWP_MOVE | SWP_SIZE | SWP_NOREDRAW)) == 0) ||
478 hwnd == desktop || WinQueryWindow(hwnd, QW_PARENT) == desktop);
479
480 if ((fl & ~(SWP_ZORDER | SWP_SHOW | SWP_HIDE | SWP_ACTIVATE |
481 SWP_MOVE | SWP_SIZE | SWP_NOREDRAW)) != 0 ||
482 hwnd == desktop || WinQueryWindow(hwnd, QW_PARENT) == desktop) {
483 return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
484 }
485
486 SWP swpOld;
487 WinQueryWindowPos(hwnd, &swpOld);
488
489 // do some checks
490 if ((fl & SWP_ZORDER) && swpOld.hwndInsertBehind == hwndInsertBehind)
491 fl &= ~SWP_ZORDER;
492 if ((fl & SWP_SHOW) && (swpOld.fl & SWP_SHOW))
493 fl &= ~SWP_SHOW;
494 if ((fl & SWP_HIDE) && (swpOld.fl & SWP_HIDE))
495 fl &= ~SWP_HIDE;
496 if ((fl & (SWP_SHOW | SWP_HIDE)) == (SWP_SHOW | SWP_HIDE))
497 fl &= ~SWP_HIDE;
498
499 // do the job but not invalidate or redraw
500 BOOL rc = WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy,
501 fl | SWP_NOREDRAW);
502 if (rc == FALSE || (fl & SWP_NOREDRAW))
503 return rc;
504
505 SWP swpNew;
506 WinQueryWindowPos(hwnd, &swpNew);
507
508 if (swpOld.hwndInsertBehind == swpNew.hwndInsertBehind)
509 fl &= ~SWP_ZORDER;
510
511 if ((fl & (SWP_ZORDER | SWP_SHOW | SWP_HIDE | SWP_MOVE | SWP_SIZE)) == 0)
512 return rc;
513
514 HPS hps = qt_display_ps();
515 HWND hwndParent = WinQueryWindow(hwnd, QW_PARENT);
516
517 // get window bounds
518 HRGN hrgnSelf = GpiCreateRegion(hps, 0, NULL);
519 qt_WinQueryClipRegionOrRect(hwnd, hrgnSelf);
520
521 if (fl & SWP_SHOW) {
522 WinInvalidateRegion(hwnd, hrgnSelf, TRUE);
523 } else if (fl & SWP_HIDE) {
524 // translate the region to the parent coordinate system
525 POINTL ptl = { swpNew.x, swpNew.y };
526 GpiOffsetRegion(hps, hrgnSelf, &ptl);
527 // invalidate the parent and children below this window
528 qt_WinInvalidateRegionEx(hwndParent, hrgnSelf,
529 WinQueryWindow(hwnd, QW_NEXT), HWND_BOTTOM);
530 } else {
531 // SWP_ZORDER or SWP_MOVE or SWP_SIZE
532
533 if (fl & SWP_ZORDER) {
534 // below we assume that WinSetWindowPos() returns FALSE if
535 // an incorrect (unrelated) hwndInsertBehind is passed when SWP_ZORDER
536 // is set
537
538 // first, detect whether we are moving up or down
539 BOOL up;
540 HWND hwndFrom, hwndTo;
541 if (swpOld.hwndInsertBehind == HWND_TOP) {
542 up = FALSE;
543 hwndFrom = WinQueryWindow(hwndParent, QW_TOP);
544 hwndTo = swpNew.hwndInsertBehind;
545 } else {
546 up = TRUE;
547 for (HWND hwndAbove = hwnd;
548 (hwndAbove = WinQueryWindow(hwndAbove, QW_PREV)) != 0;) {
549 if (hwndAbove == swpOld.hwndInsertBehind) {
550 up = FALSE;
551 break;
552 }
553 }
554 if (up) {
555 hwndFrom = swpOld.hwndInsertBehind;
556 hwndTo = WinQueryWindow(hwnd, QW_NEXT);
557 } else {
558 hwndFrom = WinQueryWindow(swpOld.hwndInsertBehind, QW_NEXT);
559 hwndTo = swpNew.hwndInsertBehind;
560 }
561 }
562#if defined(QT_DEBUGWIDGETMASK)
563 qDebug(" moving up? %ld", up);
564 qDebug(" hwndFrom=%s", qStrHWND(hwndFrom).toUtf8().constData());
565 qDebug(" hwndTo=%s", qStrHWND(hwndTo).toUtf8().constData());
566#endif
567
568 SWP swp;
569 HWND sibling = hwndFrom;
570 HRGN hrgn = GpiCreateRegion(hps, 0, NULL);
571 HRGN hrgnUpd = GpiCreateRegion(hps, 0, NULL);
572
573 if (up) {
574 // go upwards in z-order
575 while (1) {
576 WinQueryWindowPos(sibling, &swp);
577#if defined(QT_DEBUGWIDGETMASK)
578 qDebug(" sibling=%s [fl=%08lX]",
579 qStrHWND(sibling).toUtf8().constData(), swp.fl);
580#endif
581 // proceed only if not hidden
582 if (swp.fl & SWP_SHOW) {
583 // get sibling's bounds (clip region or rect)
584 qt_WinQueryClipRegionOrRect(sibling, hrgn);
585 // translate the region to this window's coordinate system
586 POINTL ptl = { swp.x - swpNew.x, swp.y - swpNew.y };
587 GpiOffsetRegion(hps, hrgn, &ptl);
588 // add to the region of siblings we're moving on top of
589 GpiCombineRegion(hps, hrgnUpd, hrgnUpd, hrgn, CRGN_OR);
590#if defined(QT_DEBUGWIDGETMASK)
591 qDebug(" processed");
592#endif
593 }
594 // iterate to the prev window (above)
595 if (sibling == hwndTo)
596 break;
597 sibling = swp.hwndInsertBehind;
598 }
599 // intersect the resulting region with the widget region and
600 // invalidate
601 GpiCombineRegion(hps, hrgnUpd, hrgnSelf, hrgnUpd, CRGN_AND);
602 WinInvalidateRegion(hwnd, hrgnUpd, TRUE);
603 } else {
604 // go downwards in reverse z-order
605 POINTL ptl = { 0, 0 };
606 while (1) {
607 WinQueryWindowPos(sibling, &swp);
608#if defined(QT_DEBUGWIDGETMASK)
609 qDebug(" sibling=%s [fl=%08lX]",
610 qStrHWND(sibling).toUtf8().constData(), swp.fl);
611#endif
612 // proceed only if not hidden
613 if (swp.fl & SWP_SHOW) {
614 // get sibling's bounds (clip region or rect)
615 qt_WinQueryClipRegionOrRect(sibling, hrgn);
616 // undo the previous translation and translate this window's
617 // region to the siblings's coordinate system
618 ptl.x += swpNew.x - swp.x;
619 ptl.y += swpNew.y - swp.y;
620 GpiOffsetRegion(hps, hrgnSelf, &ptl);
621 // intersect the sibling's region with the translated one
622 // and invalidate the sibling
623 GpiCombineRegion(hps, hrgnUpd, hrgnSelf, hrgn, CRGN_AND);
624 WinInvalidateRegion(sibling, hrgnUpd, TRUE);
625 // substract the invalidated area from the widget's region
626 // (no need to invalidate it any more)
627 GpiCombineRegion(hps, hrgnSelf, hrgnSelf, hrgnUpd, CRGN_DIFF);
628 // prepare the translation from the sibling's
629 // coordinates back to this window's coordinates
630 ptl.x = swp.x - swpNew.x;
631 ptl.y = swp.y - swpNew.y;
632#if defined(QT_DEBUGWIDGETMASK)
633 qDebug(" processed");
634#endif
635 }
636 // iterate to the next window (below)
637 if (sibling == hwndTo)
638 break;
639 sibling = WinQueryWindow(sibling, QW_NEXT);
640 }
641 }
642
643 GpiDestroyRegion(hps, hrgnUpd);
644 GpiDestroyRegion(hps, hrgn);
645 }
646
647 if (fl & (SWP_MOVE | SWP_SIZE)) {
648 // Since we don't use WS_CLIPCHILDREN and WS_CLIPSIBLINGS,
649 // WinSetWindowPos() does not correctly update involved windows.
650 // The fix is to do it ourselves, taking clip regions into account.
651 // set new and old rectangles
652 const RECTL rcls [2] = {
653 // new (relative to parent)
654 { swpNew.x, swpNew.y, swpNew.x + swpNew.cx, swpNew.y + swpNew.cy },
655 // old (relative to parent)
656 { swpOld.x, swpOld.y, swpOld.x + swpOld.cx, swpOld.y + swpOld.cy }
657 };
658 const RECTL &rclNew = rcls [0];
659 const RECTL &rclOld = rcls [1];
660 // delta to shift coordinate space from parent to this widget
661 POINTL ptlToSelf = { -swpNew.x, -swpNew.y };
662 // use parent PS for blitting
663 HPS hps = WinGetPS(hwndParent);
664 // get old and new clip regions (relative to parent)
665 HRGN hrgnOld = GpiCreateRegion(hps, 1, &rclOld);
666 HRGN hrgnNew = GpiCreateRegion(hps, 1, &rclNew);
667 if (WinQueryClipRegion(hwnd, 0) != QCRGN_NO_CLIP_REGION) {
668 HRGN hrgnTemp = GpiCreateRegion(hps, 0, NULL);
669 // old (clipped to the old rect)
670 WinQueryClipRegion(hwnd, hrgnTemp);
671 GpiOffsetRegion(hps, hrgnTemp, (PPOINTL) &rclOld);
672 GpiCombineRegion(hps, hrgnOld, hrgnTemp, hrgnOld, CRGN_AND);
673 // new (clipped to the new rect)
674 WinQueryClipRegion(hwnd, hrgnTemp);
675 if (swpOld.cy != swpNew.cy) {
676 // keep the clip region top-left aligned by adding the
677 // height delta (new size - old size)
678 POINTL ptl = {0, swpNew.cy - swpOld.cy };
679 GpiOffsetRegion(hps, hrgnTemp, &ptl);
680 WinSetClipRegion(hwnd, hrgnTemp);
681 }
682 GpiOffsetRegion(hps, hrgnTemp, (PPOINTL) &rclNew);
683 GpiCombineRegion(hps, hrgnNew, hrgnTemp, hrgnNew, CRGN_AND);
684 GpiDestroyRegion(hps, hrgnTemp);
685 }
686 // the rest is useful only when the widget is visible
687 if (swpNew.fl & SWP_SHOW) {
688 // create affected region (old + new, relative to widget)
689 HRGN hrgnAff = GpiCreateRegion(hps, 0, NULL);
690 GpiCombineRegion(hps, hrgnAff, hrgnOld, hrgnNew, CRGN_OR);
691 GpiOffsetRegion(hps, hrgnAff, &ptlToSelf);
692 // get bounding rectangle of affected region
693 RECTL rclAff;
694 GpiQueryRegionBox(hps, hrgnAff, &rclAff);
695 // get region of obstacles limited to affected rectangle
696 HRGN hrgnObst = GpiCreateRegion(hps, 0, NULL);
697 qt_WinProcessWindowObstacles(hwnd, &rclAff, hrgnObst, CRGN_OR,
698 PWO_Sibings | PWO_Ancestors |
699 PWO_Screen | PWO_TopLevel);
700 // shift region of obstacles and affected region back to
701 // parent coords
702 GpiOffsetRegion(hps, hrgnObst, (PPOINTL) &rclNew);
703 GpiOffsetRegion(hps, hrgnAff, (PPOINTL) &rclNew);
704 // get parent bounds (clip region or rect)
705 HRGN hrgnUpd = GpiCreateRegion(hps, 0, NULL);
706 qt_WinQueryClipRegionOrRect(hwndParent, hrgnUpd);
707 // add parts of old region beyond parent bounds to
708 // region of obstacles
709 GpiCombineRegion(hps, hrgnOld, hrgnOld, hrgnUpd, CRGN_DIFF);
710 GpiCombineRegion(hps, hrgnObst, hrgnObst, hrgnOld, CRGN_OR);
711 // substract region of obstacles from affected region
712 GpiCombineRegion(hps, hrgnAff, hrgnAff, hrgnObst, CRGN_DIFF);
713 // remember it as parent update region (need later)
714 GpiCombineRegion(hps, hrgnUpd, hrgnAff, 0, CRGN_COPY);
715 // copy region of obstacles to delta region and shift it by
716 // delta (note: movement is considered to be top-left aligned)
717 HRGN hrgnDelta = GpiCreateRegion(hps, 0, NULL);
718 GpiCombineRegion(hps, hrgnDelta, hrgnObst, 0, CRGN_COPY);
719 POINTL ptlDelta = { rclNew.xLeft - rclOld.xLeft,
720 rclNew.yTop - rclOld.yTop };
721 GpiOffsetRegion(hps, hrgnDelta, &ptlDelta);
722 // substract region of obstacles from delta region to get
723 // pure delta
724 GpiCombineRegion(hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF);
725 // calculate minimal rectangle to blit (top-left aligned)
726 int minw = qMin(swpOld.cx, swpNew.cx);
727 int minh = qMin(swpOld.cy, swpNew.cy);
728 POINTL blitPtls [4] = {
729 // target (new)
730 { rclNew.xLeft, rclNew.yTop - minh },
731 { rclNew.xLeft + minw, rclNew.yTop },
732 // source (old)
733 { rclOld.xLeft, rclOld.yTop - minh },
734 };
735 // proceed with blitting only if target and source rects differ
736 if (blitPtls[0].x != blitPtls[2].x ||
737 blitPtls[0].y != blitPtls[2].y)
738 {
739 // Substract delta region from affected region (to minimize
740 // flicker)
741 GpiCombineRegion(hps, hrgnAff, hrgnAff, hrgnDelta, CRGN_DIFF);
742 // set affected region to parent PS
743 GpiSetClipRegion(hps, hrgnAff, NULL);
744 // blit minimal rectangle
745 GpiBitBlt(hps, hps, 3, blitPtls, ROP_SRCCOPY, BBO_IGNORE);
746 GpiSetClipRegion(hps, 0, NULL);
747 }
748 // substract new widget region from the parent update region
749 // and invalidate it (with underlying children)
750 GpiCombineRegion(hps, hrgnUpd, hrgnUpd, hrgnNew, CRGN_DIFF );
751 qt_WinInvalidateRegionEx(hwndParent, hrgnUpd,
752 WinQueryWindow(hwnd, QW_NEXT),
753 HWND_BOTTOM);
754 // intersect pure delta region with new region
755 // (to detect areas clipped off to minimize flicker when blitting)
756 GpiCombineRegion(hps, hrgnDelta, hrgnDelta, hrgnNew, CRGN_AND);
757 // substract blitted rectangle from new region
758 GpiSetRegion(hps, hrgnAff, 1, (PRECTL) &blitPtls);
759 GpiCombineRegion(hps, hrgnNew, hrgnNew, hrgnAff, CRGN_DIFF);
760 // combine the rest with intersected delta region
761 GpiCombineRegion(hps, hrgnNew, hrgnNew, hrgnDelta, CRGN_OR);
762 // shift the result back to widget coords and invalidate
763 GpiOffsetRegion(hps, hrgnNew, &ptlToSelf);
764 WinInvalidateRegion(hwnd, hrgnNew, TRUE);
765 // free resources
766 GpiDestroyRegion(hps, hrgnDelta);
767 GpiDestroyRegion(hps, hrgnUpd);
768 GpiDestroyRegion(hps, hrgnObst);
769 GpiDestroyRegion(hps, hrgnAff);
770 }
771 // free resources
772 GpiDestroyRegion(hps, hrgnOld);
773 GpiDestroyRegion(hps, hrgnNew);
774 WinReleasePS(hps);
775 }
776 }
777
778 GpiDestroyRegion(hps, hrgnSelf);
779
780 return TRUE;
781}
782
783/*!
784 \internal
785
786 Helper function to extract regions of all windows that overlap the given
787 hwnd subject to their z-order (excluding children of hwnd) from the given
788 hrgn. hps is the presentation space of hrgn.
789 */
790void qt_WinExcludeOverlappingWindows(HWND hwnd, HPS hps, HRGN hrgn)
791{
792 HRGN vr = GpiCreateRegion(hps, 0, NULL);
793 RECTL r;
794
795 // enumerate all windows that are on top of this hwnd
796 HWND id = hwnd, deskId = QApplication::desktop()->winId();
797 do {
798 HWND i = id;
799 while((i = WinQueryWindow( i, QW_PREV ))) {
800 if (WinIsWindowVisible(i)) {
801 WinQueryWindowRect(i, &r);
802 WinMapWindowPoints(i, hwnd, (PPOINTL) &r, 2);
803 GpiSetRegion(hps, vr, 1, &r);
804 GpiCombineRegion(hps, hrgn, hrgn, vr, CRGN_DIFF);
805 }
806 }
807 id = WinQueryWindow(id, QW_PARENT);
808 } while(id != deskId);
809
810 GpiDestroyRegion(hps, vr);
811}
812
813/*!
814 \internal
815
816 Helper function to scroll window contents. WinScrollWindow() is a bit
817 buggy and corrupts update regions sometimes (which leaves some outdated
818 areas unpainted after scrolling), so we reimplement its functionality in
819 this function. dy and clip->yBottom/yTop should be GPI coordinates, not Qt.
820 all clip coordinates are inclusive.
821 */
822void qt_WinScrollWindowWell(HWND hwnd, LONG dx, LONG dy, const PRECTL clip = NULL)
823{
824 WinLockVisRegions(HWND_DESKTOP, TRUE);
825
826 HPS lhps = WinGetClipPS(hwnd, HWND_TOP,
827 PSF_LOCKWINDOWUPDATE | PSF_CLIPSIBLINGS);
828 if (clip)
829 GpiIntersectClipRectangle(lhps, clip);
830
831 // remember the update region and validate it. it will be shifted and
832 // invalidated again later
833 HRGN update = GpiCreateRegion(lhps, 0, NULL);
834 WinQueryUpdateRegion(hwnd, update);
835 WinValidateRegion(hwnd, update, TRUE);
836
837 POINTL ptls[4];
838 RECTL &sr = *(PRECTL) &ptls[2];
839 RECTL &tr = *(PRECTL) &ptls[0];
840
841 // get the source rect for scrolling
842 GpiQueryClipBox(lhps, &sr);
843 sr.xRight++; sr.yTop++; // inclusive -> exclusive
844
845 // get the visible region ignoring areas covered by children
846 HRGN visible = GpiCreateRegion(lhps, 1, &sr);
847 qt_WinExcludeOverlappingWindows(hwnd, lhps, visible);
848
849 // scroll visible region rectangles separately to avoid the flicker
850 // that could be produced by scrolling parts of overlapping windows
851 RGNRECT ctl;
852 ctl.ircStart = 1;
853 ctl.crc = 0;
854 ctl.crcReturned = 0;
855 if (dx >= 0) {
856 if (dy >= 0) ctl.ulDirection = RECTDIR_RTLF_TOPBOT;
857 else ctl.ulDirection = RECTDIR_RTLF_BOTTOP;
858 } else {
859 if (dy >= 0) ctl.ulDirection = RECTDIR_LFRT_TOPBOT;
860 else ctl.ulDirection = RECTDIR_LFRT_BOTTOP;
861 }
862 GpiQueryRegionRects(lhps, visible, NULL, &ctl, NULL);
863 ctl.crc = ctl.crcReturned;
864 int rclcnt = ctl.crcReturned;
865 PRECTL rcls = new RECTL[rclcnt];
866 GpiQueryRegionRects(lhps, visible, NULL, &ctl, rcls);
867 PRECTL r = rcls;
868 for (int i = 0; i < rclcnt; i++, r++) {
869 // source rect
870 sr = *r;
871 // target rect
872 tr.xLeft = sr.xLeft + dx;
873 tr.xRight = sr.xRight + dx;
874 tr.yBottom = sr.yBottom + dy;
875 tr.yTop = sr.yTop + dy;
876 GpiBitBlt(lhps, lhps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE);
877 }
878 delete [] rcls;
879
880 // make the scrolled version of the visible region
881 HRGN scrolled = GpiCreateRegion(lhps, 0, NULL);
882 GpiCombineRegion(lhps, scrolled, visible, 0, CRGN_COPY);
883 // invalidate the initial update region
884 GpiCombineRegion(lhps, scrolled, scrolled, update, CRGN_DIFF);
885 // shift the region
886 POINTL dp = { dx, dy };
887 GpiOffsetRegion(lhps, scrolled, &dp);
888 // substract scrolled from visible to get invalid areas
889 GpiCombineRegion(lhps, scrolled, visible, scrolled, CRGN_DIFF);
890
891 WinInvalidateRegion(hwnd, scrolled, TRUE);
892
893 GpiDestroyRegion(lhps, scrolled);
894 GpiDestroyRegion(lhps, visible);
895 GpiDestroyRegion(lhps, update);
896
897 WinReleasePS(lhps);
898
899 WinLockVisRegions(HWND_DESKTOP, FALSE);
900
901 WinUpdateWindow(hwnd);
902}
903
904/*!
905 * \internal
906 * For some unknown reason, PM sends WM_SAVEAPPLICATION to every window
907 * being destroyed, which makes it indistinguishable from WM_SAVEAPPLICATION
908 * sent to top level windows during system shutdown. We use our own version of
909 * WinDestroyWindow() and a special flag (qt_about_to_destroy_wnd) to
910 * distinguish it in qapplication_pm.cpp.
911 */
912static BOOL qt_WinDestroyWindow(HWND hwnd)
913{
914#if !defined(QT_NO_SESSIONMANAGER)
915 qt_about_to_destroy_wnd = true;
916#endif
917 BOOL rc = WinDestroyWindow(hwnd);
918#if !defined(QT_NO_SESSIONMANAGER)
919 qt_about_to_destroy_wnd = false;
920#endif
921 return rc;
922}
923
924static PFNWP QtOldSysMenuProc;
925static MRESULT EXPENTRY QtSysMenuProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
926{
927 if (msg == WM_MENUEND) {
928 // the pull-down menu is closed, always dismiss the system menu itself
929 WinPostMsg(hwnd, MM_ENDMENUMODE, MPFROMSHORT(TRUE), 0);
930 }
931 return QtOldSysMenuProc(hwnd, msg, mp1, mp2);
932}
933
934static void removeSysMenuAccels(HWND frame)
935{
936 HWND sysMenu = WinWindowFromID(frame, FID_SYSMENU);
937 if (!sysMenu)
938 return;
939
940 SHORT subId = SHORT1FROMMR(WinSendMsg(sysMenu, MM_ITEMIDFROMPOSITION, 0, 0));
941 if (subId != MIT_ERROR) {
942 MENUITEM item;
943 WinSendMsg(sysMenu, MM_QUERYITEM, MPFROM2SHORT(subId, FALSE), MPFROMP(&item));
944 HWND subMenu = item.hwndSubMenu;
945 if (subMenu) {
946 USHORT cnt = SHORT1FROMMR(WinSendMsg(subMenu, MM_QUERYITEMCOUNT, 0, 0));
947 for (int i = 0; i < cnt; i++) {
948 USHORT id = SHORT1FROMMR(
949 WinSendMsg(subMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(i), 0));
950 if (id == SC_TASKMANAGER || id == SC_CLOSE) {
951 // accels for these entries always work in Qt, skip them
952 continue;
953 }
954 USHORT len = SHORT1FROMMR(
955 WinSendMsg(subMenu, MM_QUERYITEMTEXTLENGTH, MPFROMSHORT(id), 0));
956 if (len++) {
957 char *text = new char[len];
958 WinSendMsg(subMenu, MM_QUERYITEMTEXT,
959 MPFROM2SHORT(id, len), MPFROMP(text));
960 char *tab = strrchr(text, '\t');
961 if (tab) {
962 *tab = 0;
963 WinSendMsg(subMenu, MM_SETITEMTEXT,
964 MPFROMSHORT(id), MPFROMP(text));
965 }
966 delete[] text;
967 }
968 }
969 // sublclass the system menu to leave the menu mode completely
970 // when the user presses the ESC key. by default, pressing ESC
971 // while the pull-down menu is showing brings us to the menu bar,
972 // which is confusing in the case of the system menu, because
973 // there is only one item on the menu bar, and we cannot see
974 // that it is active when the frame window has an icon.
975 PFNWP oldProc = WinSubclassWindow(sysMenu, QtSysMenuProc);
976 // set QtOldSysMenuProc only once: it must be the same for
977 // all FID_SYSMENU windows.
978 if (!QtOldSysMenuProc)
979 QtOldSysMenuProc = oldProc;
980 }
981 }
982}
983
984/*****************************************************************************
985 QWidget member functions
986 *****************************************************************************/
987
988void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
989{
990 // @todo when window is not zero, it represents an existing (external)
991 // window handle we should create a QWidget "wrapper" for to incorporate it
992 // to the Qt widget hierarchy. This functionality isn't really necessary on
993 // OS/2 at the moment, so it is not currently supported (and the window
994 // argument is simply ignored). Note that destroyOldWindow only makes
995 // sense when window is != 0 so it is also ignored.
996
997 Q_ASSERT(window == 0);
998 Q_UNUSED(destroyOldWindow);
999
1000 Q_Q(QWidget);
1001 static int sw = -1, sh = -1;
1002
1003 Qt::WindowType type = q->windowType();
1004 Qt::WindowFlags flags = data.window_flags;
1005
1006 bool topLevel = q->isWindow();
1007 bool popup = (type == Qt::Popup);
1008 bool dialog = (type == Qt::Dialog
1009 || type == Qt::Sheet
1010 || (flags & Qt::MSWindowsFixedSizeDialogHint));
1011 bool desktop = (type == Qt::Desktop);
1012 bool tool = (type == Qt::Tool || type == Qt::Drawer);
1013
1014 WId id;
1015
1016 QByteArray className = qt_reg_winclass(q).toLatin1();
1017
1018 // @todo WindowStaysOnTopHint is ignored for now (does nothing)
1019 if (popup)
1020 flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
1021
1022 if (sw < 0) { // get the screen size
1023 sw = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
1024 sh = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
1025 }
1026
1027 if (desktop && !q->testAttribute(Qt::WA_DontShowOnScreen)) { // desktop widget
1028 popup = false; // force this flags off
1029 // @todo use WinGetMaxPosition to take such things as XCenter into account?
1030 data.crect.setRect(0, 0, sw, sh);
1031 }
1032
1033 QByteArray title;
1034 ULONG style = 0;
1035 ULONG fId = 0, fStyle = 0, fcFlags = 0;
1036
1037 if (!desktop) {
1038 // @todo testing for Qt::WA_PaintUnclipped is commented out because it
1039 // is said that it causes some problems on Win32 and we also saw the
1040 // problems with this line enabled in Qt3 on OS/2 in QT_PM_NO_WIDGETMASK
1041 // mode (terrible flicker in QFileDialog because QSplitter used there
1042 // sets WA_PaintUnclipped). This however doesn't make a big difference
1043 // now since we don't support QT_PM_NO_WIDGETMASK anymore (read below
1044 // about clipping) and is left here just to show where WA_PaintUnclipped
1045 // was originally intended to be used.
1046#if 0
1047 if (!testAttribute(Qt::WA_PaintUnclipped))
1048#endif
1049 {
1050 // We don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN because when these
1051 // styles are set and the child (sibling) window has a non-NULL clip region,
1052 // PM still continues to exclude the entire child's rectangle from the
1053 // parent window's update region, ignoring its clip region. As a result,
1054 // areas outside the clip region are left unpainted. Instead, we correct
1055 // the update region of the window ourselves, on every WM_PAINT event.
1056 // Note: for top-level widgets, we specify WS_CLIPSIBLINGS anyway to let
1057 // the system do correct clipping for us (qt_WinProcessWindowObstacles()
1058 // relies on this). It's ok because top-level widgets cannot be non-
1059 // rectangular and therefore don't require our magic clipping procedure.
1060 if (topLevel)
1061 style |= WS_CLIPSIBLINGS;
1062 }
1063
1064 // for all top-level windows except popups we create a WC_FRAME
1065 // as a parent and owner.
1066 if (topLevel && !popup) {
1067 if ((type == Qt::Window || dialog || tool)) {
1068 if (!(flags & Qt::FramelessWindowHint)) {
1069 if (flags & Qt::MSWindowsFixedSizeDialogHint) {
1070 fcFlags |= FCF_DLGBORDER;
1071 } else if (tool) {
1072 // note: while it's common that top-level tool widgets
1073 // have a thiner frame, FCF_BORDER makes it too thin and
1074 // it even cannot be resized. So, use FCF_SIZEBORDER too.
1075 fcFlags |= FCF_SIZEBORDER;
1076 } else {
1077 fcFlags |= FCF_SIZEBORDER;
1078 }
1079 }
1080 if (flags & Qt::WindowTitleHint)
1081 fcFlags |= FCF_TITLEBAR;
1082 if (flags & Qt::WindowSystemMenuHint)
1083 fcFlags |= FCF_SYSMENU | FCF_CLOSEBUTTON;
1084 if (flags & Qt::WindowMinimizeButtonHint)
1085 fcFlags |= FCF_MINBUTTON;
1086 if (flags & Qt::WindowMaximizeButtonHint)
1087 fcFlags |= FCF_MAXBUTTON;
1088 } else {
1089 fcFlags |= FCF_BORDER;
1090 }
1091
1092 fStyle |= FS_NOMOVEWITHOWNER | FS_NOBYTEALIGN;
1093 fStyle |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
1094 }
1095 }
1096
1097 if (flags & Qt::WindowTitleHint) {
1098 QString t = topLevel ? qAppName() : q->objectName();
1099 t = t.left(1).toUpper() + t.mid(1).toLower();
1100 title = t.toLocal8Bit();
1101 }
1102
1103 // The Qt::WA_WState_Created flag is checked by translateConfigEvent() in
1104 // qapplication_pm.cpp. We switch it off temporarily to avoid move
1105 // and resize events during creation
1106 q->setAttribute(Qt::WA_WState_Created, false);
1107
1108 if (desktop) { // desktop widget
1109 id = WinQueryDesktopWindow(0, 0);
1110 // @todo commented out on Win32 too
1111// QWidget *otherDesktop = QWidget::find(id); // is there another desktop?
1112// if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) {
1113// otherDesktop->d_func()->setWinId(0); // remove id from widget mapper
1114// setWinId(id); // make sure otherDesktop is found first
1115// otherDesktop->d_func()->setWinId(id);
1116// } else {
1117 setWinId(id);
1118// }
1119 } else if (topLevel) {
1120 // create top-level widget
1121 if (!popup) {
1122 HWND ownerw = NULLHANDLE;
1123 QWidget *parent = q->parentWidget();
1124
1125 if (parent && !(parent->windowType() == Qt::Desktop))
1126 ownerw = parent->window()->d_func()->frameWinId();
1127 // create WC_FRAME
1128 FRAMECDATA fcData;
1129 fcData.cb = sizeof(FRAMECDATA);
1130 fcData.flCreateFlags = fcFlags;
1131 fcData.hmodResources = NULL;
1132 fcData.idResources = 0;
1133 // check whether a default icon is present in .EXE and use it if so
1134 ULONG sz = 0;
1135 if (DosQueryResourceSize(NULL, RT_POINTER, 1, &sz) == 0) {
1136 fcData.flCreateFlags |= FCF_ICON;
1137 fcData.idResources = 1;
1138 }
1139#if defined(QT_DEBUGWINCREATEDESTROY)
1140 qDebug("|Creating top level window (frame) [%s]:\n"
1141 "| owner = %08lX\n"
1142 "| title = '%s'\n"
1143 "| style = %08lX\n"
1144 "| fcFlags = %08lX",
1145 qWidgetName(q).toUtf8().constData(), ownerw,
1146 title.constData(), fStyle, fcFlags);
1147#endif
1148 fId = WinCreateWindow(HWND_DESKTOP, WC_FRAME, title, fStyle,
1149 0, 0, 0, 0, ownerw, HWND_TOP, 0,
1150 &fcData, NULL);
1151#if defined(QT_DEBUGWINCREATEDESTROY)
1152 qDebug("| hwnd = %08lX", fId);
1153#endif
1154 if (fId == NULLHANDLE)
1155 qWarning("QWidget::create(): WinCreateWindow(WC_FRAME) "
1156 "failed with 0x%08lX", WinGetLastError(0));
1157
1158 if (fcData.flCreateFlags & FCF_ICON) {
1159 // mark that we already have the window icon taken from .EXE to
1160 // prevent setWindowIcon_sys() from resetting it to nothing
1161 createTLExtra();
1162 extra->topextra->iconPointer =
1163 (HPOINTER)WinSendMsg(fId, WM_QUERYICON, 0, 0);
1164 }
1165
1166 PFNWP oldProc = WinSubclassWindow(fId, QtFrameProc);
1167 // remember QtOldFrameProc only once: it's the same for
1168 // all WC_FRAME windows.
1169 if (!QtOldFrameProc)
1170 QtOldFrameProc = oldProc;
1171
1172 // subclass all standard frame controls to get non-client mouse events
1173 // (note: the size of the ctls array must match QtOldFrameCtlProcs)
1174 HWND ctls[FID_HORZSCROLL - FID_SYSMENU + 1];
1175 if (WinMultWindowFromIDs(fId, ctls, FID_SYSMENU, FID_HORZSCROLL) > 0) {
1176 for (size_t i = 0; i < sizeof(ctls)/sizeof(ctls[0]); ++i) {
1177 if (ctls[i] != NULLHANDLE) {
1178 oldProc = WinSubclassWindow(ctls[i], QtFrameCtlProc);
1179 // remember the old proc only once: it's the same for
1180 // all standard frame control windows.
1181 if (!QtOldFrameCtlProcs[i])
1182 QtOldFrameCtlProcs[i] = oldProc;
1183 }
1184 }
1185 }
1186
1187 removeSysMenuAccels(fId);
1188
1189 // create client window
1190#if defined(QT_DEBUGWINCREATEDESTROY)
1191 qDebug("|Creating top level window (client) [%s]:\n"
1192 "| owner & parent = %08lX\n"
1193 "| class = '%s'\n"
1194 "| title = '%s'\n"
1195 "| style = %08lX",
1196 qWidgetName(q).toUtf8().constData(), fId, className.constData(),
1197 title.constData(), style);
1198#endif
1199 // note that we place the client on top (HWND_TOP) to exclude other
1200 // frame controls from being analyzed in qt_WinProcessWindowObstacles
1201 id = WinCreateWindow(fId, className, title, style, 0, 0, 0, 0,
1202 fId, HWND_TOP, FID_CLIENT, NULL, NULL);
1203 } else {
1204#if defined(QT_DEBUGWINCREATEDESTROY)
1205 qDebug("|Creating top level window (popup) [%s]:\n"
1206 "| class = '%s'\n"
1207 "| title = '%s'\n"
1208 "| style = %08lX",
1209 qWidgetName(q).toUtf8().constData(), className.constData(),
1210 title.constData(), style);
1211#endif
1212 id = WinCreateWindow(HWND_DESKTOP, className, title, style,
1213 0, 0, 0, 0, NULLHANDLE, HWND_TOP, 0, NULL, NULL);
1214 }
1215#if defined(QT_DEBUGWINCREATEDESTROY)
1216 qDebug("| hwnd = %08lX", id);
1217#endif
1218 if (id == NULLHANDLE)
1219 qWarning("QWidget::create(): WinCreateWindow "
1220 "failed with 0x%08lX", WinGetLastError(0));
1221 setWinId(id);
1222
1223 // it isn't mentioned in PMREF that PM is obliged to initialize window
1224 // data with zeroes (although seems to), so do it ourselves
1225 for (LONG i = 0; i <= (LONG) (QT_EXTRAWINDATASIZE - 4); i += 4)
1226 WinSetWindowULong(id, i, 0);
1227
1228 SWP swp;
1229 // Get the default window position and size. Note that when the
1230 // FS_SHELLPOSITION flag is specified during WC_FRAME window
1231 // creation its size and position remains zero until it is shown
1232 // for the first time. So, we don't use FS_SHELLPOSITION but emulate
1233 // its functionality here.
1234 WinQueryTaskSizePos(0, 0, &swp);
1235
1236 // update position & initial size of POPUP window
1237 const bool wasMoved = q->testAttribute(Qt::WA_Moved);
1238 const bool wasResized = q->testAttribute(Qt::WA_Resized);
1239 const bool isVisibleOnScreen = !q->testAttribute(Qt::WA_DontShowOnScreen);
1240 if (popup && initializeWindow && isVisibleOnScreen) {
1241 if (!wasResized) {
1242 swp.cx = sw / 2;
1243 swp.cy = 4 * sh / 10;
1244 } else {
1245 swp.cx = data.crect.width();
1246 swp.cy = data.crect.height();
1247 }
1248 if (!wasMoved) {
1249 swp.x = sw / 2 - swp.cx / 2;
1250 swp.y = sh / 2 - swp.cy / 2;
1251 } else {
1252 swp.x = data.crect.x();
1253 swp.y = data.crect.y();
1254 // flip y coordinate
1255 swp.y = sh - (swp.y + swp.cy);
1256 }
1257 }
1258
1259 ULONG fl = SWP_SIZE | SWP_MOVE;
1260 HWND insertBehind = NULLHANDLE;
1261 if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) {
1262 insertBehind = HWND_TOP;
1263 fl |= SWP_ZORDER;
1264 if (flags & Qt::WindowStaysOnBottomHint)
1265 qWarning() << "QWidget: Incompatible window flags: the window "
1266 "can't be on top and on bottom at the same time";
1267 } else if (flags & Qt::WindowStaysOnBottomHint) {
1268 insertBehind = HWND_BOTTOM;
1269 fl |= SWP_ZORDER;
1270 }
1271 WinSetWindowPos(popup ? id : fId, insertBehind,
1272 swp.x, swp.y, swp.cx, swp.cy, fl);
1273
1274 if (!popup) {
1275 QTLWExtra *top = topData();
1276 top->fId = fId;
1277 WinQueryWindowPos(fId, &swp);
1278 SWP cswp;
1279 WinQueryWindowPos(id, &cswp);
1280 // flip y coordinates
1281 swp.y = sh - (swp.y + swp.cy);
1282 cswp.y = swp.cy - (cswp.y + cswp.cy);
1283 // store frame dimensions
1284 QRect &fs = top->frameStrut;
1285 fs.setCoords(cswp.x, cswp.y, swp.cx - cswp.x - cswp.cx,
1286 swp.cy - cswp.y - cswp.cy);
1287 data.fstrut_dirty = false;
1288 if (wasMoved || wasResized) {
1289 // resize & move if necessary (we couldn't do it earlier
1290 // because we didn't know the frame dimensions yet)
1291 if (wasMoved) {
1292 // QWidget::move() includes frame strut so no correction is
1293 // necessary (crect was abused to store the frame position
1294 // until window creation)
1295 swp.x = data.crect.x();
1296 swp.y = data.crect.y();
1297 }
1298 if (wasResized) {
1299 swp.cx = data.crect.width() + fs.left() + fs.right();
1300 swp.cy = data.crect.height() + fs.top() + fs.bottom();
1301 }
1302 // flip y coordinate
1303 swp.y = sh - (swp.y + swp.cy);
1304 WinSetWindowPos(fId, NULLHANDLE, swp.x, swp.y, swp.cx, swp.cy,
1305 SWP_SIZE | SWP_MOVE);
1306 }
1307 }
1308
1309 if (!popup || (initializeWindow && isVisibleOnScreen)) {
1310 // fetch the actual geometry
1311 WinQueryWindowPos(popup ? id : fId, &swp);
1312 // flip y coordinate
1313 swp.y = sh - (swp.y + swp.cy);
1314 if (popup) {
1315 data.crect.setRect(swp.x, swp.y, swp.cx, swp.cy);
1316 } else {
1317 const QRect &fs = topData()->frameStrut;
1318 data.crect.setRect(swp.x + fs.left(), swp.y + fs.top(),
1319 swp.cx - fs.left() - fs.right(),
1320 swp.cy - fs.top() - fs.bottom());
1321 }
1322 }
1323 } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) {
1324 // create child widget
1325 Q_ASSERT(q->parentWidget());
1326 HWND parentw = q->parentWidget()->effectiveWinId();
1327
1328#if defined(QT_DEBUGWINCREATEDESTROY)
1329 qDebug("|Creating child window [%s]:\n"
1330 "| owner & parent = %08lX\n"
1331 "| class = '%s'\n"
1332 "| title = '%s'\n"
1333 "| style = %08lX",
1334 qWidgetName(q).toUtf8().constData(), parentw, className.constData(),
1335 title.constData(), style);
1336#endif
1337 id = WinCreateWindow(parentw, className, title, style,
1338 data.crect.left(),
1339 // flip y coordinate
1340 q->parentWidget()->height() - data.crect.bottom() - 1,
1341 data.crect.width(), data.crect.height(),
1342 parentw, HWND_TOP, 0, NULL, NULL);
1343#if defined(QT_DEBUGWINCREATEDESTROY)
1344 qDebug("| hwnd = %08lX", id);
1345#endif
1346 if (id == NULLHANDLE)
1347 qWarning("QWidget::create(): WinCreateWindow "
1348 "failed with 0x%08lX", WinGetLastError(0));
1349 setWinId(id);
1350 }
1351
1352 if (desktop) {
1353 q->setAttribute(Qt::WA_WState_Visible);
1354 }
1355
1356 q->setAttribute(Qt::WA_WState_Created); // accept move/resize events
1357
1358 hd = 0; // no presentation space
1359
1360 if (extra && !extra->mask.isEmpty())
1361 setMask_sys(extra->mask);
1362
1363 if (topLevel && (data.crect.width() == 0 || data.crect.height() == 0)) {
1364 q->setAttribute(Qt::WA_OutsideWSRange, true);
1365 }
1366
1367 if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) {
1368 Q_ASSERT(q->internalWinId() != NULLHANDLE);
1369 WinShowWindow(q->internalWinId(), TRUE);
1370 }
1371}
1372
1373void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1374{
1375 Q_D(QWidget);
1376 if (!isWindow() && parentWidget())
1377 parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
1378 d->deactivateWidgetCleanup();
1379 if (testAttribute(Qt::WA_WState_Created)) {
1380 setAttribute(Qt::WA_WState_Created, false);
1381 for(int i = 0; i < d->children.size(); ++i) { // destroy all widget children
1382 register QObject *obj = d->children.at(i);
1383 if (obj->isWidgetType())
1384 ((QWidget*)obj)->destroy(destroySubWindows,
1385 destroySubWindows);
1386 }
1387 if (mouseGrb == this)
1388 releaseMouse();
1389 if (keyboardGrb == this)
1390 releaseKeyboard();
1391 if (testAttribute(Qt::WA_ShowModal)) // just be sure we leave modal
1392 QApplicationPrivate::leaveModal(this);
1393 else if ((windowType() == Qt::Popup))
1394 qApp->d_func()->closePopup(this);
1395 if (destroyWindow && !(windowType() == Qt::Desktop) &&
1396 internalWinId() != NULLHANDLE) {
1397 HWND id = internalWinId();
1398 if (isWindow() && !(windowType() == Qt::Popup)) {
1399 // extra data including extra->topextra has been already
1400 // deleted at this point by deleteExtra() and therefore
1401 // calling frameWinId() is useless -- it will return the
1402 // client window handle. Use WinQueryWindow() instead.
1403 id = WinQueryWindow(id, QW_PARENT);
1404 Q_ASSERT(id != NULLHANDLE);
1405 }
1406#if defined(QT_DEBUGWINCREATEDESTROY)
1407 qDebug("|Destroying window [%s]:\n"
1408 "| hwnd = %08lX", qWidgetName(this).toUtf8().constData(), id);
1409#endif
1410
1411 qt_WinDestroyWindow(id);
1412 }
1413 QT_TRY {
1414 d->setWinId(0);
1415 } QT_CATCH (const std::bad_alloc &) {
1416 // swallow - destructors must not throw
1417 }
1418 }
1419}
1420
1421void QWidgetPrivate::reparentChildren()
1422{
1423 Q_Q(QWidget);
1424 QObjectList chlist = q->children();
1425 for (int i = 0; i < chlist.size(); ++i) { // reparent children
1426 QObject *obj = chlist.at(i);
1427 if (obj->isWidgetType()) {
1428 QWidget *w = (QWidget *)obj;
1429 if ((w->windowType() == Qt::Popup)) {
1430 ;
1431 } else if (w->isWindow()) {
1432 bool showIt = w->isVisible();
1433 QPoint old_pos = w->pos();
1434 w->setParent(q, w->windowFlags());
1435 w->move(old_pos);
1436 if (showIt)
1437 w->show();
1438 } else {
1439 w->d_func()->invalidateBuffer(w->rect());
1440 WinSetParent(w->effectiveWinId(), q->effectiveWinId(), FALSE);
1441 WinSetOwner(w->effectiveWinId(), q->effectiveWinId());
1442 w->d_func()->reparentChildren();
1443#if 0 // @todo check if this is really necessary any longer
1444 // bring PM coords into accordance with Qt coords,
1445 // otherwise setGeometry() below will wrongly position
1446 // children if this widget manages their layout.
1447 SWP swp;
1448 int hd = q->height() - old_height;
1449 WinQueryWindowPos(w->effectiveWinId(), &swp);
1450 swp.y += hd;
1451 WinSetWindowPos(w->effectiveWinId(), 0, swp.x, swp.y, 0, 0, SWP_MOVE);
1452#endif
1453 }
1454 }
1455 }
1456}
1457
1458void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
1459{
1460 Q_Q(QWidget);
1461 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
1462 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
1463 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
1464
1465 WId old_fid = frameWinId();
1466
1467 // hide and reparent our own window away. Otherwise we might get
1468 // destroyed when emitting the child remove event below. See QWorkspace.
1469 if (q->isVisible() && old_fid != NULLHANDLE) {
1470 qt_WinSetWindowPos(old_fid, 0, 0, 0, 0, 0, SWP_HIDE);
1471 WinSetParent(old_fid, HWND_OBJECT, FALSE);
1472 WinSetOwner(old_fid, NULLHANDLE);
1473 }
1474 bool dropSiteWasRegistered = false;
1475 if (q->testAttribute(Qt::WA_DropSiteRegistered)) {
1476 dropSiteWasRegistered = true;
1477 q->setAttribute(Qt::WA_DropSiteRegistered, false); // ole dnd unregister (we will register again below)
1478 }
1479
1480 if ((q->windowType() == Qt::Desktop))
1481 old_fid = NULLHANDLE;
1482 setWinId(0);
1483
1484 QObjectPrivate::setParent_helper(parent);
1485 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
1486
1487 data.window_flags = f;
1488 data.fstrut_dirty = true;
1489 q->setAttribute(Qt::WA_WState_Created, false);
1490 q->setAttribute(Qt::WA_WState_Visible, false);
1491 q->setAttribute(Qt::WA_WState_Hidden, false);
1492 adjustFlags(data.window_flags, q);
1493 // keep compatibility with previous versions, we need to preserve the created state
1494 // (but we recreate the winId for the widget being reparented, again for compatibility)
1495 if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created)))
1496 createWinId();
1497 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
1498 q->setAttribute(Qt::WA_WState_Hidden);
1499 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
1500
1501 if (wasCreated) {
1502 reparentChildren();
1503 }
1504
1505 if (extra && !extra->mask.isEmpty()) {
1506 QRegion r = extra->mask;
1507 extra->mask = QRegion();
1508 q->setMask(r);
1509 }
1510 if (extra && extra->topextra && !extra->topextra->caption.isEmpty()) {
1511 setWindowIcon_sys(true);
1512 setWindowTitle_helper(extra->topextra->caption);
1513 }
1514 if (old_fid != NULLHANDLE)
1515 qt_WinDestroyWindow(old_fid);
1516
1517 if (q->testAttribute(Qt::WA_AcceptDrops) || dropSiteWasRegistered
1518 || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
1519 q->setAttribute(Qt::WA_DropSiteRegistered, true);
1520
1521 invalidateBuffer(q->rect());
1522}
1523
1524QPoint QWidget::mapToGlobal(const QPoint &pos) const
1525{
1526 Q_D(const QWidget);
1527 QWidget *parentWindow = window();
1528 if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1529 QPoint toGlobal = mapTo(parentWindow, pos) + parentWindow->pos();
1530 // Adjust for window decorations
1531 toGlobal += parentWindow->geometry().topLeft() - parentWindow->frameGeometry().topLeft();
1532 return toGlobal;
1533 }
1534 QPoint pos2 = d->mapToWS(pos);
1535 POINTL ptl;
1536 ptl.x = pos2.x();
1537 // flip y (local) coordinate
1538 ptl.y = height() - (pos2.y() + 1);
1539 WinMapWindowPoints(internalWinId(), HWND_DESKTOP, &ptl, 1);
1540 // flip y (global) coordinate
1541 ptl.y = qt_display_height() - (ptl.y + 1);
1542 return QPoint(ptl.x, ptl.y);
1543}
1544
1545QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1546{
1547 Q_D(const QWidget);
1548 QWidget *parentWindow = window();
1549 if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1550 QPoint fromGlobal = mapFrom(parentWindow, pos - parentWindow->pos());
1551 // Adjust for window decorations
1552 fromGlobal -= parentWindow->geometry().topLeft() - parentWindow->frameGeometry().topLeft();
1553 return fromGlobal;
1554 }
1555 POINTL ptl;
1556 ptl.x = pos.x();
1557 // flip y (global) coordinate
1558 ptl.y = qt_display_height() - (pos.y() + 1);
1559 WinMapWindowPoints(HWND_DESKTOP, internalWinId(), &ptl, 1);
1560 // flip y (local) coordinate
1561 ptl.y = height() - (ptl.y + 1);
1562 return d->mapFromWS(QPoint(ptl.x, ptl.y));
1563}
1564
1565void QWidgetPrivate::updateSystemBackground() {}
1566
1567#ifndef QT_NO_CURSOR
1568
1569void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
1570{
1571 Q_UNUSED(cursor);
1572 Q_Q(QWidget);
1573 qt_pm_set_cursor(q, false);
1574}
1575
1576void QWidgetPrivate::unsetCursor_sys()
1577{
1578 Q_Q(QWidget);
1579 qt_pm_set_cursor(q, false);
1580}
1581#endif
1582
1583void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
1584{
1585 Q_Q(QWidget);
1586 if (!q->isWindow())
1587 return;
1588
1589 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1590
1591 QByteArray cap = caption.toLocal8Bit();
1592 WinSetWindowText(frameWinId(), cap);
1593
1594 HSWITCH swEntry = topData()->swEntry;
1595 if (swEntry) {
1596 SWCNTRL swc;
1597 WinQuerySwitchEntry(swEntry, &swc);
1598 strncpy(swc.szSwtitle, cap, sizeof(swc.szSwtitle)-1);
1599 swc.szSwtitle[sizeof(swc.szSwtitle)-1] = 0;
1600 WinChangeSwitchEntry(swEntry, &swc);
1601 }
1602}
1603
1604void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
1605{
1606 Q_Q(QWidget);
1607 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow())
1608 return;
1609 QTLWExtra *x = this->topData();
1610 if (x->iconPointer != NULLHANDLE && !forceReset)
1611 // already been set
1612 return;
1613
1614 if (x->iconPointer != NULLHANDLE)
1615 WinDestroyPointer(x->iconPointer);
1616
1617 x->iconPointer = QPixmap::toPmHPOINTER(q->windowIcon());
1618 WinSendMsg(frameWinId(), WM_SETICON, (MPARAM)x->iconPointer, NULL);
1619}
1620
1621void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
1622{
1623 Q_UNUSED(iconText);
1624}
1625
1626QCursor *qt_grab_cursor()
1627{
1628 return mouseGrbCur;
1629}
1630
1631void QWidget::grabMouse()
1632{
1633 Q_D(QWidget);
1634 if (!qt_nograb()) {
1635 if (mouseGrb)
1636 mouseGrb->releaseMouse();
1637 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1638 WinSetCapture(HWND_DESKTOP, d->effectiveFrameWinId());
1639 mouseGrb = this;
1640#ifndef QT_NO_CURSOR
1641 mouseGrbCur = new QCursor(mouseGrb->cursor());
1642#endif
1643 }
1644}
1645
1646#ifndef QT_NO_CURSOR
1647void QWidget::grabMouse(const QCursor &cursor)
1648{
1649 Q_D(QWidget);
1650 if (!qt_nograb()) {
1651 if (mouseGrb)
1652 mouseGrb->releaseMouse();
1653 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1654 WinSetCapture(HWND_DESKTOP, d->effectiveFrameWinId());
1655 mouseGrbCur = new QCursor(cursor);
1656 WinSetPointer(HWND_DESKTOP, mouseGrbCur->handle());
1657 mouseGrb = this;
1658 }
1659}
1660#endif
1661
1662void QWidget::releaseMouse()
1663{
1664 if (!qt_nograb() && mouseGrb == this) {
1665 WinSetCapture(HWND_DESKTOP, 0);
1666 if (mouseGrbCur) {
1667 delete mouseGrbCur;
1668 mouseGrbCur = 0;
1669 }
1670 mouseGrb = 0;
1671 }
1672}
1673
1674void QWidget::grabKeyboard()
1675{
1676 if (!qt_nograb()) {
1677 if (keyboardGrb)
1678 keyboardGrb->releaseKeyboard();
1679 keyboardGrb = this;
1680 }
1681}
1682
1683void QWidget::releaseKeyboard()
1684{
1685 if (!qt_nograb() && keyboardGrb == this)
1686 keyboardGrb = 0;
1687}
1688
1689QWidget *QWidget::mouseGrabber()
1690{
1691 return mouseGrb;
1692}
1693
1694QWidget *QWidget::keyboardGrabber()
1695{
1696 return keyboardGrb;
1697}
1698
1699void QWidget::activateWindow()
1700{
1701 window()->createWinId();
1702 WinSetActiveWindow(HWND_DESKTOP, window()->d_func()->frameWinId());
1703}
1704
1705void QWidget::setWindowState(Qt::WindowStates newstate)
1706{
1707 Q_D(QWidget);
1708 Qt::WindowStates oldstate = windowState();
1709 if (oldstate == newstate)
1710 return;
1711
1712 ULONG fl = (newstate & Qt::WindowActive) ? SWP_ACTIVATE : 0;
1713
1714 if (isWindow()) {
1715 createWinId();
1716 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1717
1718 HWND fId = d->frameWinId();
1719 Q_ASSERT(fId != NULLHANDLE);
1720
1721 // Ensure the initial size is valid, since we store it as normalGeometry below.
1722 if (!testAttribute(Qt::WA_Resized) && !isVisible())
1723 adjustSize();
1724
1725 if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) {
1726 if (newstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen))
1727 d->topData()->normalGeometry = geometry();
1728 if (isVisible() && !(newstate & Qt::WindowMinimized)) {
1729 fl |= (newstate & Qt::WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
1730 WinSetWindowPos(fId, 0, 0, 0, 0, 0, fl);
1731 if (!(newstate & Qt::WindowFullScreen)) {
1732 QRect r = d->topData()->normalGeometry;
1733 if (!(newstate & Qt::WindowMaximized) && r.width() >= 0) {
1734 if (pos() != r.topLeft() || size() !=r.size()) {
1735 d->topData()->normalGeometry = QRect(0,0,-1,-1);
1736 setGeometry(r);
1737 }
1738 }
1739 } else {
1740 // @todo most likely, we don't need this as in PM the frame
1741 // strut seems to never change during window lifetime
1742// d->updateFrameStrut();
1743 }
1744 }
1745 }
1746
1747 if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
1748 if (newstate & Qt::WindowFullScreen) {
1749 if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized))
1750 d->topData()->normalGeometry = geometry();
1751 QRect r = QApplication::desktop()->screenGeometry(this);
1752 QRect fs(d->frameStrut());
1753 r.adjust(-fs.left(), -fs.top(), fs.right(), fs.bottom());
1754 fl |= SWP_ZORDER | SWP_MOVE | SWP_SIZE;
1755 WinSetWindowPos(fId, HWND_TOP, r.left(),
1756 // flip y coodrinate
1757 qt_display_height() - (r.top() + r.height()),
1758 r.width(), r.height(), fl);
1759 } else {
1760 // preserve maximized state
1761 if (isVisible()) {
1762 fl |= (newstate & Qt::WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
1763 WinSetWindowPos(fId, 0, 0, 0, 0, 0, fl);
1764 }
1765
1766 if (!(newstate & Qt::WindowMaximized)) {
1767 QRect r = d->topData()->normalGeometry;
1768 d->topData()->normalGeometry = QRect(0,0,-1,-1);
1769 if (r.isValid())
1770 setGeometry(r);
1771 }
1772 }
1773 }
1774
1775 if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
1776 if (isVisible()) {
1777 fl |= (newstate & Qt::WindowMinimized) ? SWP_MINIMIZE :
1778 (newstate & Qt::WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
1779 WinSetWindowPos(fId, 0, 0, 0, 0, 0, fl);
1780 }
1781 }
1782 }
1783
1784 data->window_state = newstate;
1785 // Note: QWindowStateChangeEvent is sent from QtWndProc(WM_MINMAXFRAME)
1786}
1787
1788void QWidgetPrivate::hide_sys()
1789{
1790 Q_Q(QWidget);
1791 deactivateWidgetCleanup();
1792 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1793 if (q->windowFlags() != Qt::Desktop) {
1794 ULONG fl = SWP_HIDE;
1795 if (q->isWindow() && frameWinId() != NULLHANDLE) {
1796 if (!(q->windowFlags() & Qt::Popup))
1797 fl |= SWP_DEACTIVATE;
1798 }
1799 qt_WinSetWindowPos(frameWinId(), 0, 0, 0, 0, 0, fl);
1800 HSWITCH swEntry = maybeTopData() ? maybeTopData()->swEntry : NULLHANDLE;
1801 if (swEntry != NULLHANDLE) {
1802 SWCNTRL swc;
1803 WinQuerySwitchEntry(swEntry, &swc);
1804 swc.uchVisibility = SWL_INVISIBLE;
1805 WinChangeSwitchEntry(swEntry, &swc);
1806 }
1807 }
1808 if (q->isWindow()) {
1809 if (QWidgetBackingStore *bs = maybeBackingStore())
1810 bs->releaseBuffer();
1811 } else {
1812 invalidateBuffer(q->rect());
1813 }
1814 q->setAttribute(Qt::WA_Mapped, false);
1815}
1816
1817void QWidgetPrivate::show_sys()
1818{
1819 Q_Q(QWidget);
1820 if (q->testAttribute(Qt::WA_OutsideWSRange))
1821 return;
1822 q->setAttribute(Qt::WA_Mapped);
1823 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1824
1825 if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
1826 invalidateBuffer(q->rect());
1827 return;
1828 }
1829
1830 if (frameWinId() != NULLHANDLE) {
1831 ULONG fl = SWP_SHOW;
1832 if (q->isWindow()) {
1833 if (q->isMinimized()) {
1834 fl = SWP_MINIMIZE;
1835 } else if (q->isMaximized()) {
1836 fl |= SWP_MAXIMIZE;
1837 } else {
1838 fl |= SWP_RESTORE;
1839 }
1840
1841 if (!(q->testAttribute(Qt::WA_ShowWithoutActivating)
1842 || (q->windowType() == Qt::Popup)
1843 || (q->windowType() == Qt::ToolTip)
1844 || (q->windowType() == Qt::Tool))) {
1845 fl |= SWP_ACTIVATE;
1846 }
1847 }
1848
1849 qt_WinSetWindowPos(frameWinId(), 0, 0, 0, 0, 0, fl);
1850
1851 if (q->isWindow()) {
1852 if (q->windowType() != Qt::Popup &&
1853 q->windowType() != Qt::Tool &&
1854 (q->windowType() != Qt::Dialog || !q->parentWidget())
1855 ) {
1856 HSWITCH &swEntry = topData()->swEntry;
1857 if (!swEntry) {
1858 // lazily create a new window list entry
1859 HWND id = frameWinId();
1860 PID pid;
1861 WinQueryWindowProcess(id, &pid, NULL);
1862 SWCNTRL swc;
1863 memset(&swc, 0, sizeof(SWCNTRL));
1864 swc.hwnd = id;
1865 swc.idProcess = pid;
1866 swc.uchVisibility = SWL_VISIBLE;
1867 swc.fbJump = SWL_JUMPABLE;
1868 WinQueryWindowText(id, sizeof(swc.szSwtitle), swc.szSwtitle);
1869 swEntry = WinAddSwitchEntry(&swc);
1870 } else {
1871 SWCNTRL swc;
1872 WinQuerySwitchEntry(swEntry, &swc);
1873 swc.uchVisibility = SWL_VISIBLE;
1874 WinChangeSwitchEntry(swEntry, &swc);
1875 }
1876 }
1877
1878 ULONG wstyle = WinQueryWindowULong(frameWinId(), QWL_STYLE);
1879 if (wstyle & WS_MINIMIZED)
1880 data.window_state |= Qt::WindowMinimized;
1881 if (wstyle & WS_MAXIMIZED)
1882 data.window_state |= Qt::WindowMaximized;
1883 }
1884 }
1885
1886 invalidateBuffer(q->rect());
1887}
1888
1889void QWidgetPrivate::setFocus_sys()
1890{
1891 Q_Q(QWidget);
1892 if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
1893 WinSetFocus(HWND_DESKTOP, q->effectiveWinId());
1894}
1895
1896void QWidgetPrivate::raise_sys()
1897{
1898 Q_Q(QWidget);
1899 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1900 if (frameWinId() != NULLHANDLE)
1901 qt_WinSetWindowPos(frameWinId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
1902
1903}
1904
1905void QWidgetPrivate::lower_sys()
1906{
1907 Q_Q(QWidget);
1908 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1909 if (frameWinId() != NULLHANDLE)
1910 qt_WinSetWindowPos(frameWinId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER);
1911 invalidateBuffer(q->rect());
1912}
1913
1914void QWidgetPrivate::stackUnder_sys(QWidget* w)
1915{
1916 Q_Q(QWidget);
1917 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1918 if (frameWinId() != NULLHANDLE && w->d_func()->frameWinId() != NULLHANDLE)
1919 WinSetWindowPos(frameWinId(), w->d_func()->frameWinId(), 0, 0, 0, 0, SWP_ZORDER);
1920 invalidateBuffer(q->rect());
1921}
1922
1923#define XCOORD_MAX 32767
1924#define WRECT_MAX 32767
1925
1926/*
1927 Helper function for non-toplevel widgets. Helps to map Qt's 32bit
1928 coordinate system to PM 16bit coordinate system.
1929
1930 This code is duplicated from the X11 code, so any changes there
1931 should also (most likely) be reflected here.
1932
1933 (In all comments below: s/X/PM/g)
1934 */
1935
1936void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
1937{
1938 Q_Q(QWidget);
1939 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1940
1941 /*
1942 There are up to four different coordinate systems here:
1943 Qt coordinate system for this widget.
1944 X coordinate system for this widget (relative to wrect).
1945 Qt coordinate system for parent
1946 X coordinate system for parent (relative to parent's wrect).
1947 */
1948 QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
1949 QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
1950 QRect wrect;
1951 //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys)
1952 QRect xrect = data.crect;
1953
1954 const QWidget *const parent = q->parentWidget();
1955 QRect parentWRect = parent->data->wrect;
1956
1957 if (parentWRect.isValid()) {
1958 // parent is clipped, and we have to clip to the same limit as parent
1959 if (!parentWRect.contains(xrect)) {
1960 xrect &= parentWRect;
1961 wrect = xrect;
1962 //translate from parent's to my Qt coord sys
1963 wrect.translate(-data.crect.topLeft());
1964 }
1965 //translate from parent's Qt coords to parent's X coords
1966 xrect.translate(-parentWRect.topLeft());
1967
1968 } else {
1969 // parent is not clipped, we may or may not have to clip
1970
1971 if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
1972 // This is where the main optimization is: we are already
1973 // clipped, and if our clip is still valid, we can just
1974 // move our window, and do not need to move or clip
1975 // children
1976
1977 QRect vrect = xrect & parent->rect();
1978 vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
1979 if (data.wrect.contains(vrect)) {
1980 xrect = data.wrect;
1981 xrect.translate(data.crect.topLeft());
1982 if (q->internalWinId() != NULLHANDLE) {
1983 Q_ASSERT(parent->internalWinId() != NULLHANDLE);
1984 int h = parent->height();
1985 qt_WinSetWindowPos(q->internalWinId(), 0, xrect.x(),
1986 // flip y coordinate
1987 h - (xrect.y() + xrect.height()),
1988 xrect.width(), xrect.height(),
1989 SWP_MOVE | SWP_SIZE);
1990 }
1991 return;
1992 }
1993 }
1994
1995 if (!validRange.contains(xrect)) {
1996 // we are too big, and must clip
1997 xrect &=wrectRange;
1998 wrect = xrect;
1999 wrect.translate(-data.crect.topLeft());
2000 //parent's X coord system is equal to parent's Qt coord
2001 //sys, so we don't need to map xrect.
2002 }
2003
2004 }
2005
2006
2007 // unmap if we are outside the valid window system coord system
2008 bool outsideRange = !xrect.isValid();
2009 bool mapWindow = false;
2010 if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
2011 q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
2012 if (outsideRange) {
2013 if (q->internalWinId() != NULLHANDLE)
2014 qt_WinSetWindowPos(q->internalWinId(), 0, 0, 0, 0, 0, SWP_HIDE);
2015 q->setAttribute(Qt::WA_Mapped, false);
2016 } else if (!q->isHidden()) {
2017 mapWindow = true;
2018 }
2019 }
2020
2021 if (outsideRange)
2022 return;
2023
2024 bool jump = (data.wrect != wrect);
2025 data.wrect = wrect;
2026
2027 // and now recursively for all children...
2028 for (int i = 0; i < children.size(); ++i) {
2029 QObject *object = children.at(i);
2030 if (object->isWidgetType()) {
2031 QWidget *w = static_cast<QWidget *>(object);
2032 if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
2033 w->d_func()->setWSGeometry();
2034 }
2035 }
2036
2037 // move ourselves to the new position and map (if necessary) after
2038 // the movement. Rationale: moving unmapped windows is much faster
2039 // than moving mapped windows
2040 if (q->internalWinId() != NULLHANDLE) {
2041 int h = parent->height();
2042 if (parent->internalWinId() == NULLHANDLE) {
2043 xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
2044 h = q->nativeParentWidget()->height();
2045 }
2046 qt_WinSetWindowPos(q->internalWinId(), 0, xrect.x(),
2047 // flip y coordinate
2048 h - (xrect.y() + xrect.height()),
2049 xrect.width(), xrect.height(), SWP_MOVE | SWP_SIZE);
2050 }
2051 if (mapWindow && !dontShow) {
2052 q->setAttribute(Qt::WA_Mapped);
2053 if (q->internalWinId() != NULLHANDLE)
2054 qt_WinSetWindowPos(q->internalWinId(), 0, 0, 0, 0, 0, SWP_SHOW);
2055 }
2056
2057 if (jump && q->internalWinId() != NULLHANDLE)
2058 WinInvalidateRect(q->internalWinId(), NULL, FALSE);
2059}
2060
2061//
2062// The internal qPMRequestConfig, defined in qapplication_pm.cpp, stores move,
2063// resize and setGeometry requests for a widget that is already
2064// processing a config event. The purpose is to avoid recursion.
2065//
2066void qPMRequestConfig(WId, int, int, int, int, int);
2067
2068void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
2069{
2070 Q_Q(QWidget);
2071 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2072 if (extra) { // any size restrictions?
2073 w = qMin(w,extra->maxw);
2074 h = qMin(h,extra->maxh);
2075 w = qMax(w,extra->minw);
2076 h = qMax(h,extra->minh);
2077 }
2078 if (q->isWindow())
2079 topData()->normalGeometry = QRect(0, 0, -1, -1);
2080
2081 QSize oldSize(q->size());
2082 QPoint oldPos(q->pos());
2083
2084 if (!q->isWindow())
2085 isMove = (data.crect.topLeft() != QPoint(x, y));
2086 bool isResize = w != oldSize.width() || h != oldSize.height();
2087
2088 if (!isMove && !isResize)
2089 return;
2090
2091 HWND fId = frameWinId();
2092
2093 if (isResize && !q->testAttribute(Qt::WA_StaticContents) &&
2094 q->internalWinId() != NULLHANDLE) {
2095 RECTL rcl = { 0, 0, data.crect.width(), data.crect.height() };
2096 WinValidateRect(q->internalWinId(), &rcl, FALSE);
2097 }
2098
2099 if (isResize)
2100 data.window_state &= ~Qt::WindowMaximized;
2101
2102 if (data.window_state & Qt::WindowFullScreen) {
2103 data.window_state &= ~Qt::WindowFullScreen;
2104 }
2105
2106 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
2107 const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
2108
2109 if (q->testAttribute(Qt::WA_WState_ConfigPending)) { // processing config event
2110 if (q->internalWinId() != NULLHANDLE)
2111 qPMRequestConfig(q->internalWinId(), isMove ? 2 : 1, x, y, w, h);
2112 } else {
2113 if (!q->testAttribute(Qt::WA_DontShowOnScreen))
2114 q->setAttribute(Qt::WA_WState_ConfigPending);
2115 if (q->windowType() == Qt::Desktop) {
2116 data.crect.setRect(x, y, w, h);
2117 } else if (q->isWindow()) {
2118 int sh = qt_display_height();
2119 QRect fs(frameStrut());
2120 if (extra) {
2121 fs.setLeft(x - fs.left());
2122 fs.setTop(y - fs.top());
2123 fs.setRight((x + w - 1) + fs.right());
2124 fs.setBottom((y + h - 1) + fs.bottom());
2125 }
2126 if (w == 0 || h == 0) {
2127 q->setAttribute(Qt::WA_OutsideWSRange, true);
2128 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
2129 hide_sys();
2130 data.crect = QRect(x, y, w, h);
2131 } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
2132 q->setAttribute(Qt::WA_OutsideWSRange, false);
2133
2134 // put the window in its place and show it
2135 WinSetWindowPos(fId, 0, fs.x(),
2136 // flip y coordinate
2137 sh - (fs.y() + fs.height()),
2138 fs.width(), fs.height(), SWP_MOVE | SWP_SIZE);
2139 data.crect.setRect(x, y, w, h);
2140
2141 show_sys();
2142 } else if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
2143 q->setAttribute(Qt::WA_OutsideWSRange, false);
2144 // If the window is hidden and in maximized state or minimized, instead of moving the
2145 // window, set the normal position of the window.
2146 SWP swp;
2147 WinQueryWindowPos(fId, &swp);
2148 if (((swp.fl & SWP_MAXIMIZE) && !WinIsWindowVisible(fId)) ||
2149 (swp.fl & SWP_MINIMIZE)) {
2150 WinSetWindowUShort(fId, QWS_XRESTORE, fs.x());
2151 WinSetWindowUShort(fId, QWS_YRESTORE, // flip y coordinate
2152 sh - (fs.y() + fs.height()));
2153 WinSetWindowUShort(fId, QWS_CXRESTORE, fs.width());
2154 WinSetWindowUShort(fId, QWS_CYRESTORE, fs.height());
2155 } else {
2156 WinSetWindowPos(fId, 0, fs.x(),
2157 // flip y coordinate
2158 sh - (fs.y() + fs.height()),
2159 fs.width(), fs.height(), SWP_MOVE | SWP_SIZE);
2160 }
2161 if (!q->isVisible())
2162 WinInvalidateRect(q->internalWinId(), NULL, FALSE);
2163 if (!(swp.fl & SWP_MINIMIZE)) {
2164 // If the layout has heightForWidth, the WinSetWindowPos() above can
2165 // change the size/position, so refresh them. Note that if the
2166 // widget is minimized, we don't update its size in Qt (see
2167 // QApplication::translateConfigEvent()).
2168 WinQueryWindowPos(fId, &swp);
2169 // flip y coordinate
2170 swp.y = sh - (swp.y + swp.cy);
2171 QRect fs(frameStrut());
2172 data.crect.setRect(swp.x + fs.left(),
2173 swp.y + fs.top(),
2174 swp.cx - fs.left() - fs.right(),
2175 swp.cy - fs.top() - fs.bottom());
2176 isResize = data.crect.size() != oldSize;
2177 }
2178 } else {
2179 q->setAttribute(Qt::WA_OutsideWSRange, false);
2180 data.crect.setRect(x, y, w, h);
2181 }
2182 } else {
2183 QRect oldGeom(data.crect);
2184 data.crect.setRect(x, y, w, h);
2185 if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) {
2186 // Top-level resize optimization does not work for native child widgets;
2187 // disable it for this particular widget.
2188 if (inTopLevelResize)
2189 tlwExtra->inTopLevelResize = false;
2190
2191 if (!isResize)
2192 moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
2193 else
2194 invalidateBuffer_resizeHelper(oldPos, oldSize);
2195
2196 if (inTopLevelResize)
2197 tlwExtra->inTopLevelResize = true;
2198 }
2199 if (q->testAttribute(Qt::WA_WState_Created))
2200 setWSGeometry();
2201 }
2202 q->setAttribute(Qt::WA_WState_ConfigPending, false);
2203 }
2204
2205 if (q->isWindow() && q->isVisible() && isResize && !inTopLevelResize) {
2206 invalidateBuffer(q->rect()); //after the resize
2207 }
2208
2209 // Process events immediately rather than in translateConfigEvent to
2210 // avoid windows message process delay.
2211 if (q->isVisible()) {
2212 if (isMove && q->pos() != oldPos) {
2213 // in QMoveEvent, pos() and oldPos() exclude the frame, adjust them
2214 QRect fs(frameStrut());
2215 QMoveEvent e(q->pos() + fs.topLeft(), oldPos + fs.topLeft());
2216 QApplication::sendEvent(q, &e);
2217 }
2218 if (isResize) {
2219 static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
2220 // If we have a backing store with static contents, we have to disable the top-level
2221 // resize optimization in order to get invalidated regions for resized widgets.
2222 // The optimization discards all invalidateBuffer() calls since we're going to
2223 // repaint everything anyways, but that's not the case with static contents.
2224 const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
2225 && !extra->topextra->inTopLevelResize
2226 && (!extra->topextra->backingStore
2227 || !extra->topextra->backingStore->hasStaticContents());
2228 if (setTopLevelResize)
2229 extra->topextra->inTopLevelResize = true;
2230 QResizeEvent e(q->size(), oldSize);
2231 QApplication::sendEvent(q, &e);
2232 if (setTopLevelResize)
2233 extra->topextra->inTopLevelResize = false;
2234 }
2235 } else {
2236 if (isMove && q->pos() != oldPos)
2237 q->setAttribute(Qt::WA_PendingMoveEvent, true);
2238 if (isResize)
2239 q->setAttribute(Qt::WA_PendingResizeEvent, true);
2240 }
2241}
2242
2243void QWidgetPrivate::setConstraints_sys()
2244{
2245 // @todo is there a way to show/hide the Maximize button according to
2246 // the shouldShowMaximizeButton() return value?
2247}
2248
2249HWND QWidgetPrivate::effectiveFrameWinId() const
2250{
2251 Q_Q(const QWidget);
2252 HWND fid = frameWinId();
2253 if (fid != NULLHANDLE || !q->testAttribute(Qt::WA_WState_Created))
2254 return fid;
2255 QWidget *realParent = q->nativeParentWidget();
2256 Q_ASSERT(realParent);
2257 Q_ASSERT(realParent->d_func()->frameWinId());
2258 return realParent->d_func()->frameWinId();
2259}
2260
2261void QWidgetPrivate::scroll_sys(int dx, int dy)
2262{
2263 Q_Q(QWidget);
2264 scrollChildren(dx, dy);
2265
2266 if (!paintOnScreen()) {
2267 scrollRect(q->rect(), dx, dy);
2268 } else {
2269 // @todo ask qt_WinScrollWindowWell() to erase background if
2270 // WA_OpaquePaintEvent is reset?
2271 //if (!q->testAttribute(Qt::WA_OpaquePaintEvent))
2272 // ;
2273 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2274 qt_WinScrollWindowWell(q->internalWinId(), dx, -dy, NULL);
2275 }
2276}
2277