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

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

gui: Added QWidget::addPmEventFilter()/removPmEventFilter() (OS/2 specific).

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