source: branches/4.5.1/src/gui/kernel/qwidget_pm.cpp

Last change on this file was 508, checked in by Dmitry A. Kuminov, 16 years ago

gui: Fixed: The default application icon embedded into the executable was not actually used as the default window icon for top-level widgets.

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