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

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

gui: Adopted to 4.6.1 changes.

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