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

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

gui: OS/2: Exported qt_WinProcessWindowObstacles().

File size: 95.3 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 internalWinId() != NULLHANDLE) {
1392 HWND id = internalWinId();
1393 if (isWindow() && !(windowType() == Qt::Popup)) {
1394 // extra data including extra->topextra has been already
1395 // deleted at this point by deleteExtra() and therefore
1396 // calling frameWinId() is useless -- it will return the
1397 // client window handle. Use WinQueryWindow() instead.
1398 id = WinQueryWindow(id, QW_PARENT);
1399 Q_ASSERT(id != NULLHANDLE);
1400 }
1401#if defined(QT_DEBUGWINCREATEDESTROY)
1402 qDebug() << "|Destroying window" << this
1403 << "\n| hwnd" << qDebugFmtHex(id);
1404#endif
1405 qt_WinDestroyWindow(id);
1406 }
1407 QT_TRY {
1408 d->setWinId(0);
1409 } QT_CATCH (const std::bad_alloc &) {
1410 // swallow - destructors must not throw
1411 }
1412 }
1413}
1414
1415void QWidgetPrivate::reparentChildren()
1416{
1417 Q_Q(QWidget);
1418 QObjectList chlist = q->children();
1419 for (int i = 0; i < chlist.size(); ++i) { // reparent children
1420 QObject *obj = chlist.at(i);
1421 if (obj->isWidgetType()) {
1422 QWidget *w = (QWidget *)obj;
1423 if ((w->windowType() == Qt::Popup)) {
1424 ;
1425 } else if (w->isWindow()) {
1426 bool showIt = w->isVisible();
1427 QPoint old_pos = w->pos();
1428 w->setParent(q, w->windowFlags());
1429 w->move(old_pos);
1430 if (showIt)
1431 w->show();
1432 } else {
1433 w->d_func()->invalidateBuffer(w->rect());
1434 WinSetParent(w->effectiveWinId(), q->effectiveWinId(), FALSE);
1435 WinSetOwner(w->effectiveWinId(), q->effectiveWinId());
1436 w->d_func()->reparentChildren();
1437#if 0 // @todo check if this is really necessary any longer
1438 // bring PM coords into accordance with Qt coords,
1439 // otherwise setGeometry() below will wrongly position
1440 // children if this widget manages their layout.
1441 SWP swp;
1442 int hd = q->height() - old_height;
1443 WinQueryWindowPos(w->effectiveWinId(), &swp);
1444 swp.y += hd;
1445 WinSetWindowPos(w->effectiveWinId(), 0, swp.x, swp.y, 0, 0, SWP_MOVE);
1446#endif
1447 }
1448 }
1449 }
1450}
1451
1452void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
1453{
1454 Q_Q(QWidget);
1455 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
1456 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
1457 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
1458
1459 WId old_fid = frameWinId();
1460
1461 // hide and reparent our own window away. Otherwise we might get
1462 // destroyed when emitting the child remove event below. See QWorkspace.
1463 if (q->isVisible() && old_fid != NULLHANDLE) {
1464 qt_WinSetWindowPos(old_fid, 0, 0, 0, 0, 0, SWP_HIDE);
1465 WinSetParent(old_fid, HWND_OBJECT, FALSE);
1466 WinSetOwner(old_fid, NULLHANDLE);
1467 }
1468 bool dropSiteWasRegistered = false;
1469 if (q->testAttribute(Qt::WA_DropSiteRegistered)) {
1470 dropSiteWasRegistered = true;
1471 q->setAttribute(Qt::WA_DropSiteRegistered, false); // ole dnd unregister (we will register again below)
1472 }
1473
1474 if ((q->windowType() == Qt::Desktop))
1475 old_fid = NULLHANDLE;
1476 setWinId(0);
1477
1478 QObjectPrivate::setParent_helper(parent);
1479 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
1480
1481 data.window_flags = f;
1482 data.fstrut_dirty = true;
1483 q->setAttribute(Qt::WA_WState_Created, false);
1484 q->setAttribute(Qt::WA_WState_Visible, false);
1485 q->setAttribute(Qt::WA_WState_Hidden, false);
1486 adjustFlags(data.window_flags, q);
1487 // keep compatibility with previous versions, we need to preserve the created state
1488 // (but we recreate the winId for the widget being reparented, again for compatibility)
1489 if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created)))
1490 createWinId();
1491 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
1492 q->setAttribute(Qt::WA_WState_Hidden);
1493 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
1494
1495 if (wasCreated) {
1496 reparentChildren();
1497 }
1498
1499 if (extra && !extra->mask.isEmpty()) {
1500 QRegion r = extra->mask;
1501 extra->mask = QRegion();
1502 q->setMask(r);
1503 }
1504 if (extra && extra->topextra && !extra->topextra->caption.isEmpty()) {
1505 setWindowIcon_sys(true);
1506 setWindowTitle_helper(extra->topextra->caption);
1507 }
1508 if (old_fid != NULLHANDLE)
1509 qt_WinDestroyWindow(old_fid);
1510
1511 if (q->testAttribute(Qt::WA_AcceptDrops) || dropSiteWasRegistered
1512 || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
1513 q->setAttribute(Qt::WA_DropSiteRegistered, true);
1514
1515 invalidateBuffer(q->rect());
1516}
1517
1518QPoint QWidget::mapToGlobal(const QPoint &pos) const
1519{
1520 Q_D(const QWidget);
1521 QWidget *parentWindow = window();
1522 if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1523 QPoint toGlobal = mapTo(parentWindow, pos) + parentWindow->pos();
1524 // Adjust for window decorations
1525 toGlobal += parentWindow->geometry().topLeft() - parentWindow->frameGeometry().topLeft();
1526 return toGlobal;
1527 }
1528 QPoint pos2 = d->mapToWS(pos);
1529 POINTL ptl;
1530 ptl.x = pos2.x();
1531 // flip y (local) coordinate
1532 ptl.y = height() - (pos2.y() + 1);
1533 WinMapWindowPoints(internalWinId(), HWND_DESKTOP, &ptl, 1);
1534 // flip y (global) coordinate
1535 ptl.y = qt_display_height() - (ptl.y + 1);
1536 return QPoint(ptl.x, ptl.y);
1537}
1538
1539QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1540{
1541 Q_D(const QWidget);
1542 QWidget *parentWindow = window();
1543 if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1544 QPoint fromGlobal = mapFrom(parentWindow, pos - parentWindow->pos());
1545 // Adjust for window decorations
1546 fromGlobal -= parentWindow->geometry().topLeft() - parentWindow->frameGeometry().topLeft();
1547 return fromGlobal;
1548 }
1549 POINTL ptl;
1550 ptl.x = pos.x();
1551 // flip y (global) coordinate
1552 ptl.y = qt_display_height() - (pos.y() + 1);
1553 WinMapWindowPoints(HWND_DESKTOP, internalWinId(), &ptl, 1);
1554 // flip y (local) coordinate
1555 ptl.y = height() - (ptl.y + 1);
1556 return d->mapFromWS(QPoint(ptl.x, ptl.y));
1557}
1558
1559void QWidgetPrivate::updateSystemBackground() {}
1560
1561#ifndef QT_NO_CURSOR
1562
1563void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
1564{
1565 Q_UNUSED(cursor);
1566 Q_Q(QWidget);
1567 qt_pm_set_cursor(q, false);
1568}
1569
1570void QWidgetPrivate::unsetCursor_sys()
1571{
1572 Q_Q(QWidget);
1573 qt_pm_set_cursor(q, false);
1574}
1575#endif
1576
1577void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
1578{
1579 Q_Q(QWidget);
1580 if (!q->isWindow())
1581 return;
1582
1583 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1584
1585 QByteArray cap = caption.toLocal8Bit();
1586 WinSetWindowText(frameWinId(), cap);
1587
1588 HSWITCH swEntry = topData()->swEntry;
1589 if (swEntry) {
1590 SWCNTRL swc;
1591 WinQuerySwitchEntry(swEntry, &swc);
1592 strncpy(swc.szSwtitle, cap, sizeof(swc.szSwtitle)-1);
1593 swc.szSwtitle[sizeof(swc.szSwtitle)-1] = 0;
1594 WinChangeSwitchEntry(swEntry, &swc);
1595 }
1596}
1597
1598void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
1599{
1600 Q_Q(QWidget);
1601 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow())
1602 return;
1603 QTLWExtra *x = this->topData();
1604 if (x->iconPointer != NULLHANDLE && !forceReset)
1605 // already been set
1606 return;
1607
1608 if (x->iconPointer != NULLHANDLE)
1609 WinDestroyPointer(x->iconPointer);
1610
1611 x->iconPointer = QPixmap::toPmHPOINTER(q->windowIcon());
1612 WinSendMsg(frameWinId(), WM_SETICON, (MPARAM)x->iconPointer, NULL);
1613}
1614
1615void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
1616{
1617 Q_UNUSED(iconText);
1618}
1619
1620QCursor *qt_grab_cursor()
1621{
1622 return mouseGrbCur;
1623}
1624
1625void QWidget::grabMouse()
1626{
1627 Q_D(QWidget);
1628 if (!qt_nograb()) {
1629 if (mouseGrb)
1630 mouseGrb->releaseMouse();
1631 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1632 WinSetCapture(HWND_DESKTOP, d->effectiveFrameWinId());
1633 mouseGrb = this;
1634#ifndef QT_NO_CURSOR
1635 mouseGrbCur = new QCursor(mouseGrb->cursor());
1636#endif
1637 }
1638}
1639
1640#ifndef QT_NO_CURSOR
1641void QWidget::grabMouse(const QCursor &cursor)
1642{
1643 Q_D(QWidget);
1644 if (!qt_nograb()) {
1645 if (mouseGrb)
1646 mouseGrb->releaseMouse();
1647 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1648 WinSetCapture(HWND_DESKTOP, d->effectiveFrameWinId());
1649 mouseGrbCur = new QCursor(cursor);
1650 WinSetPointer(HWND_DESKTOP, mouseGrbCur->handle());
1651 mouseGrb = this;
1652 }
1653}
1654#endif
1655
1656void QWidget::releaseMouse()
1657{
1658 if (!qt_nograb() && mouseGrb == this) {
1659 WinSetCapture(HWND_DESKTOP, 0);
1660 if (mouseGrbCur) {
1661 delete mouseGrbCur;
1662 mouseGrbCur = 0;
1663 }
1664 mouseGrb = 0;
1665 }
1666}
1667
1668void QWidget::grabKeyboard()
1669{
1670 if (!qt_nograb()) {
1671 if (keyboardGrb)
1672 keyboardGrb->releaseKeyboard();
1673 keyboardGrb = this;
1674 }
1675}
1676
1677void QWidget::releaseKeyboard()
1678{
1679 if (!qt_nograb() && keyboardGrb == this)
1680 keyboardGrb = 0;
1681}
1682
1683QWidget *QWidget::mouseGrabber()
1684{
1685 return mouseGrb;
1686}
1687
1688QWidget *QWidget::keyboardGrabber()
1689{
1690 return keyboardGrb;
1691}
1692
1693void QWidget::activateWindow()
1694{
1695 window()->createWinId();
1696 WinSetActiveWindow(HWND_DESKTOP, window()->d_func()->frameWinId());
1697}
1698
1699void QWidget::setWindowState(Qt::WindowStates newstate)
1700{
1701 Q_D(QWidget);
1702 Qt::WindowStates oldstate = windowState();
1703 if (oldstate == newstate)
1704 return;
1705
1706 ULONG fl = (newstate & Qt::WindowActive) ? SWP_ACTIVATE : 0;
1707
1708 if (isWindow()) {
1709 createWinId();
1710 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1711
1712 HWND fId = d->frameWinId();
1713 Q_ASSERT(fId != NULLHANDLE);
1714
1715 // Ensure the initial size is valid, since we store it as normalGeometry below.
1716 if (!testAttribute(Qt::WA_Resized) && !isVisible())
1717 adjustSize();
1718
1719 if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) {
1720 if (newstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen))
1721 d->topData()->normalGeometry = geometry();
1722 if (isVisible() && !(newstate & Qt::WindowMinimized)) {
1723 fl |= (newstate & Qt::WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
1724 WinSetWindowPos(fId, 0, 0, 0, 0, 0, fl);
1725 if (!(newstate & Qt::WindowFullScreen)) {
1726 QRect r = d->topData()->normalGeometry;
1727 if (!(newstate & Qt::WindowMaximized) && r.width() >= 0) {
1728 if (pos() != r.topLeft() || size() !=r.size()) {
1729 d->topData()->normalGeometry = QRect(0,0,-1,-1);
1730 setGeometry(r);
1731 }
1732 }
1733 } else {
1734 // @todo most likely, we don't need this as in PM the frame
1735 // strut seems to never change during window lifetime
1736// d->updateFrameStrut();
1737 }
1738 }
1739 }
1740
1741 if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
1742 if (newstate & Qt::WindowFullScreen) {
1743 if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized))
1744 d->topData()->normalGeometry = geometry();
1745 QRect r = QApplication::desktop()->screenGeometry(this);
1746 QRect fs(d->frameStrut());
1747 r.adjust(-fs.left(), -fs.top(), fs.right(), fs.bottom());
1748 fl |= SWP_ZORDER | SWP_MOVE | SWP_SIZE;
1749 WinSetWindowPos(fId, HWND_TOP, r.left(),
1750 // flip y coodrinate
1751 qt_display_height() - (r.top() + r.height()),
1752 r.width(), r.height(), fl);
1753 } else {
1754 // preserve maximized state
1755 if (isVisible()) {
1756 fl |= (newstate & Qt::WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
1757 WinSetWindowPos(fId, 0, 0, 0, 0, 0, fl);
1758 }
1759
1760 if (!(newstate & Qt::WindowMaximized)) {
1761 QRect r = d->topData()->normalGeometry;
1762 d->topData()->normalGeometry = QRect(0,0,-1,-1);
1763 if (r.isValid())
1764 setGeometry(r);
1765 }
1766 }
1767 }
1768
1769 if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
1770 if (isVisible()) {
1771 fl |= (newstate & Qt::WindowMinimized) ? SWP_MINIMIZE :
1772 (newstate & Qt::WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
1773 WinSetWindowPos(fId, 0, 0, 0, 0, 0, fl);
1774 }
1775 }
1776 }
1777
1778 data->window_state = newstate;
1779 // Note: QWindowStateChangeEvent is sent from QtWndProc(WM_MINMAXFRAME)
1780}
1781
1782/*!
1783 Adds the PM event filter to this widget. This is functionally equivalent to
1784 overriding the QWidget::pmEvent() virtual method.
1785
1786 Note that the event filters added with this method are called before
1787 QWidget::pmEvent() and may prevent Qt from further event processing
1788 including passing it to QWidget::pmEvent(). The order in which these filters
1789 are called corresponds to the order they are added to this widget.
1790
1791 \warning This function is not portable and exists only on OS/2.
1792*/
1793void QWidget::addPmEventFilter(PmEventFilter *filter)
1794{
1795 Q_D(QWidget);
1796 d->createExtra();
1797 d->extra->pmEventFilters.prepend(filter);
1798}
1799
1800/*!
1801 Removes the PM event filter added with addPmEventFilter() from this widget.
1802
1803 \warning This function is not portable and exists only on OS/2.
1804*/
1805void QWidget::removePmEventFilter(PmEventFilter *filter)
1806{
1807 Q_D(QWidget);
1808 if (d->extra)
1809 d->extra->pmEventFilters.removeOne(filter);
1810}
1811
1812void QWidgetPrivate::hide_sys()
1813{
1814 Q_Q(QWidget);
1815 deactivateWidgetCleanup();
1816 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1817 if (q->windowFlags() != Qt::Desktop) {
1818 ULONG fl = SWP_HIDE;
1819 if (q->isWindow() && frameWinId() != NULLHANDLE) {
1820 if (!(q->windowFlags() & Qt::Popup))
1821 fl |= SWP_DEACTIVATE;
1822 }
1823 qt_WinSetWindowPos(frameWinId(), 0, 0, 0, 0, 0, fl);
1824 HSWITCH swEntry = maybeTopData() ? maybeTopData()->swEntry : NULLHANDLE;
1825 if (swEntry != NULLHANDLE) {
1826 SWCNTRL swc;
1827 WinQuerySwitchEntry(swEntry, &swc);
1828 swc.uchVisibility = SWL_INVISIBLE;
1829 WinChangeSwitchEntry(swEntry, &swc);
1830 }
1831 }
1832 if (q->isWindow()) {
1833 if (QWidgetBackingStore *bs = maybeBackingStore())
1834 bs->releaseBuffer();
1835 } else {
1836 invalidateBuffer(q->rect());
1837 }
1838 q->setAttribute(Qt::WA_Mapped, false);
1839}
1840
1841void QWidgetPrivate::show_sys()
1842{
1843 Q_Q(QWidget);
1844 if (q->testAttribute(Qt::WA_OutsideWSRange))
1845 return;
1846 q->setAttribute(Qt::WA_Mapped);
1847 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1848
1849 if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
1850 invalidateBuffer(q->rect());
1851 return;
1852 }
1853
1854 if (frameWinId() != NULLHANDLE) {
1855 ULONG fl = SWP_SHOW;
1856 if (q->isWindow()) {
1857 if (q->isMinimized()) {
1858 fl = SWP_MINIMIZE;
1859 } else if (q->isMaximized()) {
1860 fl |= SWP_MAXIMIZE;
1861 } else {
1862 fl |= SWP_RESTORE;
1863 }
1864
1865 if (!(q->testAttribute(Qt::WA_ShowWithoutActivating)
1866 || (q->windowType() == Qt::Popup)
1867 || (q->windowType() == Qt::ToolTip)
1868 || (q->windowType() == Qt::Tool))) {
1869 fl |= SWP_ACTIVATE;
1870 }
1871 }
1872
1873 qt_WinSetWindowPos(frameWinId(), 0, 0, 0, 0, 0, fl);
1874
1875 if (q->isWindow()) {
1876 if (q->windowType() != Qt::Popup &&
1877 q->windowType() != Qt::ToolTip &&
1878 q->windowType() != Qt::Tool &&
1879 (q->windowType() != Qt::Dialog || !q->parentWidget()) &&
1880 (q->windowType() != Qt::SplashScreen ||
1881 (data.window_flags & Qt::WindowTitleHint))
1882 ) {
1883 HSWITCH &swEntry = topData()->swEntry;
1884 if (!swEntry) {
1885 // lazily create a new window list entry
1886 HWND id = frameWinId();
1887 PID pid;
1888 WinQueryWindowProcess(id, &pid, NULL);
1889 SWCNTRL swc;
1890 memset(&swc, 0, sizeof(SWCNTRL));
1891 swc.hwnd = id;
1892 swc.idProcess = pid;
1893 swc.uchVisibility = SWL_VISIBLE;
1894 swc.fbJump = SWL_JUMPABLE;
1895 WinQueryWindowText(id, sizeof(swc.szSwtitle), swc.szSwtitle);
1896 swEntry = WinAddSwitchEntry(&swc);
1897 } else {
1898 SWCNTRL swc;
1899 WinQuerySwitchEntry(swEntry, &swc);
1900 swc.uchVisibility = SWL_VISIBLE;
1901 WinChangeSwitchEntry(swEntry, &swc);
1902 }
1903 }
1904
1905 ULONG wstyle = WinQueryWindowULong(frameWinId(), QWL_STYLE);
1906 if (wstyle & WS_MINIMIZED)
1907 data.window_state |= Qt::WindowMinimized;
1908 if (wstyle & WS_MAXIMIZED)
1909 data.window_state |= Qt::WindowMaximized;
1910 }
1911 }
1912
1913 invalidateBuffer(q->rect());
1914}
1915
1916void QWidgetPrivate::setFocus_sys()
1917{
1918 Q_Q(QWidget);
1919 if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
1920 WinSetFocus(HWND_DESKTOP, q->effectiveWinId());
1921}
1922
1923void QWidgetPrivate::raise_sys()
1924{
1925 Q_Q(QWidget);
1926 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1927 if (frameWinId() != NULLHANDLE)
1928 qt_WinSetWindowPos(frameWinId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
1929 Q_UNUSED(q);
1930}
1931
1932void QWidgetPrivate::lower_sys()
1933{
1934 Q_Q(QWidget);
1935 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1936 if (frameWinId() != NULLHANDLE)
1937 qt_WinSetWindowPos(frameWinId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER);
1938 invalidateBuffer(q->rect());
1939}
1940
1941void QWidgetPrivate::stackUnder_sys(QWidget* w)
1942{
1943 Q_Q(QWidget);
1944 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1945 if (frameWinId() != NULLHANDLE && w->d_func()->frameWinId() != NULLHANDLE)
1946 WinSetWindowPos(frameWinId(), w->d_func()->frameWinId(), 0, 0, 0, 0, SWP_ZORDER);
1947 invalidateBuffer(q->rect());
1948}
1949
1950#define XCOORD_MAX 32767
1951#define WRECT_MAX 32767
1952
1953/*
1954 Helper function for non-toplevel widgets. Helps to map Qt's 32bit
1955 coordinate system to PM 16bit coordinate system.
1956
1957 This code is duplicated from the X11 code, so any changes there
1958 should also (most likely) be reflected here.
1959
1960 (In all comments below: s/X/PM/g)
1961 */
1962
1963void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
1964{
1965 Q_Q(QWidget);
1966 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1967
1968 /*
1969 There are up to four different coordinate systems here:
1970 Qt coordinate system for this widget.
1971 X coordinate system for this widget (relative to wrect).
1972 Qt coordinate system for parent
1973 X coordinate system for parent (relative to parent's wrect).
1974 */
1975 QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
1976 QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
1977 QRect wrect;
1978 //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)
1979 QRect xrect = data.crect;
1980
1981 const QWidget *const parent = q->parentWidget();
1982 QRect parentWRect = parent->data->wrect;
1983
1984 if (parentWRect.isValid()) {
1985 // parent is clipped, and we have to clip to the same limit as parent
1986 if (!parentWRect.contains(xrect)) {
1987 xrect &= parentWRect;
1988 wrect = xrect;
1989 //translate from parent's to my Qt coord sys
1990 wrect.translate(-data.crect.topLeft());
1991 }
1992 //translate from parent's Qt coords to parent's X coords
1993 xrect.translate(-parentWRect.topLeft());
1994
1995 } else {
1996 // parent is not clipped, we may or may not have to clip
1997
1998 if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
1999 // This is where the main optimization is: we are already
2000 // clipped, and if our clip is still valid, we can just
2001 // move our window, and do not need to move or clip
2002 // children
2003
2004 QRect vrect = xrect & parent->rect();
2005 vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
2006 if (data.wrect.contains(vrect)) {
2007 xrect = data.wrect;
2008 xrect.translate(data.crect.topLeft());
2009 if (q->internalWinId() != NULLHANDLE) {
2010 Q_ASSERT(parent->internalWinId() != NULLHANDLE);
2011 int h = parent->height();
2012 qt_WinSetWindowPos(q->internalWinId(), 0, xrect.x(),
2013 // flip y coordinate
2014 h - (xrect.y() + xrect.height()),
2015 xrect.width(), xrect.height(),
2016 SWP_MOVE | SWP_SIZE);
2017 }
2018 return;
2019 }
2020 }
2021
2022 if (!validRange.contains(xrect)) {
2023 // we are too big, and must clip
2024 xrect &=wrectRange;
2025 wrect = xrect;
2026 wrect.translate(-data.crect.topLeft());
2027 //parent's X coord system is equal to parent's Qt coord
2028 //sys, so we don't need to map xrect.
2029 }
2030
2031 }
2032
2033
2034 // unmap if we are outside the valid window system coord system
2035 bool outsideRange = !xrect.isValid();
2036 bool mapWindow = false;
2037 if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
2038 q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
2039 if (outsideRange) {
2040 if (q->internalWinId() != NULLHANDLE)
2041 qt_WinSetWindowPos(q->internalWinId(), 0, 0, 0, 0, 0, SWP_HIDE);
2042 q->setAttribute(Qt::WA_Mapped, false);
2043 } else if (!q->isHidden()) {
2044 mapWindow = true;
2045 }
2046 }
2047
2048 if (outsideRange)
2049 return;
2050
2051 bool jump = (data.wrect != wrect);
2052 data.wrect = wrect;
2053
2054 // and now recursively for all children...
2055 for (int i = 0; i < children.size(); ++i) {
2056 QObject *object = children.at(i);
2057 if (object->isWidgetType()) {
2058 QWidget *w = static_cast<QWidget *>(object);
2059 if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
2060 w->d_func()->setWSGeometry();
2061 }
2062 }
2063
2064 // move ourselves to the new position and map (if necessary) after
2065 // the movement. Rationale: moving unmapped windows is much faster
2066 // than moving mapped windows
2067 if (q->internalWinId() != NULLHANDLE) {
2068 int h = parent->height();
2069 if (parent->internalWinId() == NULLHANDLE) {
2070 xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
2071 h = q->nativeParentWidget()->height();
2072 }
2073 qt_WinSetWindowPos(q->internalWinId(), 0, xrect.x(),
2074 // flip y coordinate
2075 h - (xrect.y() + xrect.height()),
2076 xrect.width(), xrect.height(), SWP_MOVE | SWP_SIZE);
2077 }
2078 if (mapWindow && !dontShow) {
2079 q->setAttribute(Qt::WA_Mapped);
2080 if (q->internalWinId() != NULLHANDLE)
2081 qt_WinSetWindowPos(q->internalWinId(), 0, 0, 0, 0, 0, SWP_SHOW);
2082 }
2083
2084 if (jump && q->internalWinId() != NULLHANDLE)
2085 WinInvalidateRect(q->internalWinId(), NULL, FALSE);
2086}
2087
2088//
2089// The internal qPMRequestConfig, defined in qapplication_pm.cpp, stores move,
2090// resize and setGeometry requests for a widget that is already
2091// processing a config event. The purpose is to avoid recursion.
2092//
2093void qPMRequestConfig(WId, int, int, int, int, int);
2094
2095void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
2096{
2097 Q_Q(QWidget);
2098 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2099 if (extra) { // any size restrictions?
2100 w = qMin(w,extra->maxw);
2101 h = qMin(h,extra->maxh);
2102 w = qMax(w,extra->minw);
2103 h = qMax(h,extra->minh);
2104 }
2105 if (q->isWindow())
2106 topData()->normalGeometry = QRect(0, 0, -1, -1);
2107
2108 QSize oldSize(q->size());
2109 QPoint oldPos(q->pos());
2110
2111 if (!q->isWindow())
2112 isMove = (data.crect.topLeft() != QPoint(x, y));
2113 bool isResize = w != oldSize.width() || h != oldSize.height();
2114
2115 if (!isMove && !isResize)
2116 return;
2117
2118 HWND fId = frameWinId();
2119
2120 if (isResize && !q->testAttribute(Qt::WA_StaticContents) &&
2121 q->internalWinId() != NULLHANDLE) {
2122 RECTL rcl = { 0, 0, data.crect.width(), data.crect.height() };
2123 WinValidateRect(q->internalWinId(), &rcl, FALSE);
2124 }
2125
2126 if (isResize)
2127 data.window_state &= ~Qt::WindowMaximized;
2128
2129 if (data.window_state & Qt::WindowFullScreen) {
2130 data.window_state &= ~Qt::WindowFullScreen;
2131 }
2132
2133 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
2134 const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
2135
2136 if (q->testAttribute(Qt::WA_WState_ConfigPending)) { // processing config event
2137 if (q->internalWinId() != NULLHANDLE)
2138 qPMRequestConfig(q->internalWinId(), isMove ? 2 : 1, x, y, w, h);
2139 } else {
2140 if (!q->testAttribute(Qt::WA_DontShowOnScreen))
2141 q->setAttribute(Qt::WA_WState_ConfigPending);
2142 if (q->windowType() == Qt::Desktop) {
2143 data.crect.setRect(x, y, w, h);
2144 } else if (q->isWindow()) {
2145 int sh = qt_display_height();
2146 QRect fs(frameStrut());
2147 if (extra) {
2148 fs.setLeft(x - fs.left());
2149 fs.setTop(y - fs.top());
2150 fs.setRight((x + w - 1) + fs.right());
2151 fs.setBottom((y + h - 1) + fs.bottom());
2152 }
2153 if (w == 0 || h == 0) {
2154 q->setAttribute(Qt::WA_OutsideWSRange, true);
2155 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
2156 hide_sys();
2157 data.crect = QRect(x, y, w, h);
2158 } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
2159 q->setAttribute(Qt::WA_OutsideWSRange, false);
2160
2161 // put the window in its place and show it
2162 WinSetWindowPos(fId, 0, fs.x(),
2163 // flip y coordinate
2164 sh - (fs.y() + fs.height()),
2165 fs.width(), fs.height(), SWP_MOVE | SWP_SIZE);
2166 data.crect.setRect(x, y, w, h);
2167
2168 show_sys();
2169 } else if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
2170 q->setAttribute(Qt::WA_OutsideWSRange, false);
2171 // If the window is hidden and in maximized state or minimized, instead of moving the
2172 // window, set the normal position of the window.
2173 SWP swp;
2174 WinQueryWindowPos(fId, &swp);
2175 if (((swp.fl & SWP_MAXIMIZE) && !WinIsWindowVisible(fId)) ||
2176 (swp.fl & SWP_MINIMIZE)) {
2177 WinSetWindowUShort(fId, QWS_XRESTORE, fs.x());
2178 WinSetWindowUShort(fId, QWS_YRESTORE, // flip y coordinate
2179 sh - (fs.y() + fs.height()));
2180 WinSetWindowUShort(fId, QWS_CXRESTORE, fs.width());
2181 WinSetWindowUShort(fId, QWS_CYRESTORE, fs.height());
2182 } else {
2183 WinSetWindowPos(fId, 0, fs.x(),
2184 // flip y coordinate
2185 sh - (fs.y() + fs.height()),
2186 fs.width(), fs.height(), SWP_MOVE | SWP_SIZE);
2187 }
2188 if (!q->isVisible())
2189 WinInvalidateRect(q->internalWinId(), NULL, FALSE);
2190 if (!(swp.fl & SWP_MINIMIZE)) {
2191 // If the layout has heightForWidth, the WinSetWindowPos() above can
2192 // change the size/position, so refresh them. Note that if the
2193 // widget is minimized, we don't update its size in Qt (see
2194 // QApplication::translateConfigEvent()).
2195 WinQueryWindowPos(fId, &swp);
2196 // flip y coordinate
2197 swp.y = sh - (swp.y + swp.cy);
2198 QRect fs(frameStrut());
2199 data.crect.setRect(swp.x + fs.left(),
2200 swp.y + fs.top(),
2201 swp.cx - fs.left() - fs.right(),
2202 swp.cy - fs.top() - fs.bottom());
2203 isResize = data.crect.size() != oldSize;
2204 }
2205 } else {
2206 q->setAttribute(Qt::WA_OutsideWSRange, false);
2207 data.crect.setRect(x, y, w, h);
2208 }
2209 } else {
2210 QRect oldGeom(data.crect);
2211 data.crect.setRect(x, y, w, h);
2212 if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) {
2213 // Top-level resize optimization does not work for native child widgets;
2214 // disable it for this particular widget.
2215 if (inTopLevelResize)
2216 tlwExtra->inTopLevelResize = false;
2217
2218 if (!isResize)
2219 moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
2220 else
2221 invalidateBuffer_resizeHelper(oldPos, oldSize);
2222
2223 if (inTopLevelResize)
2224 tlwExtra->inTopLevelResize = true;
2225 }
2226 if (q->testAttribute(Qt::WA_WState_Created))
2227 setWSGeometry();
2228 }
2229 q->setAttribute(Qt::WA_WState_ConfigPending, false);
2230 }
2231
2232 if (q->isWindow() && q->isVisible() && isResize && !inTopLevelResize) {
2233 invalidateBuffer(q->rect()); //after the resize
2234 }
2235
2236 // Process events immediately rather than in translateConfigEvent to
2237 // avoid windows message process delay.
2238 if (q->isVisible()) {
2239 if (isMove && q->pos() != oldPos) {
2240 // in QMoveEvent, pos() and oldPos() exclude the frame, adjust them
2241 QRect fs(frameStrut());
2242 QMoveEvent e(q->pos() + fs.topLeft(), oldPos + fs.topLeft());
2243 QApplication::sendEvent(q, &e);
2244 }
2245 if (isResize) {
2246 static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
2247 // If we have a backing store with static contents, we have to disable the top-level
2248 // resize optimization in order to get invalidated regions for resized widgets.
2249 // The optimization discards all invalidateBuffer() calls since we're going to
2250 // repaint everything anyways, but that's not the case with static contents.
2251 const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
2252 && !extra->topextra->inTopLevelResize
2253 && (!extra->topextra->backingStore
2254 || !extra->topextra->backingStore->hasStaticContents());
2255 if (setTopLevelResize)
2256 extra->topextra->inTopLevelResize = true;
2257 QResizeEvent e(q->size(), oldSize);
2258 QApplication::sendEvent(q, &e);
2259 if (setTopLevelResize)
2260 extra->topextra->inTopLevelResize = false;
2261 }
2262 } else {
2263 if (isMove && q->pos() != oldPos)
2264 q->setAttribute(Qt::WA_PendingMoveEvent, true);
2265 if (isResize)
2266 q->setAttribute(Qt::WA_PendingResizeEvent, true);
2267 }
2268}
2269
2270void QWidgetPrivate::setConstraints_sys()
2271{
2272 // @todo is there a way to show/hide the Maximize button according to
2273 // the shouldShowMaximizeButton() return value?
2274}
2275
2276HWND QWidgetPrivate::effectiveFrameWinId() const
2277{
2278 Q_Q(const QWidget);
2279 HWND fid = frameWinId();
2280 if (fid != NULLHANDLE || !q->testAttribute(Qt::WA_WState_Created))
2281 return fid;
2282 QWidget *realParent = q->nativeParentWidget();
2283 Q_ASSERT(realParent);
2284 Q_ASSERT(realParent->d_func()->frameWinId());
2285 return realParent->d_func()->frameWinId();
2286}
2287
2288void QWidgetPrivate::scroll_sys(int dx, int dy)
2289{
2290 Q_Q(QWidget);
2291 scrollChildren(dx, dy);
2292
2293 if (!paintOnScreen()) {
2294 scrollRect(q->rect(), dx, dy);
2295 } else {
2296 // @todo ask qt_WinScrollWindowWell() to erase background if
2297 // WA_OpaquePaintEvent is reset?
2298 //if (!q->testAttribute(Qt::WA_OpaquePaintEvent))
2299 // ;
2300 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2301 qt_WinScrollWindowWell(q->internalWinId(), dx, -dy, NULL);
2302 }
2303}
2304
2305void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
2306{
2307 Q_Q(QWidget);
2308
2309 if (!paintOnScreen()) {
2310 scrollRect(r, dx, dy);
2311 } else {
2312 int h = data.crect.height();
2313 // flip y coordinate (all coordinates are inclusive)
2314 RECTL rcl = { r.left(), h - (r.bottom() + 1), r.right(), h - (r.top() + 1) };
2315
2316 // @todo ask qt_WinScrollWindowWell() to erase background if
2317 // WA_OpaquePaintEvent is reset?
2318 //if (!q->testAttribute(Qt::WA_OpaquePaintEvent))
2319 // ;
2320 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2321 qt_WinScrollWindowWell(q->internalWinId(), dx, -dy, &rcl);
2322 }
2323}
2324
2325int QWidget::metric(PaintDeviceMetric m) const
2326{
2327 Q_D(const QWidget);
2328 LONG val;
2329 if (m == PdmWidth) {
2330 val = data->crect.width();
2331 } else if (m == PdmHeight) {
2332 val = data->crect.height();
2333 } else {
2334 HDC hdc = GpiQueryDevice(qt_display_ps());
2335 switch (m) {
2336 case PdmDpiX:
2337 case PdmPhysicalDpiX:
2338 if (d->extra && d->extra->customDpiX)
2339 val = d->extra->customDpiX;
2340 else if (d->parent)
2341 val = static_cast<QWidget *>(d->parent)->metric(m);
2342 else
2343 DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 1, &val);
2344 break;
2345 case PdmDpiY:
2346 case PdmPhysicalDpiY:
2347 if (d->extra && d->extra->customDpiY)
2348 val = d->extra->customDpiY;
2349 else if (d->parent)
2350 val = static_cast<QWidget *>(d->parent)->metric(m);
2351 else
2352 DevQueryCaps(hdc, CAPS_VERTICAL_FONT_RES, 1, &val);
2353 break;
2354 case PdmWidthMM:
2355 DevQueryCaps(hdc, CAPS_HORIZONTAL_RESOLUTION, 1, &val);
2356 val = data->crect.width() * 1000 / val;
2357 break;
2358 case PdmHeightMM:
2359 DevQueryCaps(hdc, CAPS_VERTICAL_RESOLUTION, 1, &val);
2360 val = data->crect.height() * 1000 / val;
2361 break;
2362 case PdmNumColors:
2363 DevQueryCaps(hdc, CAPS_COLORS, 1, &val);
2364 break;
2365 case PdmDepth:
2366 LONG colorInfo[2];
2367 DevQueryCaps(hdc, CAPS_COLOR_PLANES, 2, colorInfo);
2368 val = colorInfo[0] * colorInfo[1];
2369 break;
2370 default:
2371 val = 0;
2372 qWarning("QWidget::metric: Invalid metric command");
2373 }
2374 }
2375 return val;
2376}
2377
2378void QWidgetPrivate::createSysExtra()
2379{
2380}
2381
2382void QWidgetPrivate::deleteSysExtra()
2383{
2384}
2385
2386void QWidgetPrivate::createTLSysExtra()
2387{
2388 extra->topextra->fId = NULLHANDLE;
2389 extra->topextra->swEntry = NULLHANDLE;
2390 extra->topextra->iconPointer = NULLHANDLE;
2391}
2392
2393void QWidgetPrivate::deleteTLSysExtra()
2394{
2395 if (extra->topextra->iconPointer != NULLHANDLE)
2396 WinDestroyPointer(extra->topextra->iconPointer);
2397 if (extra->topextra->swEntry != NULLHANDLE)
2398 WinRemoveSwitchEntry(extra->topextra->swEntry);
2399 // Note: extra->topextra->fId is cleaned up in QWidget::destroy()
2400}
2401
2402void QWidgetPrivate::registerDropSite(bool on)
2403{
2404 // @todo implement
2405}
2406
2407void QWidgetPrivate::setMask_sys(const QRegion &region)
2408{
2409 // @todo implement
2410}
2411
2412void QWidgetPrivate::updateFrameStrut()
2413{
2414 Q_Q(QWidget);
2415
2416 if (!q->testAttribute(Qt::WA_WState_Created))
2417 return;
2418
2419 if (q->internalWinId() == NULLHANDLE) {
2420 data.fstrut_dirty = false;
2421 return;
2422 }
2423
2424 QTLWExtra *top = maybeTopData();
2425 if (!top || top->fId == NULLHANDLE) {
2426 data.fstrut_dirty = false;
2427 return;
2428 }
2429
2430 // this widget has WC_FRAME
2431 SWP swp;
2432 WinQueryWindowPos(top->fId, &swp);
2433 SWP cswp;
2434 WinQueryWindowPos(data.winid, &cswp);
2435 // flip y coordinates
2436 swp.y = qt_display_height() - (swp.y + swp.cy);
2437 cswp.y = swp.cy - (cswp.y + cswp.cy);
2438 QRect &fs = top->frameStrut;
2439 fs.setCoords(cswp.x, cswp.y, swp.cx - cswp.x - cswp.cx,
2440 swp.cy - cswp.y - cswp.cy);
2441 data.crect.setRect(swp.x + cswp.x, swp.y + cswp.y, cswp.cx, cswp.cy);
2442
2443 data.fstrut_dirty = false;
2444}
2445
2446void QWidgetPrivate::setWindowOpacity_sys(qreal level)
2447{
2448 // @todo implement
2449}
2450
2451QPaintEngine *QWidget::paintEngine() const
2452{
2453 // @todo this is a place to return some direct on-screen PaintEngine once
2454 // we decide to support it
2455
2456 // We set this bit which is checked in setAttribute for
2457 // Qt::WA_PaintOnScreen. We do this to allow these two scenarios:
2458 //
2459 // 1. Users accidentally set Qt::WA_PaintOnScreen on X and port to
2460 // OS/2 which would mean suddenly their widgets stop working.
2461 //
2462 // 2. Users set paint on screen and subclass paintEngine() to
2463 // return 0, in which case we have a "hole" in the backingstore
2464 // allowing use of GPI directly.
2465 //
2466 // 1 is WRONG, but to minimize silent failures, we have set this
2467 // bit to ignore the setAttribute call. 2. needs to be
2468 // supported because its our only means of embeddeding native
2469 // graphics stuff.
2470 const_cast<QWidgetPrivate *>(d_func())->noPaintOnScreen = 1;
2471
2472 return 0;
2473}
2474
2475QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
2476{
2477 Q_Q(QWidget);
2478 QWindowSurface *surface = QPMDiveWindowSurface::create(q);
2479 if (!surface)
2480 surface = new QRasterWindowSurface(q);
2481 return surface;
2482}
2483
2484void QWidgetPrivate::setModal_sys()
2485{
2486}
2487
2488/*!
2489 \internal
2490
2491 Validates areas of this widget covered by (intersected with) its children
2492 and sibling widgets.
2493
2494 Clip regions of all relative widgets (set by WinSetClipRegion()) are taken
2495 into account.
2496 */
2497void QWidgetPrivate::validateObstacles()
2498{
2499 Q_ASSERT(data.winid != NULLHANDLE);
2500
2501 RECTL updateRcl;
2502 if (WinQueryUpdateRect(data.winid, &updateRcl)) {
2503 // the update rectangle may be empty
2504 if (updateRcl.xLeft != updateRcl.xRight &&
2505 updateRcl.yBottom != updateRcl.yTop) {
2506 qt_WinProcessWindowObstacles(data.winid, &updateRcl, 0, 0);
2507 }
2508 }
2509}
2510
2511QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.