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

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

gui: Fixed a crash that could happen at program termination in Dive mode if a top-level window had a native HWND window embedded in it. This was partly a r775 regression and also supersedes this change at all. Closes #184.

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