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

Last change on this file was 1108, checked in by Silvan Scherrer, 13 years ago

fix seWindowsIcon problem, reverted 1107 and did different

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