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

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

kernel: Attempted to fix some spontaneous Qt application traps during window management (seen in Psi a couple of times after showing big tool tips, see ticket:34 for more info):

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