source: trunk/src/kernel/qwidget_pm.cpp@ 77

Last change on this file since 77 was 77, checked in by dmik, 19 years ago

Implemented the OS/2 version of the QSessionManager class (see ticket:15 for more details); QT_NO_SESSIONMANAGER is no more defined by default.

  • Property svn:keywords set to Id
File size: 98.7 KB
Line 
1/****************************************************************************
2** $Id: qwidget_pm.cpp 77 2006-04-01 22:41:47Z dmik $
3**
4** Implementation of QWidget and QWindow classes for OS/2
5**
6** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 netlabs.org. Further OS/2 Development.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qapplication.h"
39#include "qapplication_p.h"
40#include "qpainter.h"
41#include "qbitmap.h"
42#include "qwidgetlist.h"
43#include "qwidgetintdict.h"
44#include "qobjectlist.h"
45#include "qaccel.h"
46#include "qimage.h"
47#include "qfocusdata.h"
48#include "qlayout.h"
49#include "qt_os2.h"
50#include "qpaintdevicemetrics.h"
51#include "qcursor.h"
52#include <private/qapplication_p.h>
53/// @todo (dmik) remove?
54//#include <private/qinputcontext_p.h>
55
56const QString qt_reg_winclass( int ); // defined in qapplication_pm.cpp
57/// @todo (dmik) later?
58//void qt_olednd_unregister( QWidget* widget, QOleDropTarget *dst ); // dnd_win
59//QOleDropTarget* qt_olednd_register( QWidget* widget );
60
61
62extern bool qt_nograb();
63
64// defined in qapplication_pm.cpp
65extern void qt_sendBlocked( QObject *obj, QWidget *modal, QEvent *e, bool override );
66#if !defined (QT_NO_SESSIONMANAGER)
67extern bool qt_about_to_destroy_wnd;
68#endif
69
70static QWidget *mouseGrb = 0;
71static QCursor *mouseGrbCur = 0;
72static QWidget *keyboardGrb = 0;
73
74extern "C" MRESULT EXPENTRY QtWndProc( HWND, ULONG, MPARAM, MPARAM );
75extern PFNWP QtOldFrameProc;
76extern "C" MRESULT EXPENTRY QtFrameProc( HWND, ULONG, MPARAM, MPARAM );
77
78PFNWP QtOldSysMenuProc;
79extern "C" MRESULT EXPENTRY QtSysMenuProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
80{
81 if ( msg == WM_MENUEND ) {
82 // the pull-down menu is closed, always dismiss the system menu itself
83 WinPostMsg( hwnd, MM_ENDMENUMODE, MPFROMSHORT(TRUE), 0 );
84 }
85 return QtOldSysMenuProc( hwnd, msg, mp1, mp2 );
86}
87
88#if !defined (QT_PM_NO_WIDGETMASK)
89
90//#define DEBUG_WIDGETMASK
91
92/**
93 * \internal
94 * Extended version of WinQueryClipRegion(). If the given window has a
95 * clip region, the given region will receive a copy of the clip region
96 * clipped to the current window rectangle. If there is no clip region,
97 * the given region will contain only the window rectangle on return.
98 */
99static void qt_WinQueryClipRegionOrRect( HWND hwnd, HRGN hrgn )
100{
101 RECTL rcl;
102 WinQueryWindowRect( hwnd, &rcl );
103
104 HPS hps = qt_display_ps();
105 GpiSetRegion( hps, hrgn, 1, &rcl );
106 if ( WinQueryClipRegion( hwnd, 0 ) != QCRGN_NO_CLIP_REGION ) {
107 HRGN hrgnTemp = GpiCreateRegion( hps, 0, NULL );
108 WinQueryClipRegion( hwnd, hrgnTemp );
109 GpiCombineRegion( hps, hrgn, hrgnTemp, hrgn, CRGN_AND );
110 GpiDestroyRegion( hps, hrgnTemp );
111 }
112}
113
114/** \internal flags for qt_WinProcessWindowObstacles() */
115enum {
116 PWO_Children = 0x01,
117 PWO_Sibings = 0x02,
118 PWO_Ancestors = 0x04,
119 PWO_TopLevel = 0x80000000,
120 // PWO_Default is suitable in most cases (for simple paint operations)
121 PWO_Default = PWO_Children | PWO_Sibings | PWO_Ancestors,
122};
123
124/**
125 * \internal
126 * Extended version of WinInvalidateRegion(): invalidates the specified region
127 * of the given window and regions of children from \a hwndFrom to \a hwndTo
128 * if they intersect with the invalid region. If either of child window
129 * handles is NULLHANDLE, children are not invalidated at all. Also, HWND_TOP
130 * can be used as \a hwndFrom, HWND_BOTTOM \a can be used as \a hwndTo.
131 */
132static BOOL qt_WinInvalidateRegionEx( HWND hwnd, HRGN hrgn,
133 HWND hwndFrom, HWND hwndTo )
134{
135#if defined (DEBUG_WIDGETMASK)
136 QWidget *w = QWidget::find( hwnd );
137 qDebug( "qt_WinInvalidateRegionEx: hwnd=%08lX (%s/%s) "
138 "hwndFrom=%08lX hwndTo=%08lX",
139 hwnd, w ? w->name() : 0, w ? w->className() : 0, hwndFrom, hwndTo );
140#endif
141
142 if ( hwndFrom == HWND_TOP )
143 hwndFrom = WinQueryWindow( hwnd, QW_TOP );
144 if ( hwndTo == HWND_BOTTOM )
145 hwndTo = WinQueryWindow( hwnd, QW_BOTTOM );
146
147 if ( hwndFrom == 0 || hwndTo == 0 )
148 return WinInvalidateRegion( hwnd, hrgn, FALSE );
149
150 if ( WinQueryWindow( hwndFrom, QW_PARENT ) != hwnd ||
151 WinQueryWindow( hwndTo, QW_PARENT ) != hwnd )
152 return FALSE;
153
154 HPS hps = qt_display_ps();
155
156 SWP swp;
157 HWND child = hwndFrom;
158 HRGN hrgnChild = GpiCreateRegion( hps, 0, NULL );
159 HRGN hrgnInv = GpiCreateRegion( hps, 0, NULL );
160 GpiCombineRegion( hps, hrgnInv, hrgn, 0, CRGN_COPY );
161
162 LONG cmplx = RGN_RECT;
163
164 while ( child ) {
165 WinQueryWindowPos( child, &swp );
166#if defined (DEBUG_WIDGETMASK)
167 w = QWidget::find( child );
168 qDebug( " child=%08lX [fl=%08lX] (%s/%s)", child, swp.fl,
169 w ? w->name() : 0, w ? w->className() : 0 );
170#endif
171 // proceed only if not hidden
172 if ( swp.fl & SWP_SHOW ) {
173 // get sibling's bounds (clip region or rect)
174 qt_WinQueryClipRegionOrRect( child, hrgnChild );
175 // translate the region to the parent's coordinate system
176 POINTL ptl = { swp.x, swp.y };
177 GpiOffsetRegion( hps, hrgnChild, &ptl );
178 // intersect the child's region with the invalid one
179 // and invalidate if not NULL
180 cmplx = GpiCombineRegion( hps, hrgnChild, hrgnChild, hrgnInv,
181 CRGN_AND );
182 if ( cmplx != RGN_NULL ) {
183 POINTL ptl2 = { -swp.x, -swp.y };
184 GpiOffsetRegion( hps, hrgnChild, &ptl2 );
185 WinInvalidateRegion( child, hrgnChild, TRUE );
186 GpiOffsetRegion( hps, hrgnChild, &ptl );
187 // substract the invalidated area from the widget's region
188 // (no need to invalidate it any more)
189 cmplx = GpiCombineRegion( hps, hrgnInv, hrgnInv, hrgnChild,
190 CRGN_DIFF );
191#if defined (DEBUG_WIDGETMASK)
192 qDebug( " processed" );
193#endif
194 // finish if nothing left
195 if ( cmplx == RGN_NULL )
196 break;
197 }
198 }
199 // iterate to the next window (below)
200 if ( child == hwndTo )
201 break;
202 child = WinQueryWindow( child, QW_NEXT );
203 }
204
205 BOOL ok = (cmplx == RGN_NULL) || (child == hwndTo);
206
207 if ( ok ) {
208 // invalidate what's left invalid after substracting children
209 WinInvalidateRegion( hwnd, hrgnInv, FALSE );
210 }
211
212 GpiDestroyRegion( hps, hrgnInv );
213 GpiDestroyRegion( hps, hrgnChild );
214
215 return ok;
216}
217
218/**
219 * \internal
220 * Helper function to collect all relative windows intersecting with the
221 * given window and placed above it in z-order.
222 *
223 * \param hwnd window in question
224 * \param prcl rectangle (in window coordinates) to limit processing to
225 * (if null, the whole window rectange is used)
226 * \param hrgn region where to combine all obstacles
227 * (if 0, obstacles are directly validated instead of collecting)
228 * \param op region operation perfomed when combining obstacles (CRGN_*)
229 * \param flags flags defining the scope (PWO_* ORed together)
230 *
231 * \return complexity of the combined region (only when \a hrgn is not 0)
232 */
233static LONG qt_WinProcessWindowObstacles( HWND hwnd, PRECTL prcl, HRGN hrgn,
234 LONG op, LONG flags = PWO_Default )
235{
236 Q_ASSERT( hwnd );
237
238 HPS displayPS = qt_display_ps();
239
240#if defined (DEBUG_WIDGETMASK)
241 QWidget *w = QWidget::find( hwnd );
242 qDebug( "qt_WinProcessWindowObstacles: hwnd=%08lX (%s/%s), prcl=%p "
243 "hrgn=%08lX, op=%ld flags=%08lX",
244 hwnd, w->name(), w->className(), prcl, hrgn, op, flags );
245#endif
246
247 SWP swpSelf;
248 WinQueryWindowPos( hwnd, &swpSelf );
249
250 RECTL rclSelf = { 0, 0, swpSelf.cx, swpSelf.cy };
251 if ( prcl )
252 rclSelf = *prcl;
253
254 HRGN whrgn = GpiCreateRegion( displayPS, 0, NULL );
255
256 LONG cmplx = RGN_NULL;
257 HWND relative;
258 SWP swp;
259
260 // first, go through all children (in z-order)
261 if ( flags & PWO_Children ) {
262 relative = WinQueryWindow( hwnd, QW_BOTTOM );
263 if ( relative != NULLHANDLE ) {
264 for ( ; relative != HWND_TOP; relative = swp.hwndInsertBehind ) {
265 WinQueryWindowPos( relative, &swp );
266#if defined (DEBUG_WIDGETMASK)
267 w = QWidget::find( relative );
268 qDebug( " child=%08lX [fl=%08lX] (%s/%s)", relative, swp.fl,
269 w ? w->name() : 0, w ? w->className() : 0 );
270#endif
271 // skip if hidden
272 if ( !(swp.fl & SWP_SHOW) )
273 continue;
274 // rough check for intersection
275 if ( swp.x >= rclSelf.xRight || swp.y >= rclSelf.yTop ||
276 swp.x + swp.cx <= rclSelf.xLeft ||
277 swp.y + swp.cy <= rclSelf.yBottom )
278 continue;
279 // get the bounds (clip region or rect)
280 qt_WinQueryClipRegionOrRect( relative, whrgn );
281 // translate the region to this window's coordinate system
282 POINTL ptl = { swp.x, swp.y };
283 GpiOffsetRegion( displayPS, whrgn, &ptl );
284 // process the region
285 if ( hrgn != NULLHANDLE ) {
286 cmplx = GpiCombineRegion( displayPS, hrgn, hrgn, whrgn, op );
287 } else {
288 WinValidateRegion( hwnd, whrgn, FALSE );
289 }
290#if defined (DEBUG_WIDGETMASK)
291 qDebug( " extracted" );
292#endif
293 }
294 }
295 }
296
297 HWND desktop = WinQueryDesktopWindow( 0, 0 );
298 HWND parent = WinQueryWindow( hwnd, QW_PARENT );
299
300 // next, go through all siblings placed above (in z-order),
301 // but only if they are not top-level windows (that cannot be
302 // non-rectangular and thus are always correctly clipped by the system)
303 if ( (flags & PWO_Sibings) && parent != desktop ) {
304 for ( relative = swpSelf.hwndInsertBehind;
305 relative != HWND_TOP; relative = swp.hwndInsertBehind ) {
306 WinQueryWindowPos( relative, &swp );
307#if defined (DEBUG_WIDGETMASK)
308 w = QWidget::find( relative );
309 qDebug( " sibling=%08lX [fl=%08lX] (%s/%s)", relative, swp.fl,
310 w ? w->name() : 0, w ? w->className() : 0 );
311#endif
312 // skip if hidden
313 if ( !(swp.fl & SWP_SHOW) )
314 continue;
315 // rough check for intersection
316 if ( swp.x >= swpSelf.x + rclSelf.xRight ||
317 swp.y >= swpSelf.y + rclSelf.yTop ||
318 swp.x + swp.cx <= swpSelf.x + rclSelf.xLeft ||
319 swp.y + swp.cy <= swpSelf.y + rclSelf.yBottom )
320 continue;
321 // get the bounds (clip region or rect)
322 qt_WinQueryClipRegionOrRect( relative, whrgn );
323 // translate the region to this window's coordinate system
324 POINTL ptl = { swp.x - swpSelf.x, swp.y - swpSelf.y };
325 GpiOffsetRegion( displayPS, whrgn, &ptl );
326 // process the region
327 if ( hrgn != NULLHANDLE ) {
328 cmplx = GpiCombineRegion( displayPS, hrgn, hrgn, whrgn, op );
329 } else {
330 WinValidateRegion( hwnd, whrgn, FALSE );
331 }
332#if defined (DEBUG_WIDGETMASK)
333 qDebug( " extracted" );
334#endif
335 }
336 }
337
338 // last, go through all siblings of our parent and its ancestors
339 // placed above (in z-order)
340 if ( flags & PWO_Ancestors ) {
341 POINTL delta = { swpSelf.x, swpSelf.y };
342 while ( parent != desktop ) {
343 HWND grandParent = WinQueryWindow( parent, QW_PARENT );
344 if ( !(flags & PWO_TopLevel) ) {
345 // When PWO_TopLevel is not specified, top-level windows
346 // (children of the desktop) are not processed. It makes sense
347 // when qt_WinProcessWindowObstacles() is used to clip out
348 // overlying windows during regular paint operations (WM_PAINT
349 // processing or drawing in a window directly through
350 // WinGetPS()): in this case, top-level windows are always
351 // correctly clipped out by the system (because they cannot be
352 // non-rectangular).
353 if ( grandParent == desktop )
354 break;
355 }
356
357 WinQueryWindowPos( parent, &swp );
358#if defined (DEBUG_WIDGETMASK)
359 w = QWidget::find( parent );
360 qDebug( " parent=%08lX [fl=%08lX] (%s/%s)", parent, swp.fl,
361 w ? w->name() : 0, w ? w->className() : 0 );
362#endif
363 delta.x += swp.x;
364 delta.y += swp.y;
365 for ( relative = swp.hwndInsertBehind;
366 relative != HWND_TOP; relative = swp.hwndInsertBehind ) {
367 WinQueryWindowPos( relative, &swp );
368#if defined (DEBUG_WIDGETMASK)
369 w = QWidget::find( relative );
370 qDebug( " ancestor=%08lX [fl=%08lX] (%s/%s)", relative, swp.fl,
371 w ? w->name() : 0, w ? w->className() : 0 );
372#endif
373 // skip if hidden
374 if ( !(swp.fl & SWP_SHOW) )
375 continue;
376 // rough check for intersection
377 if ( swp.x - delta.x >= rclSelf.xRight ||
378 swp.y - delta.y >= rclSelf.yTop ||
379 swp.x - delta.x + swp.cx <= rclSelf.xLeft ||
380 swp.y - delta.y + swp.cy <= rclSelf.yBottom )
381 continue;
382 // get the bounds (clip region or rect)
383 qt_WinQueryClipRegionOrRect( relative, whrgn );
384 // translate the region to this window's coordinate system
385 POINTL ptl = { swp.x - delta.x, swp.y - delta.y };
386 GpiOffsetRegion( displayPS, whrgn, &ptl );
387 // process the region
388 if ( hrgn != NULLHANDLE ) {
389 cmplx = GpiCombineRegion( displayPS, hrgn, hrgn, whrgn, op );
390 } else {
391 WinValidateRegion( hwnd, whrgn, FALSE );
392 }
393#if defined (DEBUG_WIDGETMASK)
394 qDebug( " extracted" );
395#endif
396 }
397 parent = grandParent;
398 }
399 }
400
401 GpiDestroyRegion( displayPS, whrgn );
402
403 return cmplx;
404}
405
406/**
407 * \internal
408 * Partial reimplementation of the WinSetWindowPos() API that obeys window clip
409 * regions. Currently supported flags are SWP_ZORDER, SWP_SHOW and SWP_HIDE.
410 * Other flags should not be used. Note that if any other flag is specified
411 * (alone or in addition to the supported ones), or if the given window is a
412 * top-level window, this function acts exactly like the original
413 * WinSetWindowPos() function.
414 */
415static BOOL qt_WinSetWindowPos( HWND hwnd, HWND hwndInsertBehind,
416 LONG x, LONG y, LONG cx, LONG cy,
417 ULONG fl )
418{
419#if defined (DEBUG_WIDGETMASK)
420 QWidget *w = QWidget::find( hwnd );
421 qDebug( "qt_WinSetWindowPos: hwnd=%08lX (%s/%s) fl=%08lX",
422 hwnd, w ? w->name() : 0, w ? w->className() : 0, fl );
423#endif
424
425 Q_ASSERT( (fl & ~(SWP_ZORDER | SWP_SHOW | SWP_HIDE)) == 0 );
426
427 HWND desktop = WinQueryDesktopWindow( 0, 0 );
428 if ( (fl & ~(SWP_ZORDER | SWP_SHOW | SWP_HIDE)) != 0 ||
429 hwnd == desktop || WinQueryWindow( hwnd, QW_PARENT ) == desktop ) {
430 return WinSetWindowPos( hwnd, hwndInsertBehind, x, y, cx, cy, fl );
431 }
432
433 SWP swpOld;
434 WinQueryWindowPos( hwnd, &swpOld );
435
436 // do some checks
437 if ( (fl & SWP_ZORDER) && swpOld.hwndInsertBehind == hwndInsertBehind )
438 fl &= ~SWP_ZORDER;
439 if ( (fl & SWP_SHOW) && (swpOld.fl & SWP_SHOW) )
440 fl &= ~SWP_SHOW;
441 if ( (fl & SWP_HIDE) && (swpOld.fl & SWP_HIDE) )
442 fl &= ~SWP_HIDE;
443 if ( (fl & (SWP_SHOW | SWP_HIDE)) == (SWP_SHOW | SWP_HIDE) )
444 fl &= ~SWP_HIDE;
445
446 BOOL rc = WinSetWindowPos( hwnd, hwndInsertBehind, x, y, cx, cy,
447 fl | SWP_NOREDRAW );
448 if ( rc == FALSE || (fl & SWP_NOREDRAW) )
449 return rc;
450
451 SWP swpNew;
452 WinQueryWindowPos( hwnd, &swpNew );
453
454 if ( swpOld.hwndInsertBehind == swpNew.hwndInsertBehind )
455 fl &= ~SWP_ZORDER;
456
457 if ( (fl & (SWP_ZORDER | SWP_SHOW | SWP_HIDE)) == 0 )
458 return rc;
459
460 HPS hps = qt_display_ps();
461 HWND hwndParent = WinQueryWindow( hwnd, QW_PARENT );
462
463 // get window bounds
464 HRGN hrgnSelf = GpiCreateRegion( hps, 0, NULL );
465 qt_WinQueryClipRegionOrRect( hwnd, hrgnSelf );
466
467 if ( fl & SWP_SHOW ) {
468 WinInvalidateRegion( hwnd, hrgnSelf, TRUE );
469 } else if ( fl & SWP_HIDE ) {
470 // translate the region to the parent coordinate system
471 POINTL ptl = { swpNew.x, swpNew.y };
472 GpiOffsetRegion( hps, hrgnSelf, &ptl );
473 // invalidate the parent and children below this window
474 qt_WinInvalidateRegionEx( hwndParent, hrgnSelf,
475 WinQueryWindow( hwnd, QW_NEXT ), HWND_BOTTOM );
476 } else { // fl & SWP_ZORDER
477 // below we assume that WinSetWindowPos() returns FALSE if
478 // an incorrect (unrelated) hwndInsertBehind is passed when SWP_ZORDER
479 // is set
480
481 // first, detect whether we are moving up or down
482 BOOL up;
483 HWND hwndFrom, hwndTo;
484 if ( swpOld.hwndInsertBehind == HWND_TOP ) {
485 up = FALSE;
486 hwndFrom = WinQueryWindow( hwndParent, QW_TOP );
487 hwndTo = swpNew.hwndInsertBehind;
488 } else {
489 up = TRUE;
490 for ( HWND hwndAbove = hwnd;
491 (hwndAbove = WinQueryWindow( hwndAbove, QW_PREV )) != 0; ) {
492 if ( hwndAbove == swpOld.hwndInsertBehind ) {
493 up = FALSE;
494 break;
495 }
496 }
497 if ( up ) {
498 hwndFrom = swpOld.hwndInsertBehind;
499 hwndTo = WinQueryWindow( hwnd, QW_NEXT );
500 } else {
501 hwndFrom = WinQueryWindow( swpOld.hwndInsertBehind, QW_NEXT );
502 hwndTo = swpNew.hwndInsertBehind;
503 }
504 }
505#if defined (DEBUG_WIDGETMASK)
506 qDebug( " moving up? %ld", up );
507 w = QWidget::find( hwndFrom );
508 qDebug( " hwndFrom=%08lX (%s/%s)", hwndFrom,
509 w ? w->name() : 0, w ? w->className() : 0 );
510 w = QWidget::find( hwndTo );
511 qDebug( " hwndTo=%08lX (%s/%s)", hwndTo,
512 w ? w->name() : 0, w ? w->className() : 0 );
513#endif
514
515 SWP swp;
516 HWND sibling = hwndFrom;
517 HRGN hrgn = GpiCreateRegion( hps, 0, NULL );
518 HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
519
520 if ( up ) {
521 // go upwards in z-order
522 while ( 1 ) {
523 WinQueryWindowPos( sibling, &swp );
524#if defined (DEBUG_WIDGETMASK)
525 w = QWidget::find( sibling );
526 qDebug( " sibling=%08lX [fl=%08lX] (%s/%s)", sibling, swp.fl,
527 w ? w->name() : 0, w ? w->className() : 0 );
528#endif
529 // proceed only if not hidden
530 if ( swp.fl & SWP_SHOW ) {
531 // get sibling's bounds (clip region or rect)
532 qt_WinQueryClipRegionOrRect( sibling, hrgn );
533 // translate the region to this window's coordinate system
534 POINTL ptl = { swp.x - swpNew.x, swp.y - swpNew.y };
535 GpiOffsetRegion( hps, hrgn, &ptl );
536 // add to the region of siblings we're moving on top of
537 GpiCombineRegion( hps, hrgnUpd, hrgnUpd, hrgn, CRGN_OR );
538#if defined (DEBUG_WIDGETMASK)
539 qDebug( " processed" );
540#endif
541 }
542 // iterate to the prev window (above)
543 if ( sibling == hwndTo )
544 break;
545 sibling = swp.hwndInsertBehind;
546 }
547 // intersect the resulting region with the widget region and
548 // invalidate
549 GpiCombineRegion( hps, hrgnUpd, hrgnSelf, hrgnUpd, CRGN_AND );
550 WinInvalidateRegion( hwnd, hrgnUpd, TRUE );
551 } else {
552 // go downwards in reverse z-order
553 POINTL ptl = { 0, 0 };
554 while ( 1 ) {
555 WinQueryWindowPos( sibling, &swp );
556#if defined (DEBUG_WIDGETMASK)
557 w = QWidget::find( sibling );
558 qDebug( " sibling=%08lX [fl=%08lX] (%s/%s)", sibling, swp.fl,
559 w ? w->name() : 0, w ? w->className() : 0 );
560#endif
561 // proceed only if not hidden
562 if ( swp.fl & SWP_SHOW ) {
563 // get sibling's bounds (clip region or rect)
564 qt_WinQueryClipRegionOrRect( sibling, hrgn );
565 // undo the previous translation and translate this window's
566 // region to the siblings's coordinate system
567 ptl.x += swpNew.x - swp.x;
568 ptl.y += swpNew.y - swp.y;
569 GpiOffsetRegion( hps, hrgnSelf, &ptl );
570 // intersect the sibling's region with the translated one
571 // and invalidate the sibling
572 GpiCombineRegion( hps, hrgnUpd, hrgnSelf, hrgn, CRGN_AND );
573 WinInvalidateRegion( sibling, hrgnUpd, TRUE );
574 // substract the invalidated area from the widget's region
575 // (no need to invalidate it any more)
576 GpiCombineRegion( hps, hrgnSelf, hrgnSelf, hrgnUpd, CRGN_DIFF );
577 // prepare the translation from the sibling's
578 // coordinates back to this window's coordinates
579 ptl.x = swp.x - swpNew.x;
580 ptl.y = swp.y - swpNew.y;
581#if defined (DEBUG_WIDGETMASK)
582 qDebug( " processed" );
583#endif
584 }
585 // iterate to the next window (below)
586 if ( sibling == hwndTo )
587 break;
588 sibling = WinQueryWindow( sibling, QW_NEXT );
589 }
590 }
591
592 GpiDestroyRegion( hps, hrgnUpd );
593 GpiDestroyRegion( hps, hrgn );
594 }
595
596 GpiDestroyRegion( hps, hrgnSelf );
597
598 return TRUE;
599}
600
601#endif
602
603/*!
604 * \internal
605 * For some unknown reason, PM sends WM_SAVEAPPLICATION to every window
606 * being destroyed, which makes it indistinguishable from WM_SAVEAPPLICATION
607 * sent to top level windows during system shutdown. We use our own version of
608 * WinDestroyWindow() and a special flag (qt_about_to_destroy_wnd) to
609 * distinguish it in qapplication_pm.cpp.
610 */
611static BOOL qt_WinDestroyWindow( HWND hwnd )
612{
613#if !defined (QT_NO_SESSIONMANAGER)
614 qt_about_to_destroy_wnd = TRUE;
615#endif
616 BOOL rc = WinDestroyWindow( hwnd );
617#if !defined (QT_NO_SESSIONMANAGER)
618 qt_about_to_destroy_wnd = FALSE;
619#endif
620 return rc;
621}
622
623static void removeSysMenuAccels( HWND frame )
624{
625 HWND sysMenu = WinWindowFromID( frame, FID_SYSMENU );
626 if ( !sysMenu )
627 return;
628
629 SHORT subId = SHORT1FROMMR( WinSendMsg( sysMenu, MM_ITEMIDFROMPOSITION, 0, 0 ) );
630 if ( subId != MIT_ERROR ) {
631 MENUITEM item;
632 WinSendMsg( sysMenu, MM_QUERYITEM, MPFROM2SHORT(subId, FALSE), MPFROMP(&item) );
633 HWND subMenu = item.hwndSubMenu;
634 if ( subMenu ) {
635 USHORT cnt = SHORT1FROMMR( WinSendMsg( subMenu, MM_QUERYITEMCOUNT, 0, 0 ) );
636 for ( int i = 0; i < cnt; i++ ) {
637 USHORT id = SHORT1FROMMR(
638 WinSendMsg( subMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(i), 0 ) );
639 if ( id == SC_TASKMANAGER || id == SC_CLOSE ) {
640 // accels for these entries always work in Qt, skip them
641 continue;
642 }
643 USHORT len = SHORT1FROMMR(
644 WinSendMsg( subMenu, MM_QUERYITEMTEXTLENGTH, MPFROMSHORT(id), 0 ) );
645 if ( len++ ) {
646 char *text = new char[len];
647 WinSendMsg( subMenu, MM_QUERYITEMTEXT,
648 MPFROM2SHORT(id, len), MPFROMP(text) );
649 char *tab = strrchr( text, '\t' );
650 if ( tab ) {
651 *tab = 0;
652 WinSendMsg( subMenu, MM_SETITEMTEXT,
653 MPFROMSHORT(id), MPFROMP(text) );
654 }
655 delete[] text;
656 }
657 }
658 // sublclass the system menu to leave the menu mode completely
659 // when the user presses the ESC key. by default, pressing ESC
660 // while the pull-down menu is showing brings us to the menu bar,
661 // which is confusing in the case of the system menu, because
662 // there is only one item on the menu bar, and we cannot see
663 // that it is active when the frame window has an icon.
664 PFNWP oldProc = WinSubclassWindow( sysMenu, QtSysMenuProc );
665 // set QtOldSysMenuProc only once: it must be the same for
666 // all FID_SYSMENU windows.
667 if ( !QtOldSysMenuProc )
668 QtOldSysMenuProc = oldProc;
669 }
670 }
671}
672
673/*****************************************************************************
674 QWidget member functions
675 *****************************************************************************/
676
677//#define QT_DEBUGWINCREATEDESTROY
678
679void QWidget::create( WId window, bool initializeWindow, bool destroyOldWindow )
680{
681 // When window is not zero, it represents an existing (external) window
682 // handle we should create a QWidget "wrapper" for to incorporate it to the
683 // Qt widget hierarchy. But so far I have never seen this method called
684 // with window != 0, so we ignore this argument (as well as the other two
685 // that make sense only together with it) for now and will not implement
686 // this functionality until there's a real need.
687
688 Q_ASSERT( window == 0 );
689 Q_UNUSED( initializeWindow );
690 Q_UNUSED( destroyOldWindow );
691
692 if ( testWState(WState_Created) && window == 0 )
693 return;
694 setWState( WState_Created ); // set created flag
695
696 if ( !parentWidget() || parentWidget()->isDesktop() )
697 setWFlags( WType_TopLevel ); // top-level widget
698
699 static int sw = -1, sh = -1;
700
701 bool topLevel = testWFlags(WType_TopLevel);
702 bool popup = testWFlags(WType_Popup);
703 bool dialog = testWFlags(WType_Dialog);
704 bool desktop = testWFlags(WType_Desktop);
705 WId id = 0;
706
707 if ( popup ) {
708 /// @todo (dmik) WStyle_StaysOnTop is ignored for now (does nothing)
709 setWFlags(WStyle_StaysOnTop); // a popup stays on top
710 }
711
712 if ( sw < 0 ) { // get the screen size
713 sw = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
714 sh = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
715 }
716
717 if ( dialog || popup || desktop ) { // these are top-level, too
718 topLevel = TRUE;
719 setWFlags( WType_TopLevel );
720 }
721
722 if ( desktop ) { // desktop widget
723 popup = FALSE; // force this flags off
724 /// @todo (dmik)
725 // use WinGetMaxPosition () to take into account such things as XCenter?
726 crect.setRect( 0, 0, sw, sh );
727 }
728
729 PCSZ title = NULL;
730 ULONG style = 0;
731 ULONG fId = 0, fStyle = 0, fcFlags = 0;
732
733 if ( popup ) {
734 style |= WS_SAVEBITS;
735 } else if ( !topLevel ) {
736 if ( !testWFlags(WStyle_Customize) )
737 setWFlags( WStyle_NormalBorder | WStyle_Title | WStyle_MinMax | WStyle_SysMenu );
738 } else if (!desktop ) {
739 if ( !testWFlags(WStyle_Customize) ) {
740 if ( testWFlags(WStyle_Tool) ) {
741 // a special case for WStyle_Tool w/o WStyle_Customize.
742 // it violates the Qt docs but it is used by QPopupMenu
743 // to create torn-off menus.
744 setWFlags( WStyle_Title );
745 } else {
746 if ( dialog )
747 setWFlags( WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu );
748 else
749 setWFlags( WStyle_NormalBorder | WStyle_Title | WStyle_MinMax | WStyle_SysMenu );
750 }
751 }
752 }
753 if ( !desktop ) {
754#if !defined (QT_PM_NO_WIDGETMASK)
755 // We don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN, because when these
756 // styles are set and a child/sibling window has a non-NULL clip region,
757 // PM still continues to exclude the entire child's rectangle from the
758 // parent window's update region, ignoring its clip region. As a result,
759 // areas outside the clip region are left unpainted. Instead, we correct
760 // the update region of the window ourselves, on every WM_PAINT event.
761#else
762 /// @todo (dmik)
763 // this is temporarily commented out because QSplitter sets
764 // WPaintUnclipped which causes terrible flicker in QFileDialog's list
765 // box and list view. This needs to be investigated. Qt/Win32 does also
766 // comment this out...
767 /* if ( !testWFlags( WPaintUnclipped ) ) */
768 style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
769#endif
770 // for all top-level windows except popups we create a WC_FRAME
771 // as a parent and owner.
772 if ( topLevel && !popup ) {
773 if ( !testWFlags(WStyle_NoBorder) ) {
774 if ( testWFlags(WStyle_NormalBorder) ) {
775 fcFlags |= FCF_SIZEBORDER;
776 } else if ( testWFlags(WStyle_DialogBorder) ) {
777 fcFlags |= FCF_DLGBORDER;
778 } else if ( testWFlags(WStyle_Tool) ) {
779 fcFlags |= FCF_BORDER;
780 }
781 }
782 if ( testWFlags(WStyle_Title) )
783 fcFlags |= FCF_TITLEBAR;
784 if ( testWFlags(WStyle_SysMenu) )
785 fcFlags |= FCF_SYSMENU | FCF_CLOSEBUTTON;
786 if ( testWFlags(WStyle_Minimize) )
787 fcFlags |= FCF_MINBUTTON;
788 if ( testWFlags(WStyle_Maximize) )
789 fcFlags |= FCF_MAXBUTTON;
790 fStyle |= FS_NOMOVEWITHOWNER | FS_NOBYTEALIGN;
791 fStyle |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
792 }
793 }
794 if ( testWFlags(WStyle_Title) ) {
795 title = topLevel ? qAppName() : name();
796 }
797
798 // The WState_Created flag is checked by translateConfigEvent() in
799 // qapplication_pm.cpp. We switch it off temporarily to avoid move
800 // and resize events during creation
801 clearWState( WState_Created );
802
803 QString className = qt_reg_winclass( getWFlags() );
804 PCSZ pszClassName = className.latin1();
805
806 if ( desktop ) { // desktop widget
807 id = WinQueryDesktopWindow( 0, 0 );
808 QWidget *otherDesktop = find( id ); // is there another desktop?
809 if ( otherDesktop && otherDesktop->testWFlags(WPaintDesktop) ) {
810 otherDesktop->setWinId( 0 ); // remove id from widget mapper
811 setWinId( id ); // make sure otherDesktop is
812 otherDesktop->setWinId( id ); // found first
813 } else {
814 setWinId( id );
815 }
816 } else if ( topLevel ) {
817 // create top-level widget
818 HWND ownerw = 0;
819 if ( !popup ) {
820 QWidget *p = parentWidget();
821 if ( p && !p->isDesktop() )
822 ownerw = p->topLevelWidget()->winFId();
823 }
824
825 if ( !popup ) {
826 // create WC_FRAME
827 FRAMECDATA fcData;
828 fcData.cb = sizeof(FRAMECDATA);
829 fcData.flCreateFlags = fcFlags;
830 fcData.hmodResources = NULL;
831 fcData.idResources = 0;
832#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
833 qDebug ( "|Creating top level window [%s/%s] (frame):\n"
834 "| owner = %08lX\n"
835 "| title = '%s'\n"
836 "| style = %08lX\n"
837 "| fcFlags = %08lX",
838 name(), this->className(), ownerw, title, fStyle, fcFlags );
839#endif
840 fId = WinCreateWindow(
841 HWND_DESKTOP, WC_FRAME, title, fStyle, 0, 0, 0, 0,
842 ownerw, HWND_TOP, 0, &fcData, NULL
843 );
844#ifndef QT_NO_DEBUG
845#ifdef QT_DEBUGWINCREATEDESTROY
846 qDebug( "| hwnd = %08lX", fId );
847#endif
848 if ( fId == 0 )
849 qSystemWarning( "QWidget: Failed to create frame window" );
850#endif
851 PFNWP oldProc = WinSubclassWindow( fId, QtFrameProc );
852 // set QtOldFrameProc only once: it must be the same for
853 // all WC_FRAME windows.
854 if ( !QtOldFrameProc )
855 QtOldFrameProc = oldProc;
856
857 removeSysMenuAccels( fId );
858
859 // create client
860#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
861 qDebug( "|Creating top level window [%s/%s] (client):\n"
862 "| owner & parent = %08lX\n"
863 "| class = '%s'\n"
864 "| title = '%s'\n"
865 "| style = %08lX",
866 name(), this->className(), fId, pszClassName, title, style );
867#endif
868 // note that we place the client on top (HWND_TOP) to exclude other
869 // frame controls from being analyzed in qt_WinProcessWindowObstacles
870 id = WinCreateWindow(
871 fId, pszClassName, title, style, 0, 0, 0, 0,
872 fId, HWND_TOP, FID_CLIENT, NULL, NULL
873 );
874 } else {
875#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
876 qDebug( "|Creating top level window [%s/%s]:\n"
877 "| owner = %08lX\n"
878 "| class = '%s'\n"
879 "| title = '%s'\n"
880 "| style = %08lX",
881 name(), this->className(), ownerw, pszClassName, title, style );
882#endif
883 id = WinCreateWindow(
884 HWND_DESKTOP, pszClassName, title, style, 0, 0, 0, 0,
885 ownerw, HWND_TOP, 0, NULL, NULL
886 );
887 }
888#ifndef QT_NO_DEBUG
889#ifdef QT_DEBUGWINCREATEDESTROY
890 qDebug( "| hwnd = %08lX", id );
891#endif
892 if ( id == 0 )
893 qSystemWarning( "QWidget: Failed to create window" );
894#endif
895 setWinId( id );
896 /// @todo (dmik) WStyle_StaysOnTop is ignored for now (does nothing)
897/*
898 if ( testWFlags( WStyle_StaysOnTop) )
899 SetWindowPos( id, HWND_TOPMOST, 0, 0, 100, 100, SWP_NOACTIVATE );
900*/
901
902 // When the FS_SHELLPOSITION flag is specified during WC_FRAME window
903 // creation its size and position remains zero until it is shown
904 // for the first time. So, we don't use FS_SHELLPOSITION but emulate
905 // its functionality here.
906 SWP swp;
907 WinQueryTaskSizePos( 0, 0, &swp );
908 WinSetWindowPos( fId, 0, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE );
909 } else {
910 // create child widget
911 HWND parentw = parentWidget()->winId();
912#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
913 qDebug( "|Creating child window [%s/%s]:\n"
914 "| owner & parent = %08lX\n"
915 "| class = '%s'\n"
916 "| title = '%s'\n"
917 "| style = %08lX",
918 name(), this->className(), parentw, pszClassName, title, style );
919#endif
920 id = WinCreateWindow(
921 parentw, pszClassName, title, style,
922 0, parentWidget()->crect.height() - 30, 100, 30,
923 parentw, HWND_TOP, 0, NULL, NULL
924 );
925#ifndef QT_NO_DEBUG
926#ifdef QT_DEBUGWINCREATEDESTROY
927 qDebug( "| hwnd = %08lX", id );
928#endif
929 if ( id == 0 )
930 qSystemWarning( "QWidget: Failed to create window" );
931#endif
932 setWinId( id );
933 }
934
935 if ( desktop ) {
936 setWState( WState_Visible );
937 } else {
938 SWP cswp;
939 WinQueryWindowPos( id, &cswp );
940 if ( topLevel ) {
941 QTLWExtra *top = topData();
942 if ( fId ) {
943 SWP fswp;
944 WinQueryWindowPos( fId, &fswp );
945 // flip y coordinates
946 fswp.y = sh - (fswp.y + fswp.cy);
947 cswp.y = fswp.cy - (cswp.y + cswp.cy);
948 crect.setRect(
949 fswp.x + cswp.x, fswp.y + cswp.y,
950 cswp.cx, cswp.cy
951 );
952
953 top->fleft = cswp.x;
954 top->ftop = cswp.y;
955 top->fright = fswp.cx - cswp.x - cswp.cx;
956 top->fbottom = fswp.cy - cswp.y - cswp.cy;
957 top->fId = fId;
958 } else {
959 // flip y coordinate
960 cswp.y = sh - (cswp.y + cswp.cy);
961 crect.setRect( cswp.x, cswp.y, cswp.cx, cswp.cy );
962 }
963 fstrut_dirty = FALSE;
964 } else {
965 int cy = parentWidget()->crect.height();
966 // flip y coordinate
967 cswp.y = cy - (cswp.y + cswp.cy);
968 crect.setRect( cswp.x, cswp.y, cswp.cx, cswp.cy );
969 }
970 }
971
972 setWState( WState_Created ); // accept move/resize events
973 hps = 0; // no presentation space
974
975 setFontSys();
976
977/// @todo (dmik) remove?
978// QInputContext::enable( this, im_enabled & !((bool)testWState(WState_Disabled)) );
979}
980
981
982void QWidget::destroy( bool destroyWindow, bool destroySubWindows )
983{
984 deactivateWidgetCleanup();
985 if ( testWState(WState_Created) ) {
986 clearWState( WState_Created );
987 if ( children() ) {
988 QObjectListIt it(*children());
989 register QObject *obj;
990 while ( (obj=it.current()) ) { // destroy all widget children
991 ++it;
992 if ( obj->isWidgetType() )
993 ((QWidget*)obj)->destroy(destroySubWindows,
994 destroySubWindows);
995 }
996 }
997 if ( mouseGrb == this )
998 releaseMouse();
999 if ( keyboardGrb == this )
1000 releaseKeyboard();
1001 if ( testWFlags(WShowModal) ) // just be sure we leave modal
1002 qt_leave_modal( this );
1003 else if ( testWFlags(WType_Popup) )
1004 qApp->closePopup( this );
1005 if ( destroyWindow && !testWFlags(WType_Desktop) ) {
1006 HWND id = winId();
1007 if ( isTopLevel() && !testWFlags(WType_Popup) ) {
1008 // extra data including extra->topextra has been already
1009 // deleted at this point by deleteExtra() and therefore
1010 // calling winFId() useless -- it will always return the
1011 // client window handle. Use WinQueryWindow() instead.
1012 id = WinQueryWindow( id, QW_PARENT );
1013 }
1014#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
1015 qDebug( "|Destroying window [%s/%s]:\n"
1016 "| hwnd = %08lX",
1017 name(), className(), id );
1018#endif
1019 qt_WinDestroyWindow( id );
1020 }
1021 setWinId( 0 );
1022 }
1023}
1024
1025void QWidget::reparentSys( QWidget *parent, WFlags f, const QPoint &p,
1026 bool showIt )
1027{
1028 QWidget* oldtlw = topLevelWidget();
1029 WId old_winfid = winFId();
1030
1031 // hide and reparent our own window away. Otherwise we might get
1032 // destroyed when emitting the child remove event below. See QWorkspace.
1033 // this is also necessary for modal windows to leave the modal state
1034 // correctly.
1035 if ( isVisible() ) {
1036 hide();
1037 WinSetParent( old_winfid, HWND_OBJECT, FALSE );
1038 WinSetOwner( old_winfid, 0 );
1039 }
1040
1041 // unblock the widget if blocked
1042 QWidget *blockedBy = 0;
1043 if ( isTopLevel() )
1044 blockedBy = (QWidget*) WinQueryWindowULong( winId(), QWL_QTMODAL );
1045 if ( !blockedBy && parentWidget() )
1046 blockedBy = (QWidget*) WinQueryWindowULong(
1047 parentWidget()->topLevelWidget()->winId(), QWL_QTMODAL );
1048 if ( blockedBy ) {
1049 QEvent e( QEvent::WindowUnblocked );
1050 qt_sendBlocked( this, blockedBy, &e, FALSE );
1051 }
1052
1053 bool accept_drops = acceptDrops();
1054 if ( accept_drops )
1055 setAcceptDrops( FALSE ); // ole dnd unregister (we will register again below)
1056 if ( testWFlags(WType_Desktop) )
1057 old_winfid = 0;
1058 setWinId( 0 );
1059 if ( isTopLevel() ) {
1060 QTLWExtra *top = topData();
1061 if ( top->swEntry ) {
1062 WinRemoveSwitchEntry( top->swEntry );
1063 top->swEntry = 0;
1064 }
1065 top->fId = 0;
1066 }
1067
1068 if ( parent != parentObj ) {
1069 if ( parentObj ) // remove from parent
1070 parentObj->removeChild( this );
1071 if ( parent ) // insert into new parent
1072 parent->insertChild( this );
1073 }
1074
1075 bool enable = isEnabled(); // remember status
1076 FocusPolicy fp = focusPolicy();
1077 QSize s = size();
1078 QString capt = caption();
1079 widget_flags = f;
1080 clearWState( WState_Created | WState_Visible | WState_ForceHide );
1081 create();
1082 if ( isTopLevel() || (!parent || parent->isVisible() ) )
1083 setWState( WState_ForceHide ); // new widgets do not show up in already visible parents
1084 const QObjectList *chlist = children();
1085 if ( chlist ) { // reparent children
1086 SWP swp;
1087 QObjectListIt it( *chlist );
1088 QObject *obj;
1089 while ( (obj=it.current()) ) {
1090 if ( obj->isWidgetType() ) {
1091 QWidget *w = (QWidget *)obj;
1092 if ( w->isPopup() )
1093 ;
1094 else if ( w->isTopLevel() ) {
1095 w->reparent( this, w->getWFlags(), w->pos(), !w->isHidden() );
1096 } else {
1097 WinSetParent( w->winId(), winId(), FALSE );
1098 WinSetOwner( w->winId(), winId() );
1099 // bring PM coords into accordance with Qt coords,
1100 // otherwise setGeometry() below will wrongly position
1101 // children if this widget manages their layout.
1102 int hd = height() - s.height();
1103 WinQueryWindowPos( w->winId(), &swp );
1104 swp.y += hd;
1105 WinSetWindowPos( w->winId(), 0, swp.x, swp.y, 0, 0, SWP_MOVE );
1106 }
1107 }
1108 ++it;
1109 }
1110 }
1111
1112 // block the widget if it should be blocked
1113 blockedBy = 0;
1114 if ( parentWidget() )
1115 blockedBy = (QWidget*) WinQueryWindowULong(
1116 parentWidget()->topLevelWidget()->winId(), QWL_QTMODAL );
1117 if ( blockedBy ) {
1118 if ( isTopLevel() && testWFlags( WGroupLeader ) )
1119 blockedBy = 0;
1120 } else {
1121 QWidget *topModal = qApp->activeModalWidget();
1122 if (
1123 topModal && this != topModal && parentWidget() != topModal &&
1124 isTopLevel() && !testWFlags( WGroupLeader )
1125 )
1126 blockedBy = topModal;
1127 }
1128 if ( blockedBy ) {
1129 QEvent e( QEvent::WindowBlocked );
1130 qt_sendBlocked( this, blockedBy, &e, FALSE );
1131 }
1132
1133 setGeometry( p.x(), p.y(), s.width(), s.height() );
1134 setEnabled( enable );
1135 setFocusPolicy( fp );
1136 if ( !capt.isNull() ) {
1137 extra->topextra->caption = QString::null;
1138 setCaption( capt );
1139 }
1140 if ( showIt )
1141 show();
1142 if ( old_winfid )
1143 qt_WinDestroyWindow( old_winfid );
1144
1145 reparentFocusWidgets( oldtlw ); // fix focus chains
1146
1147 if ( accept_drops )
1148 setAcceptDrops( TRUE );
1149
1150//@@TODO (dmik): remove?
1151//#ifdef Q_OS_TEMP
1152// // Show borderless toplevel windows in tasklist & NavBar
1153// if ( !parent ) {
1154// QString txt = caption().isEmpty()?qAppName():caption();
1155// SetWindowText( winId(), (TCHAR*)txt.ucs2() );
1156// }
1157//#endif
1158}
1159
1160QPoint QWidget::mapToGlobal( const QPoint &pos ) const
1161{
1162 if ( !isVisible() || isMinimized() )
1163 return mapTo( topLevelWidget(), pos ) + topLevelWidget()->pos() +
1164 (topLevelWidget()->geometry().topLeft() - topLevelWidget()->frameGeometry().topLeft());
1165 POINTL ptl;
1166 ptl.x = pos.x();
1167 // flip y (local) coordinate
1168 ptl.y = height() - (pos.y() + 1);
1169 WinMapWindowPoints( winId(), HWND_DESKTOP, &ptl, 1 );
1170 // flip y (global) coordinate
1171 ptl.y = QApplication::desktop()->height() - (ptl.y + 1);
1172 return QPoint( ptl.x, ptl.y );
1173}
1174
1175QPoint QWidget::mapFromGlobal( const QPoint &pos ) const
1176{
1177 if ( !isVisible() || isMinimized() )
1178 return mapFrom( topLevelWidget(), pos - topLevelWidget()->pos() );
1179 POINTL ptl;
1180 ptl.x = pos.x();
1181 // flip y (global) coordinate
1182 ptl.y = QApplication::desktop()->height() - (pos.y() + 1);
1183 WinMapWindowPoints( HWND_DESKTOP, winId(), &ptl, 1 );
1184 // flip y (local) coordinate
1185 ptl.y = height() - (ptl.y + 1);
1186 return QPoint( ptl.x, ptl.y );
1187}
1188
1189void QWidget::setFontSys( QFont *f )
1190{
1191//@@TODO (dmik): should this do something on OS/2?
1192//@@TODO (dmik): remove?
1193// QInputContext::setFont( this, (f ? *f : font()) );
1194}
1195
1196void QWidget::setMicroFocusHint(int x, int y, int width, int height, bool text, QFont *f)
1197{
1198//@@TODO (dmik): do we need to create a caret (cursor) in OS/2 also?
1199// currently, try to do so (which can be useful for 3rd-party apps
1200// that are interested in the current cursor position, i.e. where the user
1201// input is now taking place.
1202 // flip y coordinate
1203 int fy = crect.height() - (y + height);
1204 WinCreateCursor( winId(), x, fy, width, height, CURSOR_SOLID, NULL );
1205
1206//@@TODO (dmik): remove?
1207// if ( text )
1208// QInputContext::setFocusHint( x, y, width, height, this );
1209 setFontSys( f );
1210
1211 if ( QRect( x, y, width, height ) != microFocusHint() )
1212 extraData()->micro_focus_hint.setRect( x, y, width, height );
1213}
1214
1215void QWidget::resetInputContext()
1216{
1217//@@TODO (dmik): remove?
1218// QInputContext::accept();
1219}
1220
1221void QWidget::setBackgroundColorDirect( const QColor &color )
1222{
1223 bg_col = color;
1224 if ( extra && extra->bg_pix ) { // kill the background pixmap
1225 delete extra->bg_pix;
1226 extra->bg_pix = 0;
1227 }
1228}
1229
1230
1231static int allow_null_pixmaps = 0;
1232
1233
1234void QWidget::setBackgroundPixmapDirect( const QPixmap &pixmap )
1235{
1236 QPixmap old;
1237 if ( extra && extra->bg_pix )
1238 old = *extra->bg_pix;
1239 if ( !allow_null_pixmaps && pixmap.isNull() ) {
1240 if ( extra && extra->bg_pix ) {
1241 delete extra->bg_pix;
1242 extra->bg_pix = 0;
1243 }
1244 } else {
1245 if ( extra && extra->bg_pix )
1246 delete extra->bg_pix;
1247 else
1248 createExtra();
1249 extra->bg_pix = new QPixmap( pixmap );
1250 }
1251}
1252
1253
1254void QWidget::setBackgroundEmpty()
1255{
1256 allow_null_pixmaps++;
1257 setErasePixmap(QPixmap());
1258 allow_null_pixmaps--;
1259}
1260
1261extern void qt_set_cursor( QWidget *, const QCursor & ); // qapplication_pm.cpp
1262
1263void QWidget::setCursor( const QCursor &cursor )
1264{
1265 if ( cursor.handle() != arrowCursor.handle()
1266 || (extra && extra->curs) ) {
1267 createExtra();
1268 delete extra->curs;
1269 extra->curs = new QCursor(cursor);
1270 }
1271 setWState( WState_OwnCursor );
1272 qt_set_cursor( this, QWidget::cursor() );
1273}
1274
1275void QWidget::unsetCursor()
1276{
1277 if ( extra ) {
1278 delete extra->curs;
1279 extra->curs = 0;
1280 }
1281 if ( !isTopLevel() )
1282 clearWState( WState_OwnCursor );
1283 qt_set_cursor( this, cursor() );
1284}
1285
1286void QWidget::setCaption( const QString &caption )
1287{
1288 if ( QWidget::caption() == caption )
1289 return; // for less flicker
1290 topData()->caption = caption;
1291
1292 QCString cap = caption.local8Bit();
1293 WinSetWindowText( winFId(), cap );
1294
1295 HSWITCH swEntry = topData()->swEntry;
1296 if ( swEntry ) {
1297 SWCNTRL swc;
1298 WinQuerySwitchEntry( swEntry, &swc );
1299 strncpy( swc.szSwtitle, cap, sizeof(swc.szSwtitle)-1 );
1300 swc.szSwtitle [sizeof(swc.szSwtitle)-1] = 0;
1301 WinChangeSwitchEntry( swEntry, &swc );
1302 }
1303
1304 QEvent e( QEvent::CaptionChange );
1305 QApplication::sendEvent( this, &e );
1306}
1307
1308void QWidget::setIcon( const QPixmap &pixmap )
1309{
1310 QTLWExtra* x = topData();
1311 delete x->icon;
1312 x->icon = 0;
1313 HPOINTER oldIcon = x->pmIcon;
1314 x->pmIcon = 0;
1315
1316 if ( !pixmap.isNull() ) { // valid icon
1317 x->icon = new QPixmap( pixmap );
1318
1319 if ( isTopLevel() ) {
1320 const QPixmap *normal = 0;
1321 const QPixmap *mini = 0;
1322
1323 // QPixmap::createIcon() is not yet capable to create both normal
1324 // and mini icons (due to a bug in WinCreateIconIndirect), so
1325 // if the specified pixmap is equal or larger than the normal icon
1326 // size, then we create a normal icon, otherwise a mini one.
1327
1328 int iconw = WinQuerySysValue( HWND_DESKTOP, SV_CXICON );
1329 int iconh = WinQuerySysValue( HWND_DESKTOP, SV_CYICON );
1330 if ( pixmap.width() >= iconw && pixmap.height() >= iconh ) {
1331 normal = &pixmap;
1332 } else {
1333 mini = &pixmap;
1334 }
1335
1336 x->pmIcon = QPixmap::createIcon( false, 0, 0, normal, mini );
1337 }
1338 }
1339
1340 if ( isTopLevel() )
1341 WinSendMsg( x->fId, WM_SETICON, MPFROMLONG( x->pmIcon ), 0 );
1342
1343 if ( oldIcon )
1344 WinDestroyPointer( oldIcon );
1345
1346 QEvent e( QEvent::IconChange );
1347 QApplication::sendEvent( this, &e );
1348}
1349
1350
1351void QWidget::setIconText( const QString &iconText )
1352{
1353 topData()->iconText = iconText;
1354}
1355
1356QCursor *qt_grab_cursor()
1357{
1358 return mouseGrbCur;
1359}
1360
1361void QWidget::grabMouse()
1362{
1363 if ( !qt_nograb() ) {
1364 if ( mouseGrb )
1365 mouseGrb->releaseMouse();
1366 WinSetCapture( HWND_DESKTOP, winFId() );
1367 mouseGrb = this;
1368 }
1369}
1370
1371void QWidget::grabMouse( const QCursor &cursor )
1372{
1373 if ( !qt_nograb() ) {
1374 if ( mouseGrb )
1375 mouseGrb->releaseMouse();
1376 WinSetCapture( HWND_DESKTOP, winFId() );
1377 mouseGrbCur = new QCursor( cursor );
1378 WinSetPointer( HWND_DESKTOP, mouseGrbCur->handle() );
1379 mouseGrb = this;
1380 }
1381}
1382
1383void QWidget::releaseMouse()
1384{
1385 if ( !qt_nograb() && mouseGrb == this ) {
1386 WinSetCapture( HWND_DESKTOP, 0 );
1387 if ( mouseGrbCur ) {
1388 delete mouseGrbCur;
1389 mouseGrbCur = 0;
1390 }
1391 mouseGrb = 0;
1392 }
1393}
1394
1395void QWidget::grabKeyboard()
1396{
1397 if ( !qt_nograb() ) {
1398 if ( keyboardGrb )
1399 keyboardGrb->releaseKeyboard();
1400 keyboardGrb = this;
1401 }
1402}
1403
1404void QWidget::releaseKeyboard()
1405{
1406 if ( !qt_nograb() && keyboardGrb == this )
1407 keyboardGrb = 0;
1408}
1409
1410
1411QWidget *QWidget::mouseGrabber()
1412{
1413 return mouseGrb;
1414}
1415
1416QWidget *QWidget::keyboardGrabber()
1417{
1418 return keyboardGrb;
1419}
1420
1421void QWidget::setActiveWindow()
1422{
1423 WinSetActiveWindow( HWND_DESKTOP, topLevelWidget()->winFId() );
1424}
1425
1426void QWidget::update()
1427{
1428 update( 0, 0, -1, -1 );
1429}
1430
1431void QWidget::update( int x, int y, int w, int h )
1432{
1433 if ( w && h &&
1434 (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
1435 if ( w < 0 )
1436 w = crect.width() - x;
1437 if ( h < 0 )
1438 h = crect.height() - y;
1439
1440 // flip y coordinate
1441 y = crect.height() - (y + h);
1442 RECTL rcl = { x, y, x + w, y + h };
1443
1444#if !defined (QT_PM_NO_WIDGETMASK)
1445 WinInvalidateRect( winId(), &rcl, FALSE );
1446#else
1447 // WinInvalidateRect() has such a "feature" that children are not
1448 // actually extracted from the window's update region when it has
1449 // the WS_CLIPCHILDREN flag, meaning that every child will anyway
1450 // receive a WM_PAINT message if its visible region intersects with
1451 // the update region of its parent, with its update region set to
1452 // that intersection. This in turn means that if we invalidate the
1453 // window completely, all its visible children wil completely repaint
1454 // themselves, what is not we want. The solution is to manually
1455 // substract children from the region we want to be updated.
1456 ULONG wstyle = WinQueryWindowULong( winId(), QWL_STYLE );
1457 if ( (wstyle & WS_CLIPCHILDREN) && children() ) {
1458 HPS lhps = hps;
1459 if ( !lhps ) lhps = qt_display_ps();
1460 HRGN hrgn = GpiCreateRegion( lhps, 1, &rcl );
1461 HRGN whrgn = GpiCreateRegion( lhps, 0, NULL );
1462 int hgt = crect.height();
1463
1464 QObjectListIt it(*children());
1465 register QObject *object;
1466 QWidget *w;
1467 while ( it ) {
1468 object = it.current();
1469 ++it;
1470 if ( object->isWidgetType() ) {
1471 w = (QWidget*)object;
1472 if ( !w->isTopLevel() && w->isShown() ) {
1473 const QRect &r = w->crect;
1474 rcl.xLeft = r.left();
1475 rcl.yBottom = hgt - (r.bottom() + 1);
1476 rcl.xRight = r.right() + 1;
1477 rcl.yTop = hgt - r.top();
1478 GpiSetRegion( lhps, whrgn, 1, &rcl );
1479 GpiCombineRegion( lhps, hrgn, hrgn, whrgn, CRGN_DIFF );
1480 }
1481 }
1482 }
1483 GpiDestroyRegion( lhps, whrgn );
1484 WinInvalidateRegion( winId(), hrgn, FALSE );
1485 GpiDestroyRegion( lhps, hrgn );
1486 } else {
1487 WinInvalidateRect( winId(), &rcl, FALSE );
1488 }
1489#endif
1490 }
1491}
1492
1493void QWidget::repaint( int x, int y, int w, int h, bool erase )
1494{
1495 if ( (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
1496#if defined (DEBUG_REPAINTRESIZE)
1497 qDebug( "repaint(): [%s/%s/%08X] %d,%d; %d,%d erase: %d resizeNoErase: %d",
1498 name(), className(), widget_flags, x, y, w, h, erase,
1499 (testWFlags( WResizeNoErase ) != 0) );
1500#endif
1501 if ( w < 0 )
1502 w = crect.width() - x;
1503 if ( h < 0 )
1504 h = crect.height() - y;
1505 QRect r( x, y, w, h );
1506 if ( r.isEmpty() )
1507 return; // nothing to do
1508
1509 // flip y coordinate
1510 int fy = crect.height() - (y + h);
1511 RECTL rcl = { x, fy, x + w, fy + h };
1512 WinValidateRect( winId(), &rcl, FALSE );
1513
1514 Q_ASSERT( !WinQueryWindowULong( winId(), QWL_QTCLIPRGN ) );
1515 QRegion reg;
1516 if ( r != rect() ) {
1517 reg = QRegion( r );
1518 WinSetWindowULong( winId(), QWL_QTCLIPRGN, (ULONG) &reg );
1519 }
1520
1521 QPaintEvent e( r, erase );
1522 if ( erase )
1523 this->erase( x, y, w, h );
1524 QApplication::sendEvent( this, &e );
1525
1526 WinSetWindowULong( winId(), QWL_QTCLIPRGN, 0 );
1527 }
1528}
1529
1530void QWidget::repaint( const QRegion& reg, bool erase )
1531{
1532 if ( (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
1533#if defined (DEBUG_REPAINTRESIZE)
1534 qDebug( "repaint(): [%s/%s/%08X] <region> erase: %d resizeNoErase: %d",
1535 name(), className(), widget_flags, erase,
1536 (testWFlags( WResizeNoErase ) != 0) );
1537#endif
1538 // convert region y coordinates from Qt to GPI (see qregion_pm.cpp)
1539 WinValidateRegion( winId(), reg.handle( height() ), FALSE );
1540
1541 Q_ASSERT( !WinQueryWindowULong( winId(), QWL_QTCLIPRGN ) );
1542 WinSetWindowULong( winId(), QWL_QTCLIPRGN, (ULONG) &reg );
1543
1544 QPaintEvent e( reg, erase );
1545 if ( erase )
1546 this->erase( reg );
1547 QApplication::sendEvent( this, &e );
1548
1549 WinSetWindowULong( winId(), QWL_QTCLIPRGN, 0 );
1550 }
1551}
1552
1553void QWidget::setWindowState(uint newstate)
1554{
1555 uint oldstate = windowState();
1556
1557 //@@TODO (dmik): should we deactivate the widget when no WindowActive
1558 // is specified? Guess no, because such behavior can be seen in Win32
1559 // (the only exception is when WindowMinimized is set w/o WindowActive).
1560 // As well as nothing is done in Win32 when only WindowActive is
1561 // specified.
1562 ULONG fl = (newstate & WindowActive) ?
1563 SWP_ACTIVATE :
1564 // mimic Win32 behavior
1565 (newstate & WindowMinimized) ? SWP_DEACTIVATE :
1566 // mimic Win32 behavior
1567 ((oldstate & WindowMinimized) &&
1568 (newstate & WindowMaximized)) ? SWP_ACTIVATE :
1569 0;
1570
1571 if (isTopLevel()) {
1572 WId id = winFId();
1573 QTLWExtra *top = topData();
1574
1575 if ((oldstate & WindowMaximized) != (newstate & WindowMaximized)) {
1576 if (isVisible() && !(newstate & WindowMinimized)) {
1577 ULONG f = (newstate & WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
1578 WinSetWindowPos( id, 0, 0, 0, 0, 0, fl | f );
1579 QRect r = topData()->normalGeometry;
1580 if (!(newstate & WindowMaximized) && r.width() >= 0) {
1581 if (pos() != r.topLeft() || size() !=r.size()) {
1582 top->normalGeometry = QRect( 0, 0, -1, -1 );
1583 r.addCoords( top->fleft, top->ftop, top->fleft, top->ftop);
1584 setGeometry( r );
1585 }
1586 }
1587 }
1588 }
1589
1590 if ((oldstate & WindowFullScreen) != (newstate & WindowFullScreen)) {
1591 if (newstate & WindowFullScreen) {
1592 if ( top->normalGeometry.width() < 0 && !(oldstate & WindowMaximized) )
1593 top->normalGeometry = QRect( pos(), size() );
1594 QRect r = QApplication::desktop()->screenGeometry(this);
1595 r.addCoords( -top->fleft, -top->fbottom, top->fright, top->ftop );
1596 WinSetWindowPos(
1597 id, 0, r.x(), r.y(), r.width(), r.height(),
1598 fl | SWP_SIZE | SWP_MOVE
1599 );
1600//@@TODO (dmik): we do not need to call updateFrameStrut() because the frame
1601// is not changed, but who will update our crect?..
1602// updateFrameStrut();
1603 } else {
1604 ULONG f = fl;
1605 // the widget is still maximized
1606 if ( newstate & WindowMaximized ) {
1607 if (isVisible())
1608 f |= SWP_MAXIMIZE;
1609 }
1610 if ( f ) WinSetWindowPos( id, 0, 0, 0, 0, 0, f );
1611 if ( !(newstate & WindowMaximized) ) {
1612 QRect r = top->normalGeometry;
1613 top->normalGeometry = QRect( 0, 0, -1, -1 );
1614 r.addCoords( top->fleft, top->ftop, top->fleft, top->ftop);
1615 setGeometry( r );
1616 }
1617//@@TODO (dmik): we do not need to call updateFrameStrut() because the frame
1618// is not changed, but who will update our crect?..
1619// else {
1620// updateFrameStrut();
1621// }
1622 }
1623 }
1624
1625 if ((oldstate & WindowMinimized) != (newstate & WindowMinimized)) {
1626 if (isVisible()) {
1627 ULONG f =
1628 (newstate & WindowMinimized) ? SWP_MINIMIZE :
1629 (newstate & WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
1630 WinSetWindowPos( id, 0, 0, 0, 0, 0, fl | f );
1631 }
1632 }
1633 }
1634
1635 widget_state &= ~(WState_Minimized | WState_Maximized | WState_FullScreen);
1636 if (newstate & WindowMinimized)
1637 widget_state |= WState_Minimized;
1638 if (newstate & WindowMaximized)
1639 widget_state |= WState_Maximized;
1640 if (newstate & WindowFullScreen)
1641 widget_state |= WState_FullScreen;
1642
1643 QEvent e(QEvent::WindowStateChange);
1644 QApplication::sendEvent(this, &e);
1645}
1646
1647
1648/*
1649 \internal
1650 Platform-specific part of QWidget::hide().
1651*/
1652
1653void QWidget::hideWindow()
1654{
1655 deactivateWidgetCleanup();
1656 HWND id = winFId();
1657
1658#if defined (QT_PM_NO_WIDGETMASK)
1659 WinShowWindow( id, FALSE );
1660#else
1661 qt_WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_HIDE );
1662#endif
1663
1664 if ( isTopLevel() )
1665 WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_DEACTIVATE );
1666
1667 HSWITCH swEntry = topData()->swEntry;
1668 if ( swEntry ) {
1669 SWCNTRL swc;
1670 WinQuerySwitchEntry( swEntry, &swc );
1671 swc.uchVisibility = SWL_INVISIBLE;
1672 WinChangeSwitchEntry( swEntry, &swc );
1673 }
1674}
1675
1676
1677/*
1678 \internal
1679 Platform-specific part of QWidget::show().
1680*/
1681
1682void QWidget::showWindow()
1683{
1684#if defined (QT_PM_NO_WIDGETMASK)
1685 WinShowWindow( winFId(), TRUE );
1686#else
1687 qt_WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, SWP_SHOW );
1688#endif
1689
1690 ULONG fl = 0;
1691 if ( isTopLevel() ) {
1692 // we do this check here bevause setWindowState() does not actually
1693 // change the window state when the window is not visible, assuming
1694 // it will be done here.
1695 if (testWState(WState_Minimized))
1696 fl |= SWP_MINIMIZE;
1697 else if (testWState(WState_Maximized))
1698 fl |= SWP_MAXIMIZE;
1699
1700 if (
1701 !testWFlags(WType_Popup | WStyle_Tool) &&
1702 (!testWFlags(WType_Dialog) || !parentWidget())
1703 ) {
1704 HSWITCH &swEntry = topData()->swEntry;
1705 if ( !swEntry ) {
1706 // lazily create a new window list entry
1707 HWND id = winFId(); // frame handle, if any
1708 PID pid;
1709 WinQueryWindowProcess( id, &pid, NULL );
1710 SWCNTRL swc;
1711 memset( &swc, 0, sizeof(SWCNTRL) );
1712 swc.hwnd = id;
1713 swc.idProcess = pid;
1714 swc.uchVisibility = SWL_VISIBLE;
1715 swc.fbJump = SWL_JUMPABLE;
1716 WinQueryWindowText( id, sizeof(swc.szSwtitle), swc.szSwtitle );
1717 swEntry = WinAddSwitchEntry( &swc );
1718 } else {
1719 SWCNTRL swc;
1720 WinQuerySwitchEntry( swEntry, &swc );
1721 swc.uchVisibility = SWL_VISIBLE;
1722 WinChangeSwitchEntry( swEntry, &swc );
1723 }
1724 }
1725 }
1726 if (!testWFlags(WStyle_Tool) && !isPopup())
1727 fl |= SWP_ACTIVATE;
1728 if ( fl )
1729 WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, fl );
1730}
1731
1732void QWidget::raise()
1733{
1734 QWidget *p = parentWidget();
1735 if ( p && p->childObjects && p->childObjects->findRef(this) >= 0 )
1736 p->childObjects->append( p->childObjects->take() );
1737//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
1738// uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
1739
1740#if defined (QT_PM_NO_WIDGETMASK)
1741 WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
1742#else
1743 qt_WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
1744#endif
1745}
1746
1747void QWidget::lower()
1748{
1749 QWidget *p = parentWidget();
1750 if ( p && p->childObjects && p->childObjects->findRef(this) >= 0 )
1751 p->childObjects->insert( 0, p->childObjects->take() );
1752//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
1753// uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
1754
1755#if defined (QT_PM_NO_WIDGETMASK)
1756 WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
1757#else
1758 qt_WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
1759#endif
1760}
1761
1762void QWidget::stackUnder( QWidget* w )
1763{
1764 QWidget *p = parentWidget();
1765 if ( !w || isTopLevel() || p != w->parentWidget() || this == w )
1766 return;
1767 if ( p && p->childObjects && p->childObjects->findRef(w) >= 0 && p->childObjects->findRef(this) >= 0 ) {
1768 p->childObjects->take();
1769 p->childObjects->insert( p->childObjects->findRef(w), this );
1770 }
1771#if defined (QT_PM_NO_WIDGETMASK)
1772 WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
1773#else
1774 qt_WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
1775#endif
1776}
1777
1778//
1779// The internal qPMRequestConfig, defined in qeventloop_pm.cpp, stores move,
1780// resize and setGeometry requests for a widget that is already
1781// processing a config event. The purpose is to avoid recursion.
1782//
1783void qPMRequestConfig( WId, int, int, int, int, int );
1784
1785void QWidget::internalSetGeometry( int x, int y, int w, int h, bool isMove )
1786{
1787 if ( extra ) { // any size restrictions?
1788 w = QMIN(w,extra->maxw);
1789 h = QMIN(h,extra->maxh);
1790 w = QMAX(w,extra->minw);
1791 h = QMAX(h,extra->minh);
1792 }
1793 if ( w < 1 ) // invalid size
1794 w = 1;
1795 if ( h < 1 )
1796 h = 1;
1797 QSize oldSize( size() );
1798 QPoint oldPos( pos() );
1799 if ( !isTopLevel() )
1800 isMove = (crect.topLeft() != QPoint( x, y ));
1801 bool isResize = w != oldSize.width() || h != oldSize.height();
1802 if ( isMove == FALSE && isResize == FALSE )
1803 return;
1804 clearWState(WState_Maximized);
1805 clearWState(WState_FullScreen);
1806 if (isTopLevel())
1807 topData()->normalGeometry = QRect(0, 0, -1, -1);
1808 if ( testWState(WState_ConfigPending) ) { // processing config event
1809 qPMRequestConfig( winId(), isMove ? 2 : 1, x, y, w, h );
1810 } else {
1811 setWState( WState_ConfigPending );
1812 if ( isTopLevel() ) {
1813/// @todo (dmik) optimize: use extra->topextra directly (after updating fstrut
1814// if necessary) instead of calling frameGeometry()
1815 QRect fr( frameGeometry() );
1816 int fx = fr.left() + x - crect.left();
1817 int fy = fr.top() + y - crect.top();
1818 int fw = fr.width() + w - crect.width();
1819 int fh = fr.height() + h - crect.height();
1820 // flip y coordinate
1821 fy = QApplication::desktop()->height() - (fy + fh);
1822 crect.setRect( x, y, w, h );
1823 WinSetWindowPos( winFId(), 0, fx, fy, fw, fh, SWP_MOVE | SWP_SIZE );
1824 } else {
1825#if defined (QT_PM_NO_WIDGETMASK)
1826 // flip y coordinate
1827 int fy = parentWidget()->height() - (y + h);
1828 crect.setRect( x, y, w, h );
1829 WinSetWindowPos( winId(), 0, x, fy, w, h, SWP_MOVE | SWP_SIZE );
1830#else
1831 // When WS_CLIPCHILDREN and WS_CLIPSIBLINGS are not used,
1832 // WinSetWindowPos() does not correctly update involved windows.
1833 // The fix is to do it ourselves, taking clip regions into account.
1834
1835 QWidget *parent = parentWidget();
1836 const int ph = parent->height();
1837 // flip y coordinate
1838 int fy = ph - (y + h);
1839 // set new and old rectangles
1840 const RECTL rcls [2] = {
1841 // new (y flipped, relative to parent)
1842 { x, fy, x + w, fy + h },
1843 // old (y flipped, relative to parent)
1844 { crect.left(), ph - (crect.bottom() + 1),
1845 crect.right() + 1, ph - crect.top() }
1846 };
1847 const RECTL &rclNew = rcls [0];
1848 const RECTL &rclOld = rcls [1];
1849 // delta to shift coordinate space from parent to this widget
1850 POINTL ptlToSelf = { -x, -fy };
1851 // update crect and move the widget w/o redrawing
1852 crect.setRect( x, y, w, h );
1853 WinSetWindowPos( winId(), 0, x, fy, w, h,
1854 SWP_MOVE | SWP_SIZE | SWP_NOREDRAW );
1855 // use parent PS for blitting
1856 HPS hps = WinGetPS( parent->winId() );
1857 // get old and new clip regions (relative to parent)
1858 HRGN hrgnOld = GpiCreateRegion( hps, 1, &rclOld );
1859 HRGN hrgnNew = GpiCreateRegion( hps, 1, &rclNew );
1860 if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
1861 HRGN hrgnTemp = GpiCreateRegion( hps, 0, NULL );
1862 // old (clipped to the old rect)
1863 WinQueryClipRegion( winId(), hrgnTemp );
1864 GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclOld );
1865 GpiCombineRegion( hps, hrgnOld, hrgnTemp, hrgnOld, CRGN_AND );
1866 // new (clipped to the new rect)
1867 WinQueryClipRegion( winId(), hrgnTemp );
1868 if ( oldSize.height() != h ) {
1869 // keep the clip region top-left aligned by adding the
1870 // height delta (new size - old size)
1871 POINTL ptl = { 0, h - oldSize.height() };
1872 GpiOffsetRegion( hps, hrgnTemp, &ptl );
1873 WinSetClipRegion( winId(), hrgnTemp );
1874 }
1875 GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclNew );
1876 GpiCombineRegion( hps, hrgnNew, hrgnTemp, hrgnNew, CRGN_AND );
1877 GpiDestroyRegion( hps, hrgnTemp );
1878 }
1879 // the rest is useful only when the widget is visible
1880 if ( isVisible() ) {
1881 // create affected region (old + new, relative to widget)
1882 HRGN hrgnAff = GpiCreateRegion( hps, 0, NULL );
1883 GpiCombineRegion( hps, hrgnAff, hrgnOld, hrgnNew, CRGN_OR );
1884 GpiOffsetRegion( hps, hrgnAff, &ptlToSelf );
1885 // get bounding rectangle of affected region
1886 RECTL rclAff;
1887 GpiQueryRegionBox( hps, hrgnAff, &rclAff );
1888 // get region of obstacles limited to affected rectangle
1889 HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
1890 qt_WinProcessWindowObstacles( winId(), &rclAff, hrgnObst, CRGN_OR,
1891 PWO_Sibings | PWO_Ancestors |
1892 PWO_TopLevel );
1893 // shift region of obstacles and affected region back to
1894 // parent coords
1895 GpiOffsetRegion( hps, hrgnObst, (PPOINTL) &rclNew );
1896 GpiOffsetRegion( hps, hrgnAff, (PPOINTL) &rclNew );
1897 // get parent bounds (clip region or rect)
1898 HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
1899 qt_WinQueryClipRegionOrRect( parent->winId(), hrgnUpd );
1900 // add parts of old region beyond parent bounds to
1901 // region of obstacles
1902 GpiCombineRegion( hps, hrgnOld, hrgnOld, hrgnUpd, CRGN_DIFF );
1903 GpiCombineRegion( hps, hrgnObst, hrgnObst, hrgnOld, CRGN_OR );
1904 // substract region of obstacles from affected region
1905 GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnObst, CRGN_DIFF );
1906 // remember it as parent update region (need later)
1907 GpiCombineRegion( hps, hrgnUpd, hrgnAff, 0, CRGN_COPY );
1908 // copy region of obstacles to delta region and shift it by
1909 // delta (note: movement is considered to be top-left aligned)
1910 HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
1911 GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
1912 POINTL ptlDelta = { rclNew.xLeft - rclOld.xLeft,
1913 rclNew.yTop - rclOld.yTop };
1914 GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
1915 // substract region of obstacles from delta region to get
1916 // pure delta
1917 GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
1918 // calculate minimal rectangle to blit (top-left aligned)
1919 int minw = QMIN( oldSize.width(), w );
1920 int minh = QMIN( oldSize.height(), h );
1921 POINTL blitPtls [4] = {
1922 // target (new)
1923 { rclNew.xLeft, rclNew.yTop - minh },
1924 { rclNew.xLeft + minw, rclNew.yTop },
1925 // source (old)
1926 { rclOld.xLeft, rclOld.yTop - minh },
1927 };
1928 // proceed with blitting only if target and source rects differ
1929 if ( blitPtls[0].x != blitPtls[2].x ||
1930 blitPtls[0].y != blitPtls[2].y )
1931 {
1932 // Substract delta region from affected region (to minimize
1933 // flicker)
1934 GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnDelta, CRGN_DIFF );
1935 // set affected region to parent PS
1936 GpiSetClipRegion( hps, hrgnAff, NULL );
1937 // blit minimal rectangle
1938 GpiBitBlt( hps, hps, 3, blitPtls, ROP_SRCCOPY, BBO_IGNORE );
1939 GpiSetClipRegion( hps, 0, NULL );
1940 }
1941 // substract new widget region from the parent update region
1942 // and invalidate it (with underlying children)
1943 GpiCombineRegion( hps, hrgnUpd, hrgnUpd, hrgnNew, CRGN_DIFF );
1944 qt_WinInvalidateRegionEx( parent->winId(), hrgnUpd,
1945 WinQueryWindow( winId(), QW_NEXT ),
1946 HWND_BOTTOM );
1947 // intersect pure delta region with new region
1948 // (to detect areas clipped off to minimize flicker when blitting)
1949 GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnNew, CRGN_AND );
1950 // substract blitted rectangle from new region
1951 GpiSetRegion( hps, hrgnAff, 1, (PRECTL) &blitPtls );
1952 GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnAff, CRGN_DIFF );
1953 // combine the rest with intersected delta region
1954 GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnDelta, CRGN_OR );
1955 // shift the result back to widget coords and invalidate
1956 GpiOffsetRegion( hps, hrgnNew, &ptlToSelf );
1957 WinInvalidateRegion( winId(), hrgnNew, TRUE );
1958 // free resources
1959 GpiDestroyRegion( hps, hrgnDelta );
1960 GpiDestroyRegion( hps, hrgnUpd );
1961 GpiDestroyRegion( hps, hrgnObst );
1962 GpiDestroyRegion( hps, hrgnAff );
1963 }
1964 // free resources
1965 GpiDestroyRegion( hps, hrgnOld );
1966 GpiDestroyRegion( hps, hrgnNew );
1967 WinReleasePS( hps );
1968#endif
1969 }
1970 clearWState( WState_ConfigPending );
1971 }
1972
1973 if ( isVisible() ) {
1974 if ( isMove && pos() != oldPos ) {
1975 QMoveEvent e( pos(), oldPos );
1976 QApplication::sendEvent( this, &e );
1977 }
1978 if ( isResize ) {
1979 QResizeEvent e( size(), oldSize );
1980 QApplication::sendEvent( this, &e );
1981 if ( !testWFlags( WStaticContents ) )
1982 repaint( !testWFlags(WResizeNoErase) );
1983 }
1984 } else {
1985 if ( isMove && pos() != oldPos )
1986 QApplication::postEvent( this,
1987 new QMoveEvent( pos(), oldPos ) );
1988 if ( isResize )
1989 QApplication::postEvent( this,
1990 new QResizeEvent( size(), oldSize ) );
1991 }
1992}
1993
1994void QWidget::setMinimumSize( int minw, int minh )
1995{
1996#if defined(QT_CHECK_RANGE)
1997 if ( minw < 0 || minh < 0 )
1998 qWarning("QWidget::setMinimumSize: The smallest allowed size is (0,0)");
1999#endif
2000 createExtra();
2001 if ( extra->minw == minw && extra->minh == minh )
2002 return;
2003 extra->minw = minw;
2004 extra->minh = minh;
2005 if ( minw > width() || minh > height() ) {
2006 bool resized = testWState( WState_Resized );
2007 resize( QMAX(minw,width()), QMAX(minh,height()) );
2008 if ( !resized )
2009 clearWState( WState_Resized ); //not a user resize
2010 }
2011 updateGeometry();
2012}
2013
2014void QWidget::setMaximumSize( int maxw, int maxh )
2015{
2016#if defined(QT_CHECK_RANGE)
2017 if ( maxw > QWIDGETSIZE_MAX || maxh > QWIDGETSIZE_MAX ) {
2018 qWarning("QWidget::setMaximumSize: The largest allowed size is (%d,%d)",
2019 QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
2020 maxw = QMIN( maxw, QWIDGETSIZE_MAX );
2021 maxh = QMIN( maxh, QWIDGETSIZE_MAX );
2022 }
2023 if ( maxw < 0 || maxh < 0 ) {
2024 qWarning("QWidget::setMaximumSize: (%s/%s) Negative sizes (%d,%d) "
2025 "are not possible",
2026 name( "unnamed" ), className(), maxw, maxh );
2027 maxw = QMAX( maxw, 0 );
2028 maxh = QMAX( maxh, 0 );
2029 }
2030#endif
2031 createExtra();
2032 if ( extra->maxw == maxw && extra->maxh == maxh )
2033 return;
2034 extra->maxw = maxw;
2035 extra->maxh = maxh;
2036 if ( maxw < width() || maxh < height() ) {
2037 bool resized = testWState( WState_Resized );
2038 resize( QMIN(maxw,width()), QMIN(maxh,height()) );
2039 if ( !resized )
2040 clearWState( WState_Resized ); //not a user resize
2041 }
2042 updateGeometry();
2043}
2044
2045void QWidget::setSizeIncrement( int w, int h )
2046{
2047 createTLExtra();
2048 extra->topextra->incw = w;
2049 extra->topextra->inch = h;
2050}
2051
2052void QWidget::setBaseSize( int w, int h )
2053{
2054 createTLExtra();
2055 extra->topextra->basew = w;
2056 extra->topextra->baseh = h;
2057}
2058
2059extern void qt_erase_background( HPS, int, int, int, int,
2060 const QColor &, const QPixmap *, int, int, int );
2061
2062void QWidget::erase( int x, int y, int w, int h )
2063{
2064 // SIMILAR TO region ERASE BELOW
2065
2066 if ( backgroundMode()==NoBackground )
2067 return;
2068 if ( w < 0 )
2069 w = crect.width() - x;
2070 if ( h < 0 )
2071 h = crect.height() - y;
2072
2073 HPS lhps;
2074 bool tmphps;
2075
2076 if( QPainter::redirect( this ) ) {
2077 tmphps = FALSE;
2078 lhps = QPainter::redirect( this )->handle();
2079 Q_ASSERT( lhps );
2080 } else if ( !hps ) {
2081 tmphps = TRUE;
2082 lhps = getTargetPS( ClipAll );
2083 } else {
2084 tmphps = FALSE;
2085 lhps = hps;
2086 }
2087
2088 QPoint offset = backgroundOffset();
2089 int ox = offset.x();
2090 int oy = offset.y();
2091
2092 qt_erase_background(
2093 lhps, x, y, w, h, bg_col, backgroundPixmap(),
2094 ox, oy, crect.height()
2095 );
2096
2097 if ( tmphps )
2098 WinReleasePS( lhps );
2099}
2100
2101void QWidget::erase( const QRegion& rgn )
2102{
2103 // SIMILAR TO rect ERASE ABOVE
2104
2105 if ( backgroundMode()==NoBackground )
2106 return;
2107
2108 HPS lhps;
2109 bool tmphps;
2110
2111 if( QPainter::redirect( this ) ) {
2112 tmphps = FALSE;
2113 lhps = QPainter::redirect( this )->handle();
2114 Q_ASSERT( lhps );
2115 } else if ( !hps ) {
2116 tmphps = TRUE;
2117 lhps = getTargetPS( ClipAll );
2118 } else {
2119 tmphps = FALSE;
2120 lhps = hps;
2121 }
2122
2123 HRGN oldRegion = GpiQueryClipRegion( lhps );
2124 HRGN newRegion = 0;
2125 if ( oldRegion ) {
2126 GpiSetClipRegion( lhps, 0, NULL );
2127 newRegion = GpiCreateRegion( lhps, 0, NULL );
2128 GpiCombineRegion( lhps, newRegion, oldRegion, rgn.handle( height() ),
2129 CRGN_AND );
2130 } else {
2131 newRegion = rgn.handle( height() );
2132 }
2133 GpiSetClipRegion( lhps, newRegion, NULL );
2134
2135 QPoint offset = backgroundOffset();
2136 int ox = offset.x();
2137 int oy = offset.y();
2138
2139 qt_erase_background(
2140 lhps, 0, 0, crect.width(), crect.height(),
2141 bg_col, backgroundPixmap(), ox, oy, crect.height()
2142 );
2143
2144 GpiSetClipRegion( lhps, oldRegion, NULL );
2145
2146 if ( oldRegion )
2147 GpiDestroyRegion( lhps, newRegion );
2148 if ( tmphps )
2149 WinReleasePS( lhps );
2150}
2151
2152#if defined (QT_PM_NO_WIDGETMASK)
2153
2154// helper function to extract regions of all windows that overlap the given
2155// hwnd subject to their z-order (excluding children of hwnd) from the given
2156// hrgn. hps is the presentation space of hrgn.
2157void qt_WinExcludeOverlappingWindows( HWND hwnd, HPS hps, HRGN hrgn )
2158{
2159 HRGN vr = GpiCreateRegion( hps, 0, NULL );
2160 RECTL r;
2161
2162 // enumerate all windows that are on top of this hwnd
2163 HWND id = hwnd, deskId = QApplication::desktop()->winId();
2164 do {
2165 HWND i = id;
2166 while( (i = WinQueryWindow( i, QW_PREV )) ) {
2167 if ( WinIsWindowShowing( i ) ) {
2168 WinQueryWindowRect( i, &r );
2169 WinMapWindowPoints( i, hwnd, (PPOINTL) &r, 2 );
2170 GpiSetRegion( hps, vr, 1, &r );
2171 GpiCombineRegion( hps, hrgn, hrgn, vr, CRGN_DIFF );
2172 }
2173 }
2174 id = WinQueryWindow( id, QW_PARENT );
2175 } while( id != deskId );
2176
2177 GpiDestroyRegion( hps, vr );
2178}
2179
2180// helper function to scroll window contents. WinScrollWindow() is a bit
2181// buggy and corrupts update regions sometimes (which leaves some outdated
2182// areas unpainted after scrolling), so we reimplement its functionality in
2183// this function. dy and clip->yBottom/yTop should be GPI coordinates, not Qt.
2184// all clip coordinates are inclusive.
2185void qt_WinScrollWindowWell( HWND hwnd, LONG dx, LONG dy, const PRECTL clip = NULL )
2186{
2187 WinLockVisRegions( HWND_DESKTOP, TRUE );
2188
2189 HPS lhps = WinGetClipPS(
2190 hwnd, HWND_TOP,
2191 PSF_LOCKWINDOWUPDATE | PSF_CLIPSIBLINGS
2192 );
2193 if ( clip )
2194 GpiIntersectClipRectangle( lhps, clip );
2195
2196 // remember the update region and validate it. it will be shifted and
2197 // invalidated again later
2198 HRGN update = GpiCreateRegion( lhps, 0, NULL );
2199 WinQueryUpdateRegion( hwnd, update );
2200 WinValidateRegion( hwnd, update, TRUE );
2201
2202 POINTL ptls[4];
2203 RECTL &sr = *(PRECTL) &ptls[2];
2204 RECTL &tr = *(PRECTL) &ptls[0];
2205
2206 // get the source rect for scrolling
2207 GpiQueryClipBox( lhps, &sr );
2208 sr.xRight++; sr.yTop++; // inclusive -> exclusive
2209
2210 // get the visible region ignoring areas covered by children
2211 HRGN visible = GpiCreateRegion( lhps, 1, &sr );
2212 qt_WinExcludeOverlappingWindows( hwnd, lhps, visible );
2213
2214 // scroll visible region rectangles separately to avoid the flicker
2215 // that could be produced by scrolling parts of overlapping windows
2216 RGNRECT ctl;
2217 ctl.ircStart = 1;
2218 ctl.crc = 0;
2219 ctl.crcReturned = 0;
2220 if ( dx >= 0 ) {
2221 if ( dy >= 0 ) ctl.ulDirection = RECTDIR_RTLF_TOPBOT;
2222 else ctl.ulDirection = RECTDIR_RTLF_BOTTOP;
2223 } else {
2224 if ( dy >= 0 ) ctl.ulDirection = RECTDIR_LFRT_TOPBOT;
2225 else ctl.ulDirection = RECTDIR_LFRT_BOTTOP;
2226 }
2227 GpiQueryRegionRects( lhps, visible, NULL, &ctl, NULL );
2228 ctl.crc = ctl.crcReturned;
2229 int rclcnt = ctl.crcReturned;
2230 PRECTL rcls = new RECTL[rclcnt];
2231 GpiQueryRegionRects( lhps, visible, NULL, &ctl, rcls );
2232 PRECTL r = rcls;
2233 for ( int i = 0; i < rclcnt; i++, r++ ) {
2234 // source rect
2235 sr = *r;
2236 // target rect
2237 tr.xLeft = sr.xLeft + dx;
2238 tr.xRight = sr.xRight + dx;
2239 tr.yBottom = sr.yBottom + dy;
2240 tr.yTop = sr.yTop + dy;
2241 GpiBitBlt( lhps, lhps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
2242 }
2243 delete [] rcls;
2244
2245 // make the scrolled version of the visible region
2246 HRGN scrolled = GpiCreateRegion( lhps, 0, NULL );
2247 GpiCombineRegion( lhps, scrolled, visible, 0, CRGN_COPY );
2248 // invalidate the initial update region
2249 GpiCombineRegion( lhps, scrolled, scrolled, update, CRGN_DIFF );
2250 // shift the region
2251 POINTL dp = { dx, dy };
2252 GpiOffsetRegion( lhps, scrolled, &dp );
2253 // substract scrolled from visible to get invalid areas
2254 GpiCombineRegion( lhps, scrolled, visible, scrolled, CRGN_DIFF );
2255
2256 WinInvalidateRegion( hwnd, scrolled, TRUE );
2257
2258 GpiDestroyRegion( lhps, scrolled );
2259 GpiDestroyRegion( lhps, visible );
2260 GpiDestroyRegion( lhps, update );
2261
2262 WinReleasePS( lhps );
2263
2264 WinLockVisRegions( HWND_DESKTOP, FALSE );
2265
2266 WinUpdateWindow( hwnd );
2267}
2268
2269#else
2270
2271/**
2272 * \internal
2273 * Helper to scroll window contents.
2274 * All coordinates are GPI, not Qt.
2275 */
2276static void scrollWindow( HWND hwnd, int w, int h,
2277 int dx, int dy, const PRECTL clip = NULL )
2278{
2279 POINTL ptlDelta = { dx, dy };
2280
2281 POINTL ptls[4];
2282 RECTL &rclSrc = *(PRECTL) &ptls[2];
2283 RECTL &rclDst = *(PRECTL) &ptls[0];
2284
2285 if ( clip ) {
2286 rclSrc = *clip;
2287 } else {
2288 rclSrc.xLeft = rclSrc.yBottom = 0;
2289 rclSrc.xRight = w;
2290 rclSrc.yTop = h;
2291 }
2292 rclDst = rclSrc;
2293 rclDst.xLeft += dx;
2294 rclDst.xRight += dx;
2295 rclDst.yBottom += dy;
2296 rclDst.yTop += dy;
2297
2298 if ( !clip ) {
2299 // move all child widgets silently
2300 SWP swp;
2301 HWND child = WinQueryWindow( hwnd, QW_BOTTOM );
2302 if ( child != NULLHANDLE ) {
2303 for ( ; child != HWND_TOP; child = swp.hwndInsertBehind ) {
2304 WinQueryWindowPos( child, &swp );
2305 swp.x += dx;
2306 swp.y += dy;
2307 WinSetWindowPos( child, 0, swp.x, swp.y, 0, 0,
2308 SWP_MOVE | SWP_NOADJUST | SWP_NOREDRAW );
2309 // WinSetWindowPos() doesn't send WM_MOVE to windows w/o
2310 // CS_MOVENOTIFY, but having this style for non-toplevel
2311 // widgets is unwanted, so we send them WM_MOVE manually
2312 // to let their geometry to be properly updated by
2313 // QETWidget::translateConfigEvent().
2314 WinSendMsg( child, WM_MOVE, 0, 0 );
2315 }
2316 }
2317 }
2318
2319 WinLockVisRegions( HWND_DESKTOP, TRUE );
2320
2321 HPS hps = WinGetPS( hwnd );
2322
2323 // get widget bounds (clip region or rect)
2324 HRGN hrgnClip = GpiCreateRegion( hps, 0, NULL );
2325 qt_WinQueryClipRegionOrRect( hwnd, hrgnClip );
2326 // compose a region uncovered after scrolling
2327 HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
2328 GpiCombineRegion( hps, hrgnUpd, hrgnClip, 0, CRGN_COPY );
2329 GpiOffsetRegion( hps, hrgnUpd, &ptlDelta );
2330 GpiCombineRegion( hps, hrgnUpd, hrgnClip, hrgnUpd, CRGN_DIFF );
2331
2332 if ( clip ) {
2333 // intersect it with the given clip rect
2334 HRGN hrgn = GpiCreateRegion( hps, 1, clip );
2335 GpiCombineRegion( hps, hrgnUpd, hrgnClip, hrgnUpd, CRGN_AND );
2336 GpiDestroyRegion( hps, hrgn );
2337 }
2338
2339 int pwoFlags = PWO_Ancestors | PWO_Sibings | PWO_TopLevel;
2340 if ( clip )
2341 pwoFlags |= PWO_Children;
2342
2343 // get the region of obstacles
2344 HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
2345 qt_WinProcessWindowObstacles( hwnd, &rclSrc, hrgnObst, CRGN_OR, pwoFlags );
2346 // create the delta region of obstacles
2347 HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
2348 GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
2349 GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
2350 // substract the region of obstaces fro the delta region to get pure delta
2351 GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
2352 // substract obstacles the clip region
2353 GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnObst, CRGN_DIFF );
2354 // substract pure delta from the clip region (to reduce flicker)
2355 GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnDelta, CRGN_DIFF );
2356
2357 // scroll the area
2358 GpiSetClipRegion( hps, hrgnClip, NULL );
2359 GpiBitBlt( hps, hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
2360 GpiSetClipRegion( hps, 0, NULL );
2361
2362 // invalidate the delta region (clipped off when blitting)
2363 WinInvalidateRegion( hwnd, hrgnDelta, clip == NULL );
2364
2365 // invalidate the region uncovered after scrolling
2366 WinInvalidateRegion( hwnd, hrgnUpd, clip == NULL );
2367
2368 GpiDestroyRegion( hps, hrgnDelta );
2369 GpiDestroyRegion( hps, hrgnObst );
2370 GpiDestroyRegion( hps, hrgnUpd );
2371 GpiDestroyRegion( hps, hrgnClip );
2372 WinReleasePS( hps );
2373
2374 WinLockVisRegions( HWND_DESKTOP, FALSE );
2375
2376 WinUpdateWindow( hwnd );
2377}
2378
2379#endif
2380
2381void QWidget::scroll( int dx, int dy )
2382{
2383 if ( testWState( WState_BlockUpdates ) && !children() )
2384 return;
2385
2386#if defined (QT_PM_NO_WIDGETMASK)
2387
2388 // move non-toplevel children
2389 if ( children() ) {
2390 QObjectListIt it(*children());
2391 register QObject *obj;
2392 int h = crect.height();
2393 while ( (obj=it.current()) ) {
2394 ++it;
2395 if ( obj->isWidgetType() ) {
2396 QWidget *w = (QWidget*)obj;
2397 if ( !w->isTopLevel() ) {
2398 WinSetWindowPos(
2399 w->winId(), 0,
2400 w->crect.left() + dx,
2401 // flip y coordinate
2402 h - (w->crect.bottom() + dy + 1),
2403 0, 0,
2404 SWP_MOVE | SWP_NOADJUST | SWP_NOREDRAW
2405 );
2406 // WinSetWindowPos() doesn't send WM_MOVE to windows w/o
2407 // CS_MOVENOTIFY, but having this style for non-toplevel
2408 // widgets is unwanted, so we send them WM_MOVE manually
2409 // to let their geometry to be properly updated by
2410 // QETWidget::translateConfigEvent().
2411 WinSendMsg( w->winId(), WM_MOVE, 0, 0 );
2412 }
2413 }
2414 }
2415 }
2416
2417 qt_WinScrollWindowWell( winId(), dx, -dy, NULL );
2418
2419#else
2420
2421 scrollWindow( winId(), width(), height(), dx, -dy, NULL );
2422
2423#endif
2424}
2425
2426void QWidget::scroll( int dx, int dy, const QRect& r )
2427{
2428 if ( testWState( WState_BlockUpdates ) )
2429 return;
2430
2431#if defined (QT_PM_NO_WIDGETMASK)
2432
2433 int h = crect.height();
2434 // flip y coordinate (all coordinates are inclusive)
2435 RECTL rcl = { r.left(), h - (r.bottom() + 1), r.right(), h - (r.top() + 1) };
2436 qt_WinScrollWindowWell( winId(), dx, -dy, &rcl );
2437
2438#else
2439
2440 int h = crect.height();
2441 // flip y coordinate
2442 RECTL rcl = { r.left(), h - (r.bottom() + 1),
2443 r.right() + 1, h - r.top() };
2444 scrollWindow( winId(), width(), height(), dx, -dy, &rcl );
2445
2446#endif
2447}
2448
2449void QWidget::drawText( int x, int y, const QString &str )
2450{
2451 if ( testWState(WState_Visible) ) {
2452 QPainter paint;
2453 paint.begin( this );
2454 paint.drawText( x, y, str );
2455 paint.end();
2456 }
2457}
2458
2459
2460int QWidget::metric( int m ) const
2461{
2462 LONG val;
2463 if ( m == QPaintDeviceMetrics::PdmWidth ) {
2464 val = crect.width();
2465 } else if ( m == QPaintDeviceMetrics::PdmHeight ) {
2466 val = crect.height();
2467 } else {
2468 HDC hdc = GpiQueryDevice( qt_display_ps() );
2469 switch ( m ) {
2470 case QPaintDeviceMetrics::PdmDpiX:
2471 case QPaintDeviceMetrics::PdmPhysicalDpiX:
2472 DevQueryCaps( hdc, CAPS_HORIZONTAL_FONT_RES, 1, &val );
2473 break;
2474 case QPaintDeviceMetrics::PdmDpiY:
2475 case QPaintDeviceMetrics::PdmPhysicalDpiY:
2476 DevQueryCaps( hdc, CAPS_VERTICAL_FONT_RES, 1, &val );
2477 break;
2478 case QPaintDeviceMetrics::PdmWidthMM:
2479 DevQueryCaps( hdc, CAPS_HORIZONTAL_RESOLUTION, 1, &val );
2480 val = width() * 1000 / val;
2481 break;
2482 case QPaintDeviceMetrics::PdmHeightMM:
2483 DevQueryCaps( hdc, CAPS_VERTICAL_RESOLUTION, 1, &val );
2484 val = width() * 1000 / val;
2485 break;
2486 case QPaintDeviceMetrics::PdmNumColors:
2487 DevQueryCaps( hdc, CAPS_COLORS, 1, &val );
2488 break;
2489 case QPaintDeviceMetrics::PdmDepth:
2490 LONG colorInfo [2];
2491 DevQueryCaps( hdc, CAPS_COLOR_PLANES, 2, colorInfo );
2492 val = colorInfo [0] * colorInfo [1];
2493 break;
2494 default:
2495 val = 0;
2496#if defined(QT_CHECK_RANGE)
2497 qWarning( "QWidget::metric: Invalid metric command" );
2498#endif
2499 }
2500 }
2501 return val;
2502}
2503
2504void QWidget::createSysExtra()
2505{
2506//@@TODO (dmik): later
2507// extra->dropTarget = 0;
2508}
2509
2510void QWidget::deleteSysExtra()
2511{
2512 setAcceptDrops( FALSE );
2513}
2514
2515void QWidget::createTLSysExtra()
2516{
2517 extra->topextra->fId = 0;
2518 extra->topextra->swEntry = 0;
2519 extra->topextra->pmIcon = 0;
2520}
2521
2522void QWidget::deleteTLSysExtra()
2523{
2524 if ( extra->topextra->pmIcon )
2525 WinDestroyPointer( extra->topextra->pmIcon );
2526 if ( extra->topextra->swEntry )
2527 WinRemoveSwitchEntry( extra->topextra->swEntry );
2528 // frame window (extra->topextra->fId) is destroyed in
2529 // destroy() if it exists
2530}
2531
2532bool QWidget::acceptDrops() const
2533{
2534 return 0;
2535/// @todo (dmik) later
2536// return ( extra && extra->dropTarget );
2537}
2538
2539void QWidget::setAcceptDrops( bool on )
2540{
2541/// @todo (dmik) later
2542// // Enablement is defined by extra->dropTarget != 0.
2543//
2544// if ( on ) {
2545// // Turn on.
2546// createExtra();
2547// QWExtra *extra = extraData();
2548// if ( !extra->dropTarget )
2549// extra->dropTarget = qt_olednd_register( this );
2550// } else {
2551// // Turn off.
2552// QWExtra *extra = extraData();
2553// if ( extra && extra->dropTarget ) {
2554// qt_olednd_unregister(this, extra->dropTarget);
2555// extra->dropTarget = 0;
2556// }
2557// }
2558}
2559
2560#if !defined (QT_PM_NO_WIDGETMASK)
2561
2562// helper for QWidget::setMask()
2563static void setClipRegion( HWND hwnd, int x, int y, int w, int h, HRGN hrgn,
2564 HWND parent )
2565{
2566 if ( !WinIsWindowVisible( hwnd ) ) {
2567 // if the window is hidden, no need to invalidate anything
2568 WinSetClipRegion( hwnd, hrgn );
2569 return;
2570 }
2571
2572 HPS hps = qt_display_ps();
2573 const RECTL rcl = { 0, 0, w, h };
2574
2575 // get the old bounds (clip region or rect)
2576 HRGN hrgnOld = GpiCreateRegion( hps, 0, NULL );
2577 qt_WinQueryClipRegionOrRect( hwnd, hrgnOld );
2578 // set the new clip region
2579 WinSetClipRegion( hwnd, hrgn );
2580
2581 HRGN hrgnUpd;
2582 if ( hrgn != 0 ) {
2583 hrgnUpd = GpiCreateRegion( hps, 0, NULL );
2584 // substract the new clip region from the old one
2585 GpiCombineRegion( hps, hrgnUpd, hrgnOld, hrgn, CRGN_DIFF );
2586 // move the result to the parent coordinate space
2587 POINTL ptl = { x, y };
2588 GpiOffsetRegion( hps, hrgnUpd, &ptl );
2589 // invalidate areas in parent uncovered by the new clip region
2590 qt_WinInvalidateRegionEx( parent, hrgnUpd,
2591 WinQueryWindow( hwnd, QW_NEXT ), HWND_BOTTOM );
2592 } else {
2593 // the new region is being set to NULL, which means to widget bounds
2594 // (no need to substract new from old, because it will produce RGN_NULL)
2595 hrgnUpd = GpiCreateRegion( hps, 1, &rcl );
2596 hrgn = hrgnUpd;
2597 }
2598 // substract the old clip region from the new one
2599 GpiCombineRegion( hps, hrgnUpd, hrgn, hrgnOld, CRGN_DIFF );
2600 // invalidate areas in hwnd uncovered by the new clip region
2601 WinInvalidateRegion( hwnd, hrgnUpd, TRUE );
2602
2603 GpiDestroyRegion( hps, hrgnUpd );
2604 GpiDestroyRegion( hps, hrgnOld );
2605}
2606
2607#endif
2608
2609/*!
2610 \overload
2611
2612 Causes only the parts of the widget which overlap \a region to be
2613 visible. If the region includes pixels outside the rect() of the
2614 widget, window system controls in that area may or may not be
2615 visible, depending on the platform.
2616
2617 Note that this effect can be slow if the region is particularly
2618 complex.
2619
2620 Note that on OS/2, masks for top-level widgets are not currently
2621 supported, so setting a mask on such a widget has no effect.
2622
2623 \sa setMask(), clearMask()
2624*/
2625
2626void QWidget::setMask( const QRegion &region )
2627{
2628#if !defined (QT_PM_NO_WIDGETMASK)
2629 if (isTopLevel()) {
2630#if defined (QT_CHECK_STATE)
2631 qWarning( "QWidget::setMask() for top-level widgets "
2632 "is not implemented on OS/2" );
2633#endif
2634 return;
2635 }
2636 setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
2637 width(), height(), region.handle( height() ),
2638 parentWidget()->winId() );
2639#else
2640 Q_UNUSED( region );
2641#endif
2642}
2643
2644/*!
2645 Causes only the pixels of the widget for which \a bitmap has a
2646 corresponding 1 bit to be visible. If the region includes pixels
2647 outside the rect() of the widget, window system controls in that
2648 area may or may not be visible, depending on the platform.
2649
2650 Note that this effect can be slow if the region is particularly
2651 complex.
2652
2653 Note that on OS/2, masks for top-level widgets are not currently
2654 supported, so setting a mask on such a widget has no effect.
2655
2656 See \c examples/tux for an example of masking for transparency.
2657
2658 \sa setMask(), clearMask()
2659*/
2660
2661void QWidget::setMask( const QBitmap &bitmap )
2662{
2663#if !defined (QT_PM_NO_WIDGETMASK)
2664 if (isTopLevel()) {
2665#if defined (QT_CHECK_STATE)
2666 qWarning( "QWidget::setMask() for top-level widgets "
2667 "is not implemented on OS/2" );
2668#endif
2669 return;
2670 }
2671 QRegion rgn = QRegion( bitmap );
2672 setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
2673 width(), height(), rgn.handle( height() ),
2674 parentWidget()->winId() );
2675#else
2676 Q_UNUSED( bitmap );
2677#endif
2678}
2679
2680void QWidget::clearMask()
2681{
2682#if !defined (QT_PM_NO_WIDGETMASK)
2683 if (isTopLevel())
2684 return;
2685 setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
2686 width(), height(), 0,
2687 parentWidget()->winId() );
2688#endif
2689}
2690
2691void QWidget::setName( const char *name )
2692{
2693 QObject::setName( name );
2694}
2695
2696void QWidget::updateFrameStrut() const
2697{
2698 QWidget *that = (QWidget *) this;
2699
2700 if ( !isVisible() || isDesktop() ) {
2701 that->fstrut_dirty = isVisible();
2702 return;
2703 }
2704
2705 QTLWExtra *top = that->topData();
2706 if ( top->fId ) {
2707 // this widget has WC_FRAME
2708 SWP cswp;
2709 WinQueryWindowPos( winId(), &cswp );
2710 SWP fswp;
2711 WinQueryWindowPos( top->fId, &fswp );
2712 // flip y coordinates
2713 fswp.y = QApplication::desktop()->height() - (fswp.y + fswp.cy);
2714 cswp.y = fswp.cy - (cswp.y + cswp.cy);
2715 that->crect.setRect(
2716 fswp.x + cswp.x, fswp.y + cswp.y,
2717 cswp.cx, cswp.cy
2718 );
2719
2720 top->fleft = cswp.x;
2721 top->ftop = cswp.y;
2722 top->fright = fswp.cx - cswp.x - cswp.cx;
2723 top->fbottom = fswp.cy - cswp.y - cswp.cy;
2724 }
2725 that->fstrut_dirty = FALSE;
2726}
2727
2728void QWidget::setMouseTracking( bool enable )
2729{
2730 if ( enable )
2731 setWState( WState_MouseTracking );
2732 else
2733 clearWState( WState_MouseTracking );
2734}
2735
2736void QWidget::setWindowOpacity(double)
2737{
2738}
2739
2740double QWidget::windowOpacity() const
2741{
2742 return 1.0;
2743}
2744
2745/**
2746 * \internal
2747 * Returns the frame wihdow handle if this widget is a top-level widget and
2748 * has the standard WC_FRAME as its parent/owner (where it is FID_CLIENT).
2749 * If the widget does not have the standard frame or it is not top-level, this
2750 * function simply retuns the winId() value.
2751 */
2752WId QWidget::winFId()
2753{
2754 HWND fId = 0;
2755 if ( isTopLevel() )
2756 fId = topData()->fId;
2757 if ( !fId )
2758 fId = winId();
2759 return fId;
2760}
2761
2762#if !defined (QT_PM_NO_WIDGETMASK)
2763
2764/*!
2765 * \internal
2766 *
2767 * Validates areas of this widget covered by (intersected with) its children
2768 * and sibling widgets.
2769 *
2770 * Clip regions of all relative widgets (set by WinSetClipRegion()) are taken
2771 * into account.
2772 */
2773void QWidget::validateObstacles()
2774{
2775 RECTL updateRcl;
2776 if ( WinQueryUpdateRect( winId(), &updateRcl ) ) {
2777 // the update rectangle may be empty
2778 if ( updateRcl.xLeft != updateRcl.xRight &&
2779 updateRcl.yBottom != updateRcl.yTop ) {
2780 qt_WinProcessWindowObstacles( winId(), &updateRcl, 0, 0 );
2781 }
2782 }
2783}
2784
2785#endif // !defined (QT_PM_NO_WIDGETMASK)
2786
2787/*!
2788 * \internal
2789 *
2790 * Obtains a presentaiton space to draw on this widget, set up according
2791 * mode \a m and to widget flags.
2792 *
2793 * The returned handle must be freed using WinReleasePS() after usage.
2794 */
2795HPS QWidget::getTargetPS( ClipMode m /* = ClipDefault */ )
2796{
2797 HPS widgetPS = 0;
2798
2799 if ( isDesktop() ) {
2800 widgetPS = WinGetScreenPS( HWND_DESKTOP );
2801 return widgetPS;
2802 } else {
2803 if ( m == Unclipped || (m == ClipDefault &&
2804 testWFlags( WPaintUnclipped )) ) {
2805 widgetPS = WinGetClipPS( winId(), 0, PSF_PARENTCLIP );
2806 return widgetPS;
2807 } else {
2808 widgetPS = WinGetPS( winId() );
2809 }
2810 }
2811
2812#if !defined (QT_PM_NO_WIDGETMASK)
2813 RECTL rcl = { 0, 0, crect.width(), crect.height() };
2814 HRGN hrgn = GpiCreateRegion( widgetPS, 1, &rcl );
2815 qt_WinProcessWindowObstacles( winId(), NULL, hrgn, CRGN_DIFF );
2816 HRGN hrgnOld = 0;
2817 GpiSetClipRegion( widgetPS, hrgn, &hrgnOld );
2818 Q_ASSERT( !hrgnOld );
2819 if ( hrgnOld )
2820 GpiDestroyRegion( widgetPS, hrgnOld );
2821#endif
2822
2823 return widgetPS;
2824}
2825
Note: See TracBrowser for help on using the repository browser.