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

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

gui: Implemented setting window icons for top-level windows with QWidget::setWindowIcon() (closes #55).

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