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

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

gui: Implemented QSessionManager and removed the QT_NO_SESSIONMANAGER define (closes #100).

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