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

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

Widgets: Improved min/max/fullscreen handling:

  • Layout management now works correctly when the window is minimized;
  • Fixed duplicate WindowStateChange events;
  • WindowMinimized, WindowMaximized, WindowFullScreen are mutually exclusive (note: this fetaure is experimental, since it is partly incompatible with the weird non-exclusive Qt behavior on other platforms).
  • Property svn:keywords set to Id
File size: 101.6 KB
Line 
1/****************************************************************************
2** $Id: qwidget_pm.cpp 102 2006-07-24 21:11:03Z 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 // When the FS_SHELLPOSITION flag is specified during WC_FRAME window
944 // creation its size and position remains zero until it is shown
945 // for the first time. So, we don't use FS_SHELLPOSITION but emulate
946 // its functionality here.
947 SWP swp;
948 WinQueryTaskSizePos( 0, 0, &swp );
949 WinSetWindowPos( fId, 0, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE );
950 } else {
951 // create child widget
952 HWND parentw = parentWidget()->winId();
953#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
954 qDebug( "|Creating child window [%s/%s]:\n"
955 "| owner & parent = %08lX\n"
956 "| class = '%s'\n"
957 "| title = '%s'\n"
958 "| style = %08lX",
959 name(), this->className(), parentw, pszClassName, title, style );
960#endif
961 id = WinCreateWindow(
962 parentw, pszClassName, title, style,
963 0, parentWidget()->crect.height() - 30, 100, 30,
964 parentw, HWND_TOP, 0, NULL, NULL
965 );
966#ifndef QT_NO_DEBUG
967#ifdef QT_DEBUGWINCREATEDESTROY
968 qDebug( "| hwnd = %08lX", id );
969#endif
970 if ( id == 0 )
971 qSystemWarning( "QWidget: Failed to create window" );
972#endif
973 setWinId( id );
974 }
975
976 if ( desktop ) {
977 setWState( WState_Visible );
978 } else {
979 SWP cswp;
980 WinQueryWindowPos( id, &cswp );
981 if ( topLevel ) {
982 QTLWExtra *top = topData();
983 if ( fId ) {
984 SWP fswp;
985 WinQueryWindowPos( fId, &fswp );
986 // flip y coordinates
987 fswp.y = sh - (fswp.y + fswp.cy);
988 cswp.y = fswp.cy - (cswp.y + cswp.cy);
989 crect.setRect(
990 fswp.x + cswp.x, fswp.y + cswp.y,
991 cswp.cx, cswp.cy
992 );
993
994 top->fleft = cswp.x;
995 top->ftop = cswp.y;
996 top->fright = fswp.cx - cswp.x - cswp.cx;
997 top->fbottom = fswp.cy - cswp.y - cswp.cy;
998 top->fId = fId;
999 } else {
1000 // flip y coordinate
1001 cswp.y = sh - (cswp.y + cswp.cy);
1002 crect.setRect( cswp.x, cswp.y, cswp.cx, cswp.cy );
1003 }
1004 fstrut_dirty = FALSE;
1005 } else {
1006 int cy = parentWidget()->crect.height();
1007 // flip y coordinate
1008 cswp.y = cy - (cswp.y + cswp.cy);
1009 crect.setRect( cswp.x, cswp.y, cswp.cx, cswp.cy );
1010 }
1011 }
1012
1013 setWState( WState_Created ); // accept move/resize events
1014 hps = 0; // no presentation space
1015
1016 setFontSys();
1017
1018/// @todo (dmik) remove?
1019// QInputContext::enable( this, im_enabled & !((bool)testWState(WState_Disabled)) );
1020}
1021
1022
1023void QWidget::destroy( bool destroyWindow, bool destroySubWindows )
1024{
1025 deactivateWidgetCleanup();
1026 if ( testWState(WState_Created) ) {
1027 clearWState( WState_Created );
1028 if ( children() ) {
1029 QObjectListIt it(*children());
1030 register QObject *obj;
1031 while ( (obj=it.current()) ) { // destroy all widget children
1032 ++it;
1033 if ( obj->isWidgetType() )
1034 ((QWidget*)obj)->destroy(destroySubWindows,
1035 destroySubWindows);
1036 }
1037 }
1038 if ( mouseGrb == this )
1039 releaseMouse();
1040 if ( keyboardGrb == this )
1041 releaseKeyboard();
1042 if ( testWFlags(WShowModal) ) // just be sure we leave modal
1043 qt_leave_modal( this );
1044 else if ( testWFlags(WType_Popup) )
1045 qApp->closePopup( this );
1046 if ( destroyWindow && !testWFlags(WType_Desktop) ) {
1047 HWND id = winId();
1048 if ( isTopLevel() && !testWFlags(WType_Popup) ) {
1049 // extra data including extra->topextra has been already
1050 // deleted at this point by deleteExtra() and therefore
1051 // calling winFId() useless -- it will always return the
1052 // client window handle. Use WinQueryWindow() instead.
1053 id = WinQueryWindow( id, QW_PARENT );
1054 }
1055#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
1056 qDebug( "|Destroying window [%s/%s]:\n"
1057 "| hwnd = %08lX",
1058 name(), className(), id );
1059#endif
1060 qt_WinDestroyWindow( id );
1061 }
1062 setWinId( 0 );
1063 }
1064}
1065
1066void QWidget::reparentSys( QWidget *parent, WFlags f, const QPoint &p,
1067 bool showIt )
1068{
1069 QWidget* oldtlw = topLevelWidget();
1070 WId old_winfid = winFId();
1071
1072 // hide and reparent our own window away. Otherwise we might get
1073 // destroyed when emitting the child remove event below. See QWorkspace.
1074 // this is also necessary for modal windows to leave the modal state
1075 // correctly.
1076 if ( isVisible() ) {
1077 hide();
1078 WinSetParent( old_winfid, HWND_OBJECT, FALSE );
1079 WinSetOwner( old_winfid, 0 );
1080 }
1081
1082 // unblock the widget if blocked
1083 QWidget *blockedBy = 0;
1084 if ( isTopLevel() )
1085 blockedBy = (QWidget*) WinQueryWindowULong( winId(), QWL_QTMODAL );
1086 if ( !blockedBy && parentWidget() )
1087 blockedBy = (QWidget*) WinQueryWindowULong(
1088 parentWidget()->topLevelWidget()->winId(), QWL_QTMODAL );
1089 if ( blockedBy ) {
1090 QEvent e( QEvent::WindowUnblocked );
1091 qt_sendBlocked( this, blockedBy, &e, FALSE );
1092 }
1093
1094 if ( testWFlags(WType_Desktop) )
1095 old_winfid = 0;
1096 setWinId( 0 );
1097 if ( isTopLevel() ) {
1098 QTLWExtra *top = topData();
1099 if ( top->swEntry ) {
1100 WinRemoveSwitchEntry( top->swEntry );
1101 top->swEntry = 0;
1102 }
1103 top->fId = 0;
1104 }
1105
1106 if ( parent != parentObj ) {
1107 if ( parentObj ) // remove from parent
1108 parentObj->removeChild( this );
1109 if ( parent ) // insert into new parent
1110 parent->insertChild( this );
1111 }
1112
1113 bool enable = isEnabled(); // remember status
1114 FocusPolicy fp = focusPolicy();
1115 QSize s = size();
1116 QString capt = caption();
1117 widget_flags = f;
1118 clearWState( WState_Created | WState_Visible | WState_ForceHide );
1119 create();
1120 if ( isTopLevel() || (!parent || parent->isVisible() ) )
1121 setWState( WState_ForceHide ); // new widgets do not show up in already visible parents
1122 const QObjectList *chlist = children();
1123 if ( chlist ) { // reparent children
1124 SWP swp;
1125 QObjectListIt it( *chlist );
1126 QObject *obj;
1127 while ( (obj=it.current()) ) {
1128 if ( obj->isWidgetType() ) {
1129 QWidget *w = (QWidget *)obj;
1130 if ( w->isPopup() )
1131 ;
1132 else if ( w->isTopLevel() ) {
1133 w->reparent( this, w->getWFlags(), w->pos(), !w->isHidden() );
1134 } else {
1135 WinSetParent( w->winId(), winId(), FALSE );
1136 WinSetOwner( w->winId(), winId() );
1137 // bring PM coords into accordance with Qt coords,
1138 // otherwise setGeometry() below will wrongly position
1139 // children if this widget manages their layout.
1140 int hd = height() - s.height();
1141 WinQueryWindowPos( w->winId(), &swp );
1142 swp.y += hd;
1143 WinSetWindowPos( w->winId(), 0, swp.x, swp.y, 0, 0, SWP_MOVE );
1144 }
1145 }
1146 ++it;
1147 }
1148 }
1149
1150 // block the widget if it should be blocked
1151 blockedBy = 0;
1152 if ( parentWidget() )
1153 blockedBy = (QWidget*) WinQueryWindowULong(
1154 parentWidget()->topLevelWidget()->winId(), QWL_QTMODAL );
1155 if ( blockedBy ) {
1156 if ( isTopLevel() && testWFlags( WGroupLeader ) )
1157 blockedBy = 0;
1158 } else {
1159 QWidget *topModal = qApp->activeModalWidget();
1160 if (
1161 topModal && this != topModal && parentWidget() != topModal &&
1162 isTopLevel() && !testWFlags( WGroupLeader )
1163 )
1164 blockedBy = topModal;
1165 }
1166 if ( blockedBy ) {
1167 QEvent e( QEvent::WindowBlocked );
1168 qt_sendBlocked( this, blockedBy, &e, FALSE );
1169 }
1170
1171 setGeometry( p.x(), p.y(), s.width(), s.height() );
1172 setEnabled( enable );
1173 setFocusPolicy( fp );
1174 if ( !capt.isNull() ) {
1175 extra->topextra->caption = QString::null;
1176 setCaption( capt );
1177 }
1178 if ( showIt )
1179 show();
1180 if ( old_winfid )
1181 qt_WinDestroyWindow( old_winfid );
1182
1183 reparentFocusWidgets( oldtlw ); // fix focus chains
1184}
1185
1186QPoint QWidget::mapToGlobal( const QPoint &pos ) const
1187{
1188 if ( !isVisible() || isMinimized() )
1189 return mapTo( topLevelWidget(), pos ) + topLevelWidget()->pos() +
1190 (topLevelWidget()->geometry().topLeft() - topLevelWidget()->frameGeometry().topLeft());
1191 POINTL ptl;
1192 ptl.x = pos.x();
1193 // flip y (local) coordinate
1194 ptl.y = height() - (pos.y() + 1);
1195 WinMapWindowPoints( winId(), HWND_DESKTOP, &ptl, 1 );
1196 // flip y (global) coordinate
1197 ptl.y = QApplication::desktop()->height() - (ptl.y + 1);
1198 return QPoint( ptl.x, ptl.y );
1199}
1200
1201QPoint QWidget::mapFromGlobal( const QPoint &pos ) const
1202{
1203 if ( !isVisible() || isMinimized() )
1204 return mapFrom( topLevelWidget(), pos - topLevelWidget()->pos() );
1205 POINTL ptl;
1206 ptl.x = pos.x();
1207 // flip y (global) coordinate
1208 ptl.y = QApplication::desktop()->height() - (pos.y() + 1);
1209 WinMapWindowPoints( HWND_DESKTOP, winId(), &ptl, 1 );
1210 // flip y (local) coordinate
1211 ptl.y = height() - (ptl.y + 1);
1212 return QPoint( ptl.x, ptl.y );
1213}
1214
1215void QWidget::setFontSys( QFont *f )
1216{
1217//@@TODO (dmik): should this do something on OS/2?
1218//@@TODO (dmik): remove?
1219// QInputContext::setFont( this, (f ? *f : font()) );
1220}
1221
1222void QWidget::setMicroFocusHint(int x, int y, int width, int height, bool text, QFont *f)
1223{
1224//@@TODO (dmik): do we need to create a caret (cursor) in OS/2 also?
1225// currently, try to do so (which can be useful for 3rd-party apps
1226// that are interested in the current cursor position, i.e. where the user
1227// input is now taking place.
1228 // flip y coordinate
1229 int fy = crect.height() - (y + height);
1230 WinCreateCursor( winId(), x, fy, width, height, CURSOR_SOLID, NULL );
1231
1232//@@TODO (dmik): remove?
1233// if ( text )
1234// QInputContext::setFocusHint( x, y, width, height, this );
1235 setFontSys( f );
1236
1237 if ( QRect( x, y, width, height ) != microFocusHint() )
1238 extraData()->micro_focus_hint.setRect( x, y, width, height );
1239}
1240
1241void QWidget::resetInputContext()
1242{
1243//@@TODO (dmik): remove?
1244// QInputContext::accept();
1245}
1246
1247void QWidget::setBackgroundColorDirect( const QColor &color )
1248{
1249 bg_col = color;
1250 if ( extra && extra->bg_pix ) { // kill the background pixmap
1251 delete extra->bg_pix;
1252 extra->bg_pix = 0;
1253 }
1254}
1255
1256
1257static int allow_null_pixmaps = 0;
1258
1259
1260void QWidget::setBackgroundPixmapDirect( const QPixmap &pixmap )
1261{
1262 QPixmap old;
1263 if ( extra && extra->bg_pix )
1264 old = *extra->bg_pix;
1265 if ( !allow_null_pixmaps && pixmap.isNull() ) {
1266 if ( extra && extra->bg_pix ) {
1267 delete extra->bg_pix;
1268 extra->bg_pix = 0;
1269 }
1270 } else {
1271 if ( extra && extra->bg_pix )
1272 delete extra->bg_pix;
1273 else
1274 createExtra();
1275 extra->bg_pix = new QPixmap( pixmap );
1276 }
1277}
1278
1279
1280void QWidget::setBackgroundEmpty()
1281{
1282 allow_null_pixmaps++;
1283 setErasePixmap(QPixmap());
1284 allow_null_pixmaps--;
1285}
1286
1287extern void qt_set_cursor( QWidget *, const QCursor & ); // qapplication_pm.cpp
1288
1289void QWidget::setCursor( const QCursor &cursor )
1290{
1291 if ( cursor.handle() != arrowCursor.handle()
1292 || (extra && extra->curs) ) {
1293 createExtra();
1294 delete extra->curs;
1295 extra->curs = new QCursor(cursor);
1296 }
1297 setWState( WState_OwnCursor );
1298 qt_set_cursor( this, QWidget::cursor() );
1299}
1300
1301void QWidget::unsetCursor()
1302{
1303 if ( extra ) {
1304 delete extra->curs;
1305 extra->curs = 0;
1306 }
1307 if ( !isTopLevel() )
1308 clearWState( WState_OwnCursor );
1309 qt_set_cursor( this, cursor() );
1310}
1311
1312void QWidget::setCaption( const QString &caption )
1313{
1314 if ( QWidget::caption() == caption )
1315 return; // for less flicker
1316 topData()->caption = caption;
1317
1318 QCString cap = caption.local8Bit();
1319 WinSetWindowText( winFId(), cap );
1320
1321 HSWITCH swEntry = topData()->swEntry;
1322 if ( swEntry ) {
1323 SWCNTRL swc;
1324 WinQuerySwitchEntry( swEntry, &swc );
1325 strncpy( swc.szSwtitle, cap, sizeof(swc.szSwtitle)-1 );
1326 swc.szSwtitle [sizeof(swc.szSwtitle)-1] = 0;
1327 WinChangeSwitchEntry( swEntry, &swc );
1328 }
1329
1330 QEvent e( QEvent::CaptionChange );
1331 QApplication::sendEvent( this, &e );
1332}
1333
1334void QWidget::setIcon( const QPixmap &pixmap )
1335{
1336 QTLWExtra* x = topData();
1337 delete x->icon;
1338 x->icon = 0;
1339 HPOINTER oldIcon = x->pmIcon;
1340 x->pmIcon = 0;
1341
1342 if ( !pixmap.isNull() ) { // valid icon
1343 x->icon = new QPixmap( pixmap );
1344
1345 if ( isTopLevel() ) {
1346 const QPixmap *normal = 0;
1347 const QPixmap *mini = 0;
1348
1349 // QPixmap::createIcon() is not yet capable to create both normal
1350 // and mini icons (due to a bug in WinCreateIconIndirect), so
1351 // if the specified pixmap is equal or larger than the normal icon
1352 // size, then we create a normal icon, otherwise a mini one.
1353
1354 int iconw = WinQuerySysValue( HWND_DESKTOP, SV_CXICON );
1355 int iconh = WinQuerySysValue( HWND_DESKTOP, SV_CYICON );
1356 if ( pixmap.width() >= iconw && pixmap.height() >= iconh ) {
1357 normal = &pixmap;
1358 } else {
1359 mini = &pixmap;
1360 }
1361
1362 x->pmIcon = QPixmap::createIcon( false, 0, 0, normal, mini );
1363 }
1364 }
1365
1366 if ( isTopLevel() )
1367 WinSendMsg( x->fId, WM_SETICON, MPFROMLONG( x->pmIcon ), 0 );
1368
1369 if ( oldIcon )
1370 WinDestroyPointer( oldIcon );
1371
1372 QEvent e( QEvent::IconChange );
1373 QApplication::sendEvent( this, &e );
1374}
1375
1376
1377void QWidget::setIconText( const QString &iconText )
1378{
1379 topData()->iconText = iconText;
1380}
1381
1382QCursor *qt_grab_cursor()
1383{
1384 return mouseGrbCur;
1385}
1386
1387void QWidget::grabMouse()
1388{
1389 if ( !qt_nograb() ) {
1390 if ( mouseGrb )
1391 mouseGrb->releaseMouse();
1392 WinSetCapture( HWND_DESKTOP, winFId() );
1393 mouseGrb = this;
1394 }
1395}
1396
1397void QWidget::grabMouse( const QCursor &cursor )
1398{
1399 if ( !qt_nograb() ) {
1400 if ( mouseGrb )
1401 mouseGrb->releaseMouse();
1402 WinSetCapture( HWND_DESKTOP, winFId() );
1403 mouseGrbCur = new QCursor( cursor );
1404 WinSetPointer( HWND_DESKTOP, mouseGrbCur->handle() );
1405 mouseGrb = this;
1406 }
1407}
1408
1409void QWidget::releaseMouse()
1410{
1411 if ( !qt_nograb() && mouseGrb == this ) {
1412 WinSetCapture( HWND_DESKTOP, 0 );
1413 if ( mouseGrbCur ) {
1414 delete mouseGrbCur;
1415 mouseGrbCur = 0;
1416 }
1417 mouseGrb = 0;
1418 }
1419}
1420
1421void QWidget::grabKeyboard()
1422{
1423 if ( !qt_nograb() ) {
1424 if ( keyboardGrb )
1425 keyboardGrb->releaseKeyboard();
1426 keyboardGrb = this;
1427 }
1428}
1429
1430void QWidget::releaseKeyboard()
1431{
1432 if ( !qt_nograb() && keyboardGrb == this )
1433 keyboardGrb = 0;
1434}
1435
1436
1437QWidget *QWidget::mouseGrabber()
1438{
1439 return mouseGrb;
1440}
1441
1442QWidget *QWidget::keyboardGrabber()
1443{
1444 return keyboardGrb;
1445}
1446
1447void QWidget::setActiveWindow()
1448{
1449 WinSetActiveWindow( HWND_DESKTOP, topLevelWidget()->winFId() );
1450}
1451
1452void QWidget::update()
1453{
1454 update( 0, 0, -1, -1 );
1455}
1456
1457void QWidget::update( int x, int y, int w, int h )
1458{
1459 if ( w && h &&
1460 (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
1461 if ( w < 0 )
1462 w = crect.width() - x;
1463 if ( h < 0 )
1464 h = crect.height() - y;
1465
1466 // flip y coordinate
1467 y = crect.height() - (y + h);
1468 RECTL rcl = { x, y, x + w, y + h };
1469
1470#if !defined (QT_PM_NO_WIDGETMASK)
1471 WinInvalidateRect( winId(), &rcl, FALSE );
1472#else
1473 // WinInvalidateRect() has such a "feature" that children are not
1474 // actually extracted from the window's update region when it has
1475 // the WS_CLIPCHILDREN flag, meaning that every child will anyway
1476 // receive a WM_PAINT message if its visible region intersects with
1477 // the update region of its parent, with its update region set to
1478 // that intersection. This in turn means that if we invalidate the
1479 // window completely, all its visible children wil completely repaint
1480 // themselves, what is not we want. The solution is to manually
1481 // substract children from the region we want to be updated.
1482 ULONG wstyle = WinQueryWindowULong( winId(), QWL_STYLE );
1483 if ( (wstyle & WS_CLIPCHILDREN) && children() ) {
1484 HPS lhps = hps;
1485 if ( !lhps ) lhps = qt_display_ps();
1486 HRGN hrgn = GpiCreateRegion( lhps, 1, &rcl );
1487 HRGN whrgn = GpiCreateRegion( lhps, 0, NULL );
1488 int hgt = crect.height();
1489
1490 QObjectListIt it(*children());
1491 register QObject *object;
1492 QWidget *w;
1493 while ( it ) {
1494 object = it.current();
1495 ++it;
1496 if ( object->isWidgetType() ) {
1497 w = (QWidget*)object;
1498 if ( !w->isTopLevel() && w->isShown() ) {
1499 const QRect &r = w->crect;
1500 rcl.xLeft = r.left();
1501 rcl.yBottom = hgt - (r.bottom() + 1);
1502 rcl.xRight = r.right() + 1;
1503 rcl.yTop = hgt - r.top();
1504 GpiSetRegion( lhps, whrgn, 1, &rcl );
1505 GpiCombineRegion( lhps, hrgn, hrgn, whrgn, CRGN_DIFF );
1506 }
1507 }
1508 }
1509 GpiDestroyRegion( lhps, whrgn );
1510 WinInvalidateRegion( winId(), hrgn, FALSE );
1511 GpiDestroyRegion( lhps, hrgn );
1512 } else {
1513 WinInvalidateRect( winId(), &rcl, FALSE );
1514 }
1515#endif
1516 }
1517}
1518
1519void QWidget::repaint( int x, int y, int w, int h, bool erase )
1520{
1521 if ( (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
1522#if defined (DEBUG_REPAINTRESIZE)
1523 qDebug( "repaint(): [%s/%s/%08X] %d,%d; %d,%d erase: %d resizeNoErase: %d",
1524 name(), className(), widget_flags, x, y, w, h, erase,
1525 (testWFlags( WResizeNoErase ) != 0) );
1526#endif
1527 if ( w < 0 )
1528 w = crect.width() - x;
1529 if ( h < 0 )
1530 h = crect.height() - y;
1531 QRect r( x, y, w, h );
1532 if ( r.isEmpty() )
1533 return; // nothing to do
1534
1535 // flip y coordinate
1536 int fy = crect.height() - (y + h);
1537 RECTL rcl = { x, fy, x + w, fy + h };
1538 WinValidateRect( winId(), &rcl, FALSE );
1539
1540 Q_ASSERT( !WinQueryWindowULong( winId(), QWL_QTCLIPRGN ) );
1541 QRegion reg;
1542 if ( r != rect() ) {
1543 reg = QRegion( r );
1544 WinSetWindowULong( winId(), QWL_QTCLIPRGN, (ULONG) &reg );
1545 }
1546
1547 QPaintEvent e( r, erase );
1548 if ( erase )
1549 this->erase( x, y, w, h );
1550 QApplication::sendEvent( this, &e );
1551
1552 WinSetWindowULong( winId(), QWL_QTCLIPRGN, 0 );
1553 }
1554}
1555
1556void QWidget::repaint( const QRegion& reg, bool erase )
1557{
1558 if ( (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
1559#if defined (DEBUG_REPAINTRESIZE)
1560 qDebug( "repaint(): [%s/%s/%08X] <region> erase: %d resizeNoErase: %d",
1561 name(), className(), widget_flags, erase,
1562 (testWFlags( WResizeNoErase ) != 0) );
1563#endif
1564 // convert region y coordinates from Qt to GPI (see qregion_pm.cpp)
1565 WinValidateRegion( winId(), reg.handle( height() ), FALSE );
1566
1567 Q_ASSERT( !WinQueryWindowULong( winId(), QWL_QTCLIPRGN ) );
1568 WinSetWindowULong( winId(), QWL_QTCLIPRGN, (ULONG) &reg );
1569
1570 QPaintEvent e( reg, erase );
1571 if ( erase )
1572 this->erase( reg );
1573 QApplication::sendEvent( this, &e );
1574
1575 WinSetWindowULong( winId(), QWL_QTCLIPRGN, 0 );
1576 }
1577}
1578
1579void QWidget::setWindowState( uint newstate )
1580{
1581 uint oldstate = windowState();
1582
1583 if ( newstate == oldstate )
1584 return;
1585
1586 ULONG fl = (newstate & WindowActive) ? SWP_ACTIVATE : 0;
1587
1588 /// @todo (dmik):
1589 // Ugrh. I cannot see any good logic in those weird window state
1590 // manipulations (see setWindowState() dox, original showMinimized(),
1591 // showMaximized(). showFullScreen() and showNormal() implementations).
1592 // So, treat all of three flags as exclusive for now (note: the below
1593 // code relies on this).
1594 uint op = 0;
1595 if ( newstate & WindowFullScreen ) op = WindowFullScreen;
1596 else if ( newstate & WindowMinimized ) op = WindowMinimized;
1597 else if ( newstate & WindowMaximized ) op = WindowMaximized;
1598
1599 if ( op == WindowMinimized )
1600 fl = SWP_DEACTIVATE;
1601
1602 if ( isTopLevel() && isVisible() ) {
1603 WId id = winFId();
1604 QTLWExtra *top = topData();
1605
1606 // set flag for the WM_WINDOWPOSCHANGED handler in QtFrameProc
1607 top->in_sendWindowState = 1;
1608
1609 if ( op == WindowMinimized || op == WindowMaximized ) {
1610 fl |= op == WindowMinimized ? SWP_MINIMIZE : SWP_MAXIMIZE;
1611 WinSetWindowPos( id, 0, 0, 0, 0, 0, fl );
1612 } else if ( op == WindowFullScreen ) {
1613 if ( !(oldstate & (WindowMinimized | WindowMaximized)) ) {
1614 top->normalGeometry = frameGeometry();
1615 } else {
1616 // extract normal geometry from window words
1617 USHORT x = WinQueryWindowUShort( id, QWS_XRESTORE );
1618 USHORT y = WinQueryWindowUShort( id, QWS_YRESTORE );
1619 USHORT w = WinQueryWindowUShort( id, QWS_CXRESTORE );
1620 USHORT h = WinQueryWindowUShort( id, QWS_CYRESTORE );
1621 // restore first to update the frame strut
1622 if ( oldstate & WindowMinimized )
1623 WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_RESTORE );
1624 // flip y coordinate
1625 y = QApplication::desktop()->height() - (y + h);
1626 top->normalGeometry = QRect( x, y, w, h );
1627 }
1628 QRect r = QApplication::desktop()->screenGeometry( this );
1629 r.addCoords( -top->fleft, -top->fbottom, top->fright, top->ftop );
1630 WinSetWindowPos( id, 0, r.x(), r.y(), r.width(), r.height(),
1631 fl | SWP_SIZE | SWP_MOVE );
1632 } else {
1633 if ( oldstate & WindowFullScreen ) {
1634 QRect r = top->normalGeometry;
1635 if ( r != frameGeometry() ) {
1636 r.addCoords( top->fleft, top->ftop, -top->fright, -top->fbottom );
1637 setGeometry( r );
1638 }
1639 top->normalGeometry.setWidth( 0 );
1640 } else {
1641 QRect r = top->normalGeometry;
1642 if ( r.isValid() ) {
1643 // store normal geometry in window words
1644 USHORT x = r.x();
1645 USHORT y = r.y();
1646 USHORT w = r.width();
1647 USHORT h = r.height();
1648 // flip y coordinate
1649 y = QApplication::desktop()->height() - (y + h);
1650 WinSetWindowUShort( id, QWS_XRESTORE, x );
1651 WinSetWindowUShort( id, QWS_YRESTORE, y );
1652 WinSetWindowUShort( id, QWS_CXRESTORE, w );
1653 WinSetWindowUShort( id, QWS_CYRESTORE, h );
1654 top->normalGeometry.setWidth( 0 );
1655 }
1656 WinSetWindowPos( id, 0, 0, 0, 0, 0, fl | SWP_RESTORE );
1657 }
1658 }
1659
1660 top->in_sendWindowState = 0;
1661 }
1662
1663 widget_state &= ~(WState_Minimized | WState_Maximized | WState_FullScreen);
1664 if (newstate & WindowMinimized)
1665 widget_state |= WState_Minimized;
1666 if (newstate & WindowMaximized)
1667 widget_state |= WState_Maximized;
1668 if (newstate & WindowFullScreen)
1669 widget_state |= WState_FullScreen;
1670
1671 QEvent e(QEvent::WindowStateChange);
1672 QApplication::sendEvent(this, &e);
1673}
1674
1675
1676/*
1677 \internal
1678 Platform-specific part of QWidget::hide().
1679*/
1680
1681void QWidget::hideWindow()
1682{
1683 deactivateWidgetCleanup();
1684 HWND id = winFId();
1685
1686#if defined (QT_PM_NO_WIDGETMASK)
1687 WinShowWindow( id, FALSE );
1688#else
1689 qt_WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_HIDE );
1690#endif
1691
1692 if ( isTopLevel() )
1693 WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_DEACTIVATE );
1694
1695 HSWITCH swEntry = topData()->swEntry;
1696 if ( swEntry ) {
1697 SWCNTRL swc;
1698 WinQuerySwitchEntry( swEntry, &swc );
1699 swc.uchVisibility = SWL_INVISIBLE;
1700 WinChangeSwitchEntry( swEntry, &swc );
1701 }
1702}
1703
1704
1705/*
1706 \internal
1707 Platform-specific part of QWidget::show().
1708*/
1709
1710void QWidget::showWindow()
1711{
1712#if defined (QT_PM_NO_WIDGETMASK)
1713 WinShowWindow( winFId(), TRUE );
1714#else
1715 qt_WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, SWP_SHOW );
1716#endif
1717
1718 ULONG fl = 0;
1719 if ( isTopLevel() ) {
1720 // we do this check here because setWindowState() does not actually
1721 // change the window state when the window is not visible, assuming
1722 // it will be done here.
1723 if (testWState(WState_Minimized))
1724 fl |= SWP_MINIMIZE;
1725 else if (testWState(WState_Maximized))
1726 fl |= SWP_MAXIMIZE;
1727 else if (testWState(WState_FullScreen)) {
1728 QTLWExtra *top = topData();
1729 topData()->normalGeometry = QRect( pos(), size() );
1730 QRect r = QApplication::desktop()->screenGeometry( this );
1731 r.addCoords( -top->fleft, -top->fbottom, top->fright, top->ftop );
1732 WinSetWindowPos( winFId(), 0, r.x(), r.y(), r.width(), r.height(),
1733 fl | SWP_SIZE | SWP_MOVE );
1734 }
1735
1736 if (
1737 !testWFlags(WType_Popup | WStyle_Tool) &&
1738 (!testWFlags(WType_Dialog) || !parentWidget())
1739 ) {
1740 HSWITCH &swEntry = topData()->swEntry;
1741 if ( !swEntry ) {
1742 // lazily create a new window list entry
1743 HWND id = winFId(); // frame handle, if any
1744 PID pid;
1745 WinQueryWindowProcess( id, &pid, NULL );
1746 SWCNTRL swc;
1747 memset( &swc, 0, sizeof(SWCNTRL) );
1748 swc.hwnd = id;
1749 swc.idProcess = pid;
1750 swc.uchVisibility = SWL_VISIBLE;
1751 swc.fbJump = SWL_JUMPABLE;
1752 WinQueryWindowText( id, sizeof(swc.szSwtitle), swc.szSwtitle );
1753 swEntry = WinAddSwitchEntry( &swc );
1754 } else {
1755 SWCNTRL swc;
1756 WinQuerySwitchEntry( swEntry, &swc );
1757 swc.uchVisibility = SWL_VISIBLE;
1758 WinChangeSwitchEntry( swEntry, &swc );
1759 }
1760 }
1761 }
1762 if (!testWFlags(WStyle_Tool) && !isPopup())
1763 fl |= SWP_ACTIVATE;
1764 if ( fl )
1765 WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, fl );
1766}
1767
1768void QWidget::raise()
1769{
1770 QWidget *p = parentWidget();
1771 if ( p && p->childObjects && p->childObjects->findRef(this) >= 0 )
1772 p->childObjects->append( p->childObjects->take() );
1773//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
1774// uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
1775
1776#if defined (QT_PM_NO_WIDGETMASK)
1777 WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
1778#else
1779 qt_WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
1780#endif
1781}
1782
1783void QWidget::lower()
1784{
1785 QWidget *p = parentWidget();
1786 if ( p && p->childObjects && p->childObjects->findRef(this) >= 0 )
1787 p->childObjects->insert( 0, p->childObjects->take() );
1788//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
1789// uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
1790
1791#if defined (QT_PM_NO_WIDGETMASK)
1792 WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
1793#else
1794 qt_WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
1795#endif
1796}
1797
1798void QWidget::stackUnder( QWidget* w )
1799{
1800 QWidget *p = parentWidget();
1801 if ( !w || isTopLevel() || p != w->parentWidget() || this == w )
1802 return;
1803 if ( p && p->childObjects && p->childObjects->findRef(w) >= 0 && p->childObjects->findRef(this) >= 0 ) {
1804 p->childObjects->take();
1805 p->childObjects->insert( p->childObjects->findRef(w), this );
1806 }
1807#if defined (QT_PM_NO_WIDGETMASK)
1808 WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
1809#else
1810 qt_WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
1811#endif
1812}
1813
1814//
1815// The internal qPMRequestConfig, defined in qeventloop_pm.cpp, stores move,
1816// resize and setGeometry requests for a widget that is already
1817// processing a config event. The purpose is to avoid recursion.
1818//
1819void qPMRequestConfig( WId, int, int, int, int, int );
1820
1821void QWidget::internalSetGeometry( int x, int y, int w, int h, bool isMove )
1822{
1823 if ( extra ) { // any size restrictions?
1824 w = QMIN(w,extra->maxw);
1825 h = QMIN(h,extra->maxh);
1826 w = QMAX(w,extra->minw);
1827 h = QMAX(h,extra->minh);
1828 }
1829 if ( w < 1 ) // invalid size
1830 w = 1;
1831 if ( h < 1 )
1832 h = 1;
1833 QSize oldSize( size() );
1834 QPoint oldPos( pos() );
1835 if ( !isTopLevel() )
1836 isMove = (crect.topLeft() != QPoint( x, y ));
1837 bool isResize = w != oldSize.width() || h != oldSize.height();
1838 if ( isMove == FALSE && isResize == FALSE )
1839 return;
1840 clearWState(WState_Maximized);
1841 clearWState(WState_FullScreen);
1842 if ( testWState(WState_ConfigPending) ) { // processing config event
1843 qPMRequestConfig( winId(), isMove ? 2 : 1, x, y, w, h );
1844 } else {
1845 setWState( WState_ConfigPending );
1846 if ( isTopLevel() ) {
1847/// @todo (dmik) optimize: use extra->topextra directly (after updating fstrut
1848// if necessary) instead of calling frameGeometry()
1849 QRect fr( frameGeometry() );
1850 int fx = fr.left() + x - crect.left();
1851 int fy = fr.top() + y - crect.top();
1852 int fw = fr.width() + w - crect.width();
1853 int fh = fr.height() + h - crect.height();
1854 // flip y coordinate
1855 fy = QApplication::desktop()->height() - (fy + fh);
1856 crect.setRect( x, y, w, h );
1857 WinSetWindowPos( winFId(), 0, fx, fy, fw, fh, SWP_MOVE | SWP_SIZE );
1858 } else {
1859#if defined (QT_PM_NO_WIDGETMASK)
1860 // flip y coordinate
1861 int fy = parentWidget()->height() - (y + h);
1862 crect.setRect( x, y, w, h );
1863 WinSetWindowPos( winId(), 0, x, fy, w, h, SWP_MOVE | SWP_SIZE );
1864#else
1865 // When WS_CLIPCHILDREN and WS_CLIPSIBLINGS are not used,
1866 // WinSetWindowPos() does not correctly update involved windows.
1867 // The fix is to do it ourselves, taking clip regions into account.
1868
1869 QWidget *parent = parentWidget();
1870 const int ph = parent->height();
1871 // flip y coordinate
1872 int fy = ph - (y + h);
1873 // set new and old rectangles
1874 const RECTL rcls [2] = {
1875 // new (y flipped, relative to parent)
1876 { x, fy, x + w, fy + h },
1877 // old (y flipped, relative to parent)
1878 { crect.left(), ph - (crect.bottom() + 1),
1879 crect.right() + 1, ph - crect.top() }
1880 };
1881 const RECTL &rclNew = rcls [0];
1882 const RECTL &rclOld = rcls [1];
1883 // delta to shift coordinate space from parent to this widget
1884 POINTL ptlToSelf = { -x, -fy };
1885 // update crect and move the widget w/o redrawing
1886 crect.setRect( x, y, w, h );
1887 WinSetWindowPos( winId(), 0, x, fy, w, h,
1888 SWP_MOVE | SWP_SIZE | SWP_NOREDRAW );
1889 // use parent PS for blitting
1890 HPS hps = WinGetPS( parent->winId() );
1891 // get old and new clip regions (relative to parent)
1892 HRGN hrgnOld = GpiCreateRegion( hps, 1, &rclOld );
1893 HRGN hrgnNew = GpiCreateRegion( hps, 1, &rclNew );
1894 if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
1895 HRGN hrgnTemp = GpiCreateRegion( hps, 0, NULL );
1896 // old (clipped to the old rect)
1897 WinQueryClipRegion( winId(), hrgnTemp );
1898 GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclOld );
1899 GpiCombineRegion( hps, hrgnOld, hrgnTemp, hrgnOld, CRGN_AND );
1900 // new (clipped to the new rect)
1901 WinQueryClipRegion( winId(), hrgnTemp );
1902 if ( oldSize.height() != h ) {
1903 // keep the clip region top-left aligned by adding the
1904 // height delta (new size - old size)
1905 POINTL ptl = { 0, h - oldSize.height() };
1906 GpiOffsetRegion( hps, hrgnTemp, &ptl );
1907 WinSetClipRegion( winId(), hrgnTemp );
1908 }
1909 GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclNew );
1910 GpiCombineRegion( hps, hrgnNew, hrgnTemp, hrgnNew, CRGN_AND );
1911 GpiDestroyRegion( hps, hrgnTemp );
1912 }
1913 // the rest is useful only when the widget is visible
1914 if ( isVisible() ) {
1915 // create affected region (old + new, relative to widget)
1916 HRGN hrgnAff = GpiCreateRegion( hps, 0, NULL );
1917 GpiCombineRegion( hps, hrgnAff, hrgnOld, hrgnNew, CRGN_OR );
1918 GpiOffsetRegion( hps, hrgnAff, &ptlToSelf );
1919 // get bounding rectangle of affected region
1920 RECTL rclAff;
1921 GpiQueryRegionBox( hps, hrgnAff, &rclAff );
1922 // get region of obstacles limited to affected rectangle
1923 HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
1924 qt_WinProcessWindowObstacles( winId(), &rclAff, hrgnObst, CRGN_OR,
1925 PWO_Sibings | PWO_Ancestors |
1926 PWO_Screen | PWO_TopLevel );
1927 // shift region of obstacles and affected region back to
1928 // parent coords
1929 GpiOffsetRegion( hps, hrgnObst, (PPOINTL) &rclNew );
1930 GpiOffsetRegion( hps, hrgnAff, (PPOINTL) &rclNew );
1931 // get parent bounds (clip region or rect)
1932 HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
1933 qt_WinQueryClipRegionOrRect( parent->winId(), hrgnUpd );
1934 // add parts of old region beyond parent bounds to
1935 // region of obstacles
1936 GpiCombineRegion( hps, hrgnOld, hrgnOld, hrgnUpd, CRGN_DIFF );
1937 GpiCombineRegion( hps, hrgnObst, hrgnObst, hrgnOld, CRGN_OR );
1938 // substract region of obstacles from affected region
1939 GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnObst, CRGN_DIFF );
1940 // remember it as parent update region (need later)
1941 GpiCombineRegion( hps, hrgnUpd, hrgnAff, 0, CRGN_COPY );
1942 // copy region of obstacles to delta region and shift it by
1943 // delta (note: movement is considered to be top-left aligned)
1944 HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
1945 GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
1946 POINTL ptlDelta = { rclNew.xLeft - rclOld.xLeft,
1947 rclNew.yTop - rclOld.yTop };
1948 GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
1949 // substract region of obstacles from delta region to get
1950 // pure delta
1951 GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
1952 // calculate minimal rectangle to blit (top-left aligned)
1953 int minw = QMIN( oldSize.width(), w );
1954 int minh = QMIN( oldSize.height(), h );
1955 POINTL blitPtls [4] = {
1956 // target (new)
1957 { rclNew.xLeft, rclNew.yTop - minh },
1958 { rclNew.xLeft + minw, rclNew.yTop },
1959 // source (old)
1960 { rclOld.xLeft, rclOld.yTop - minh },
1961 };
1962 // proceed with blitting only if target and source rects differ
1963 if ( blitPtls[0].x != blitPtls[2].x ||
1964 blitPtls[0].y != blitPtls[2].y )
1965 {
1966 // Substract delta region from affected region (to minimize
1967 // flicker)
1968 GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnDelta, CRGN_DIFF );
1969 // set affected region to parent PS
1970 GpiSetClipRegion( hps, hrgnAff, NULL );
1971 // blit minimal rectangle
1972 GpiBitBlt( hps, hps, 3, blitPtls, ROP_SRCCOPY, BBO_IGNORE );
1973 GpiSetClipRegion( hps, 0, NULL );
1974 }
1975 // substract new widget region from the parent update region
1976 // and invalidate it (with underlying children)
1977 GpiCombineRegion( hps, hrgnUpd, hrgnUpd, hrgnNew, CRGN_DIFF );
1978 qt_WinInvalidateRegionEx( parent->winId(), hrgnUpd,
1979 WinQueryWindow( winId(), QW_NEXT ),
1980 HWND_BOTTOM );
1981 // intersect pure delta region with new region
1982 // (to detect areas clipped off to minimize flicker when blitting)
1983 GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnNew, CRGN_AND );
1984 // substract blitted rectangle from new region
1985 GpiSetRegion( hps, hrgnAff, 1, (PRECTL) &blitPtls );
1986 GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnAff, CRGN_DIFF );
1987 // combine the rest with intersected delta region
1988 GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnDelta, CRGN_OR );
1989 // shift the result back to widget coords and invalidate
1990 GpiOffsetRegion( hps, hrgnNew, &ptlToSelf );
1991 WinInvalidateRegion( winId(), hrgnNew, TRUE );
1992 // free resources
1993 GpiDestroyRegion( hps, hrgnDelta );
1994 GpiDestroyRegion( hps, hrgnUpd );
1995 GpiDestroyRegion( hps, hrgnObst );
1996 GpiDestroyRegion( hps, hrgnAff );
1997 }
1998 // free resources
1999 GpiDestroyRegion( hps, hrgnOld );
2000 GpiDestroyRegion( hps, hrgnNew );
2001 WinReleasePS( hps );
2002#endif
2003 }
2004 clearWState( WState_ConfigPending );
2005 }
2006
2007 if ( isVisible() ) {
2008 if ( isMove && pos() != oldPos ) {
2009 QMoveEvent e( pos(), oldPos );
2010 QApplication::sendEvent( this, &e );
2011 }
2012 if ( isResize ) {
2013 QResizeEvent e( size(), oldSize );
2014 QApplication::sendEvent( this, &e );
2015 if ( !testWFlags( WStaticContents ) )
2016 repaint( !testWFlags(WResizeNoErase) );
2017 }
2018 } else {
2019 if ( isMove && pos() != oldPos )
2020 QApplication::postEvent( this,
2021 new QMoveEvent( pos(), oldPos ) );
2022 if ( isResize )
2023 QApplication::postEvent( this,
2024 new QResizeEvent( size(), oldSize ) );
2025 }
2026}
2027
2028void QWidget::setMinimumSize( int minw, int minh )
2029{
2030#if defined(QT_CHECK_RANGE)
2031 if ( minw < 0 || minh < 0 )
2032 qWarning("QWidget::setMinimumSize: The smallest allowed size is (0,0)");
2033#endif
2034 createExtra();
2035 if ( extra->minw == minw && extra->minh == minh )
2036 return;
2037 extra->minw = minw;
2038 extra->minh = minh;
2039 if ( minw > width() || minh > height() ) {
2040 bool resized = testWState( WState_Resized );
2041 resize( QMAX(minw,width()), QMAX(minh,height()) );
2042 if ( !resized )
2043 clearWState( WState_Resized ); //not a user resize
2044 }
2045 updateGeometry();
2046}
2047
2048void QWidget::setMaximumSize( int maxw, int maxh )
2049{
2050#if defined(QT_CHECK_RANGE)
2051 if ( maxw > QWIDGETSIZE_MAX || maxh > QWIDGETSIZE_MAX ) {
2052 qWarning("QWidget::setMaximumSize: The largest allowed size is (%d,%d)",
2053 QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
2054 maxw = QMIN( maxw, QWIDGETSIZE_MAX );
2055 maxh = QMIN( maxh, QWIDGETSIZE_MAX );
2056 }
2057 if ( maxw < 0 || maxh < 0 ) {
2058 qWarning("QWidget::setMaximumSize: (%s/%s) Negative sizes (%d,%d) "
2059 "are not possible",
2060 name( "unnamed" ), className(), maxw, maxh );
2061 maxw = QMAX( maxw, 0 );
2062 maxh = QMAX( maxh, 0 );
2063 }
2064#endif
2065 createExtra();
2066 if ( extra->maxw == maxw && extra->maxh == maxh )
2067 return;
2068 extra->maxw = maxw;
2069 extra->maxh = maxh;
2070 if ( maxw < width() || maxh < height() ) {
2071 bool resized = testWState( WState_Resized );
2072 resize( QMIN(maxw,width()), QMIN(maxh,height()) );
2073 if ( !resized )
2074 clearWState( WState_Resized ); //not a user resize
2075 }
2076 updateGeometry();
2077}
2078
2079void QWidget::setSizeIncrement( int w, int h )
2080{
2081 createTLExtra();
2082 extra->topextra->incw = w;
2083 extra->topextra->inch = h;
2084}
2085
2086void QWidget::setBaseSize( int w, int h )
2087{
2088 createTLExtra();
2089 extra->topextra->basew = w;
2090 extra->topextra->baseh = h;
2091}
2092
2093extern void qt_erase_background( HPS, int, int, int, int,
2094 const QColor &, const QPixmap *, int, int, int );
2095
2096void QWidget::erase( int x, int y, int w, int h )
2097{
2098 // SIMILAR TO region ERASE BELOW
2099
2100 if ( backgroundMode()==NoBackground )
2101 return;
2102 if ( w < 0 )
2103 w = crect.width() - x;
2104 if ( h < 0 )
2105 h = crect.height() - y;
2106
2107 HPS lhps;
2108 bool tmphps;
2109
2110 if( QPainter::redirect( this ) ) {
2111 tmphps = FALSE;
2112 lhps = QPainter::redirect( this )->handle();
2113 Q_ASSERT( lhps );
2114 } else if ( !hps ) {
2115 tmphps = TRUE;
2116 lhps = getTargetPS( ClipAll );
2117 } else {
2118 tmphps = FALSE;
2119 lhps = hps;
2120 }
2121
2122 QPoint offset = backgroundOffset();
2123 int ox = offset.x();
2124 int oy = offset.y();
2125
2126 qt_erase_background(
2127 lhps, x, y, w, h, bg_col, backgroundPixmap(),
2128 ox, oy, crect.height()
2129 );
2130
2131 if ( tmphps )
2132 WinReleasePS( lhps );
2133}
2134
2135void QWidget::erase( const QRegion& rgn )
2136{
2137 // SIMILAR TO rect ERASE ABOVE
2138
2139 if ( backgroundMode()==NoBackground )
2140 return;
2141
2142 HPS lhps;
2143 bool tmphps;
2144
2145 if( QPainter::redirect( this ) ) {
2146 tmphps = FALSE;
2147 lhps = QPainter::redirect( this )->handle();
2148 Q_ASSERT( lhps );
2149 } else if ( !hps ) {
2150 tmphps = TRUE;
2151 lhps = getTargetPS( ClipAll );
2152 } else {
2153 tmphps = FALSE;
2154 lhps = hps;
2155 }
2156
2157 HRGN oldRegion = GpiQueryClipRegion( lhps );
2158 HRGN newRegion = 0;
2159 if ( oldRegion ) {
2160 GpiSetClipRegion( lhps, 0, NULL );
2161 newRegion = GpiCreateRegion( lhps, 0, NULL );
2162 GpiCombineRegion( lhps, newRegion, oldRegion, rgn.handle( height() ),
2163 CRGN_AND );
2164 } else {
2165 newRegion = rgn.handle( height() );
2166 }
2167 GpiSetClipRegion( lhps, newRegion, NULL );
2168
2169 QPoint offset = backgroundOffset();
2170 int ox = offset.x();
2171 int oy = offset.y();
2172
2173 qt_erase_background(
2174 lhps, 0, 0, crect.width(), crect.height(),
2175 bg_col, backgroundPixmap(), ox, oy, crect.height()
2176 );
2177
2178 GpiSetClipRegion( lhps, oldRegion, NULL );
2179
2180 if ( oldRegion )
2181 GpiDestroyRegion( lhps, newRegion );
2182 if ( tmphps )
2183 WinReleasePS( lhps );
2184}
2185
2186#if defined (QT_PM_NO_WIDGETMASK)
2187
2188// helper function to extract regions of all windows that overlap the given
2189// hwnd subject to their z-order (excluding children of hwnd) from the given
2190// hrgn. hps is the presentation space of hrgn.
2191void qt_WinExcludeOverlappingWindows( HWND hwnd, HPS hps, HRGN hrgn )
2192{
2193 HRGN vr = GpiCreateRegion( hps, 0, NULL );
2194 RECTL r;
2195
2196 // enumerate all windows that are on top of this hwnd
2197 HWND id = hwnd, deskId = QApplication::desktop()->winId();
2198 do {
2199 HWND i = id;
2200 while( (i = WinQueryWindow( i, QW_PREV )) ) {
2201 if ( WinIsWindowVisible( i ) ) {
2202 WinQueryWindowRect( i, &r );
2203 WinMapWindowPoints( i, hwnd, (PPOINTL) &r, 2 );
2204 GpiSetRegion( hps, vr, 1, &r );
2205 GpiCombineRegion( hps, hrgn, hrgn, vr, CRGN_DIFF );
2206 }
2207 }
2208 id = WinQueryWindow( id, QW_PARENT );
2209 } while( id != deskId );
2210
2211 GpiDestroyRegion( hps, vr );
2212}
2213
2214// helper function to scroll window contents. WinScrollWindow() is a bit
2215// buggy and corrupts update regions sometimes (which leaves some outdated
2216// areas unpainted after scrolling), so we reimplement its functionality in
2217// this function. dy and clip->yBottom/yTop should be GPI coordinates, not Qt.
2218// all clip coordinates are inclusive.
2219void qt_WinScrollWindowWell( HWND hwnd, LONG dx, LONG dy, const PRECTL clip = NULL )
2220{
2221 WinLockVisRegions( HWND_DESKTOP, TRUE );
2222
2223 HPS lhps = WinGetClipPS(
2224 hwnd, HWND_TOP,
2225 PSF_LOCKWINDOWUPDATE | PSF_CLIPSIBLINGS
2226 );
2227 if ( clip )
2228 GpiIntersectClipRectangle( lhps, clip );
2229
2230 // remember the update region and validate it. it will be shifted and
2231 // invalidated again later
2232 HRGN update = GpiCreateRegion( lhps, 0, NULL );
2233 WinQueryUpdateRegion( hwnd, update );
2234 WinValidateRegion( hwnd, update, TRUE );
2235
2236 POINTL ptls[4];
2237 RECTL &sr = *(PRECTL) &ptls[2];
2238 RECTL &tr = *(PRECTL) &ptls[0];
2239
2240 // get the source rect for scrolling
2241 GpiQueryClipBox( lhps, &sr );
2242 sr.xRight++; sr.yTop++; // inclusive -> exclusive
2243
2244 // get the visible region ignoring areas covered by children
2245 HRGN visible = GpiCreateRegion( lhps, 1, &sr );
2246 qt_WinExcludeOverlappingWindows( hwnd, lhps, visible );
2247
2248 // scroll visible region rectangles separately to avoid the flicker
2249 // that could be produced by scrolling parts of overlapping windows
2250 RGNRECT ctl;
2251 ctl.ircStart = 1;
2252 ctl.crc = 0;
2253 ctl.crcReturned = 0;
2254 if ( dx >= 0 ) {
2255 if ( dy >= 0 ) ctl.ulDirection = RECTDIR_RTLF_TOPBOT;
2256 else ctl.ulDirection = RECTDIR_RTLF_BOTTOP;
2257 } else {
2258 if ( dy >= 0 ) ctl.ulDirection = RECTDIR_LFRT_TOPBOT;
2259 else ctl.ulDirection = RECTDIR_LFRT_BOTTOP;
2260 }
2261 GpiQueryRegionRects( lhps, visible, NULL, &ctl, NULL );
2262 ctl.crc = ctl.crcReturned;
2263 int rclcnt = ctl.crcReturned;
2264 PRECTL rcls = new RECTL[rclcnt];
2265 GpiQueryRegionRects( lhps, visible, NULL, &ctl, rcls );
2266 PRECTL r = rcls;
2267 for ( int i = 0; i < rclcnt; i++, r++ ) {
2268 // source rect
2269 sr = *r;
2270 // target rect
2271 tr.xLeft = sr.xLeft + dx;
2272 tr.xRight = sr.xRight + dx;
2273 tr.yBottom = sr.yBottom + dy;
2274 tr.yTop = sr.yTop + dy;
2275 GpiBitBlt( lhps, lhps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
2276 }
2277 delete [] rcls;
2278
2279 // make the scrolled version of the visible region
2280 HRGN scrolled = GpiCreateRegion( lhps, 0, NULL );
2281 GpiCombineRegion( lhps, scrolled, visible, 0, CRGN_COPY );
2282 // invalidate the initial update region
2283 GpiCombineRegion( lhps, scrolled, scrolled, update, CRGN_DIFF );
2284 // shift the region
2285 POINTL dp = { dx, dy };
2286 GpiOffsetRegion( lhps, scrolled, &dp );
2287 // substract scrolled from visible to get invalid areas
2288 GpiCombineRegion( lhps, scrolled, visible, scrolled, CRGN_DIFF );
2289
2290 WinInvalidateRegion( hwnd, scrolled, TRUE );
2291
2292 GpiDestroyRegion( lhps, scrolled );
2293 GpiDestroyRegion( lhps, visible );
2294 GpiDestroyRegion( lhps, update );
2295
2296 WinReleasePS( lhps );
2297
2298 WinLockVisRegions( HWND_DESKTOP, FALSE );
2299
2300 WinUpdateWindow( hwnd );
2301}
2302
2303#else
2304
2305/**
2306 * \internal
2307 * Helper to scroll window contents.
2308 * All coordinates are GPI, not Qt.
2309 */
2310static void scrollWindow( HWND hwnd, int w, int h,
2311 int dx, int dy, const PRECTL clip = NULL )
2312{
2313 POINTL ptlDelta = { dx, dy };
2314
2315 POINTL ptls[4];
2316 RECTL &rclSrc = *(PRECTL) &ptls[2];
2317 RECTL &rclDst = *(PRECTL) &ptls[0];
2318
2319 if ( clip ) {
2320 rclSrc = *clip;
2321 } else {
2322 rclSrc.xLeft = rclSrc.yBottom = 0;
2323 rclSrc.xRight = w;
2324 rclSrc.yTop = h;
2325 }
2326 rclDst = rclSrc;
2327 rclDst.xLeft += dx;
2328 rclDst.xRight += dx;
2329 rclDst.yBottom += dy;
2330 rclDst.yTop += dy;
2331
2332 if ( !clip ) {
2333 // move all child widgets silently
2334 SWP swp;
2335 HWND child = WinQueryWindow( hwnd, QW_BOTTOM );
2336 if ( child != NULLHANDLE ) {
2337 for ( ; child != HWND_TOP; child = swp.hwndInsertBehind ) {
2338 WinQueryWindowPos( child, &swp );
2339 swp.x += dx;
2340 swp.y += dy;
2341 WinSetWindowPos( child, 0, swp.x, swp.y, 0, 0,
2342 SWP_MOVE | SWP_NOADJUST | SWP_NOREDRAW );
2343 // WinSetWindowPos() doesn't send WM_MOVE to windows w/o
2344 // CS_MOVENOTIFY, but having this style for non-toplevel
2345 // widgets is unwanted, so we send them WM_MOVE manually
2346 // to let their geometry to be properly updated by
2347 // QETWidget::translateConfigEvent().
2348 WinSendMsg( child, WM_MOVE, 0, 0 );
2349 }
2350 }
2351 }
2352
2353 WinLockVisRegions( HWND_DESKTOP, TRUE );
2354
2355 HPS hps = WinGetPS( hwnd );
2356
2357 // get the current update (invalid) region
2358 HRGN hrgnInv = GpiCreateRegion( hps, 0, NULL );
2359 if ( WinQueryUpdateRegion( hwnd, hrgnInv ) != RGN_NULL ) {
2360 // validate it (since it's no more up-to-date after scrolling)
2361 WinValidateRegion( hwnd, hrgnInv, clip == NULL );
2362 // scroll it to get the new invalid region
2363 GpiOffsetRegion( hps, hrgnInv, &ptlDelta );
2364 }
2365
2366 // get widget bounds (clip region or rect)
2367 HRGN hrgnClip = GpiCreateRegion( hps, 0, NULL );
2368 qt_WinQueryClipRegionOrRect( hwnd, hrgnClip );
2369
2370 if ( clip ) {
2371 // intersect it with the given clip rect
2372 HRGN hrgn = GpiCreateRegion( hps, 1, clip );
2373 GpiCombineRegion( hps, hrgnClip, hrgn, hrgnClip, CRGN_AND );
2374 GpiDestroyRegion( hps, hrgn );
2375 }
2376
2377 // compose a region uncovered after scrolling
2378 HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
2379 GpiCombineRegion( hps, hrgnUpd, hrgnClip, 0, CRGN_COPY );
2380 GpiOffsetRegion( hps, hrgnUpd, &ptlDelta );
2381 GpiCombineRegion( hps, hrgnUpd, hrgnClip, hrgnUpd, CRGN_DIFF );
2382
2383 int pwoFlags = PWO_Ancestors | PWO_Sibings | PWO_TopLevel | PWO_Screen;
2384 if ( clip )
2385 pwoFlags |= PWO_Children;
2386
2387 // get the region of obstacles
2388 HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
2389 qt_WinProcessWindowObstacles( hwnd, &rclSrc, hrgnObst, CRGN_OR, pwoFlags );
2390 // create the delta region of obstacles
2391 HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
2392 GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
2393 GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
2394 // substract the region of obstaces from the delta region to get pure delta
2395 GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
2396 // substract obstacles from the clip region
2397 GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnObst, CRGN_DIFF );
2398 // substract pure delta from the clip region (to reduce flicker)
2399 GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnDelta, CRGN_DIFF );
2400 // substract the new invalid region from the clip region (to reduce flicker)
2401 GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnInv, CRGN_DIFF );
2402
2403 // scroll the area
2404 GpiSetClipRegion( hps, hrgnClip, NULL );
2405 GpiBitBlt( hps, hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
2406 GpiSetClipRegion( hps, 0, NULL );
2407
2408 // invalidate the delta region (clipped off when blitting)
2409 WinInvalidateRegion( hwnd, hrgnDelta, clip == NULL );
2410
2411 // invalidate the region uncovered after scrolling
2412 WinInvalidateRegion( hwnd, hrgnUpd, clip == NULL );
2413
2414 // put the new invalid region back
2415 WinInvalidateRegion( hwnd, hrgnInv, clip == NULL );
2416
2417 GpiDestroyRegion( hps, hrgnInv );
2418 GpiDestroyRegion( hps, hrgnDelta );
2419 GpiDestroyRegion( hps, hrgnObst );
2420 GpiDestroyRegion( hps, hrgnUpd );
2421 GpiDestroyRegion( hps, hrgnClip );
2422 WinReleasePS( hps );
2423
2424 WinLockVisRegions( HWND_DESKTOP, FALSE );
2425
2426 WinUpdateWindow( hwnd );
2427}
2428
2429#endif
2430
2431void QWidget::scroll( int dx, int dy )
2432{
2433 if ( testWState( WState_BlockUpdates ) && !children() )
2434 return;
2435
2436#if defined (QT_PM_NO_WIDGETMASK)
2437
2438 // move non-toplevel children
2439 if ( children() ) {
2440 QObjectListIt it(*children());
2441 register QObject *obj;
2442 int h = crect.height();
2443 while ( (obj=it.current()) ) {
2444 ++it;
2445 if ( obj->isWidgetType() ) {
2446 QWidget *w = (QWidget*)obj;
2447 if ( !w->isTopLevel() ) {
2448 WinSetWindowPos(
2449 w->winId(), 0,
2450 w->crect.left() + dx,
2451 // flip y coordinate
2452 h - (w->crect.bottom() + dy + 1),
2453 0, 0,
2454 SWP_MOVE | SWP_NOADJUST | SWP_NOREDRAW
2455 );
2456 // WinSetWindowPos() doesn't send WM_MOVE to windows w/o
2457 // CS_MOVENOTIFY, but having this style for non-toplevel
2458 // widgets is unwanted, so we send them WM_MOVE manually
2459 // to let their geometry to be properly updated by
2460 // QETWidget::translateConfigEvent().
2461 WinSendMsg( w->winId(), WM_MOVE, 0, 0 );
2462 }
2463 }
2464 }
2465 }
2466
2467 qt_WinScrollWindowWell( winId(), dx, -dy, NULL );
2468
2469#else
2470
2471 scrollWindow( winId(), width(), height(), dx, -dy, NULL );
2472
2473#endif
2474}
2475
2476void QWidget::scroll( int dx, int dy, const QRect& r )
2477{
2478 if ( testWState( WState_BlockUpdates ) )
2479 return;
2480
2481#if defined (QT_PM_NO_WIDGETMASK)
2482
2483 int h = crect.height();
2484 // flip y coordinate (all coordinates are inclusive)
2485 RECTL rcl = { r.left(), h - (r.bottom() + 1), r.right(), h - (r.top() + 1) };
2486 qt_WinScrollWindowWell( winId(), dx, -dy, &rcl );
2487
2488#else
2489
2490 int h = crect.height();
2491 // flip y coordinate
2492 RECTL rcl = { r.left(), h - (r.bottom() + 1),
2493 r.right() + 1, h - r.top() };
2494 scrollWindow( winId(), width(), height(), dx, -dy, &rcl );
2495
2496#endif
2497}
2498
2499void QWidget::drawText( int x, int y, const QString &str )
2500{
2501 if ( testWState(WState_Visible) ) {
2502 QPainter paint;
2503 paint.begin( this );
2504 paint.drawText( x, y, str );
2505 paint.end();
2506 }
2507}
2508
2509
2510int QWidget::metric( int m ) const
2511{
2512 LONG val;
2513 if ( m == QPaintDeviceMetrics::PdmWidth ) {
2514 val = crect.width();
2515 } else if ( m == QPaintDeviceMetrics::PdmHeight ) {
2516 val = crect.height();
2517 } else {
2518 HDC hdc = GpiQueryDevice( qt_display_ps() );
2519 switch ( m ) {
2520 case QPaintDeviceMetrics::PdmDpiX:
2521 case QPaintDeviceMetrics::PdmPhysicalDpiX:
2522 DevQueryCaps( hdc, CAPS_HORIZONTAL_FONT_RES, 1, &val );
2523 break;
2524 case QPaintDeviceMetrics::PdmDpiY:
2525 case QPaintDeviceMetrics::PdmPhysicalDpiY:
2526 DevQueryCaps( hdc, CAPS_VERTICAL_FONT_RES, 1, &val );
2527 break;
2528 case QPaintDeviceMetrics::PdmWidthMM:
2529 DevQueryCaps( hdc, CAPS_HORIZONTAL_RESOLUTION, 1, &val );
2530 val = width() * 1000 / val;
2531 break;
2532 case QPaintDeviceMetrics::PdmHeightMM:
2533 DevQueryCaps( hdc, CAPS_VERTICAL_RESOLUTION, 1, &val );
2534 val = width() * 1000 / val;
2535 break;
2536 case QPaintDeviceMetrics::PdmNumColors:
2537 DevQueryCaps( hdc, CAPS_COLORS, 1, &val );
2538 break;
2539 case QPaintDeviceMetrics::PdmDepth:
2540 LONG colorInfo [2];
2541 DevQueryCaps( hdc, CAPS_COLOR_PLANES, 2, colorInfo );
2542 val = colorInfo [0] * colorInfo [1];
2543 break;
2544 default:
2545 val = 0;
2546#if defined(QT_CHECK_RANGE)
2547 qWarning( "QWidget::metric: Invalid metric command" );
2548#endif
2549 }
2550 }
2551 return val;
2552}
2553
2554void QWidget::createSysExtra()
2555{
2556}
2557
2558void QWidget::deleteSysExtra()
2559{
2560}
2561
2562void QWidget::createTLSysExtra()
2563{
2564 extra->topextra->fId = 0;
2565 extra->topextra->swEntry = 0;
2566 extra->topextra->pmIcon = 0;
2567 extra->topextra->in_sendWindowState = 0;
2568}
2569
2570void QWidget::deleteTLSysExtra()
2571{
2572 if ( extra->topextra->pmIcon )
2573 WinDestroyPointer( extra->topextra->pmIcon );
2574 if ( extra->topextra->swEntry )
2575 WinRemoveSwitchEntry( extra->topextra->swEntry );
2576 // frame window (extra->topextra->fId) is destroyed in
2577 // destroy() if it exists
2578}
2579
2580bool QWidget::acceptDrops() const
2581{
2582 return testWState( WState_DND );
2583}
2584
2585void QWidget::setAcceptDrops( bool on )
2586{
2587 if ( testWState(WState_DND) != on ) {
2588 if ( on )
2589 setWState( WState_DND );
2590 else
2591 clearWState( WState_DND );
2592 }
2593}
2594
2595#if !defined (QT_PM_NO_WIDGETMASK)
2596
2597// helper for QWidget::setMask()
2598static void setClipRegion( HWND hwnd, int x, int y, int w, int h, HRGN hrgn,
2599 HWND parent )
2600{
2601 if ( !WinIsWindowVisible( hwnd ) ) {
2602 // if the window is hidden, no need to invalidate anything
2603 WinSetClipRegion( hwnd, hrgn );
2604 return;
2605 }
2606
2607 HPS hps = qt_display_ps();
2608 const RECTL rcl = { 0, 0, w, h };
2609
2610 // get the old bounds (clip region or rect)
2611 HRGN hrgnOld = GpiCreateRegion( hps, 0, NULL );
2612 qt_WinQueryClipRegionOrRect( hwnd, hrgnOld );
2613 // set the new clip region
2614 WinSetClipRegion( hwnd, hrgn );
2615
2616 HRGN hrgnUpd;
2617 if ( hrgn != 0 ) {
2618 hrgnUpd = GpiCreateRegion( hps, 0, NULL );
2619 // substract the new clip region from the old one
2620 GpiCombineRegion( hps, hrgnUpd, hrgnOld, hrgn, CRGN_DIFF );
2621 // move the result to the parent coordinate space
2622 POINTL ptl = { x, y };
2623 GpiOffsetRegion( hps, hrgnUpd, &ptl );
2624 // invalidate areas in parent uncovered by the new clip region
2625 qt_WinInvalidateRegionEx( parent, hrgnUpd,
2626 WinQueryWindow( hwnd, QW_NEXT ), HWND_BOTTOM );
2627 } else {
2628 // the new region is being set to NULL, which means to widget bounds
2629 // (no need to substract new from old, because it will produce RGN_NULL)
2630 hrgnUpd = GpiCreateRegion( hps, 1, &rcl );
2631 hrgn = hrgnUpd;
2632 }
2633 // substract the old clip region from the new one
2634 GpiCombineRegion( hps, hrgnUpd, hrgn, hrgnOld, CRGN_DIFF );
2635 // invalidate areas in hwnd uncovered by the new clip region
2636 WinInvalidateRegion( hwnd, hrgnUpd, TRUE );
2637
2638 GpiDestroyRegion( hps, hrgnUpd );
2639 GpiDestroyRegion( hps, hrgnOld );
2640}
2641
2642#endif
2643
2644/*!
2645 \overload
2646
2647 Causes only the parts of the widget which overlap \a region to be
2648 visible. If the region includes pixels outside the rect() of the
2649 widget, window system controls in that area may or may not be
2650 visible, depending on the platform.
2651
2652 Note that this effect can be slow if the region is particularly
2653 complex.
2654
2655 Note that on OS/2, masks for top-level widgets are not currently
2656 supported, so setting a mask on such a widget has no effect.
2657
2658 \sa setMask(), clearMask()
2659*/
2660
2661void QWidget::setMask( const QRegion &region )
2662{
2663#if !defined (QT_PM_NO_WIDGETMASK)
2664 if (isTopLevel()) {
2665#if defined (QT_CHECK_STATE)
2666 qWarning( "QWidget::setMask() for top-level widgets "
2667 "is not implemented on OS/2" );
2668#endif
2669 return;
2670 }
2671 setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
2672 width(), height(), region.handle( height() ),
2673 parentWidget()->winId() );
2674#else
2675 Q_UNUSED( region );
2676#endif
2677}
2678
2679/*!
2680 Causes only the pixels of the widget for which \a bitmap has a
2681 corresponding 1 bit to be visible. If the region includes pixels
2682 outside the rect() of the widget, window system controls in that
2683 area may or may not be visible, depending on the platform.
2684
2685 Note that this effect can be slow if the region is particularly
2686 complex.
2687
2688 Note that on OS/2, masks for top-level widgets are not currently
2689 supported, so setting a mask on such a widget has no effect.
2690
2691 See \c examples/tux for an example of masking for transparency.
2692
2693 \sa setMask(), clearMask()
2694*/
2695
2696void QWidget::setMask( const QBitmap &bitmap )
2697{
2698#if !defined (QT_PM_NO_WIDGETMASK)
2699 if (isTopLevel()) {
2700#if defined (QT_CHECK_STATE)
2701 qWarning( "QWidget::setMask() for top-level widgets "
2702 "is not implemented on OS/2" );
2703#endif
2704 return;
2705 }
2706 QRegion rgn = QRegion( bitmap );
2707 setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
2708 width(), height(), rgn.handle( height() ),
2709 parentWidget()->winId() );
2710#else
2711 Q_UNUSED( bitmap );
2712#endif
2713}
2714
2715void QWidget::clearMask()
2716{
2717#if !defined (QT_PM_NO_WIDGETMASK)
2718 if (isTopLevel())
2719 return;
2720 setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
2721 width(), height(), 0,
2722 parentWidget()->winId() );
2723#endif
2724}
2725
2726void QWidget::setName( const char *name )
2727{
2728 QObject::setName( name );
2729}
2730
2731void QWidget::updateFrameStrut() const
2732{
2733 QWidget *that = (QWidget *) this;
2734
2735 if ( !isVisible() || isDesktop() ) {
2736 that->fstrut_dirty = isVisible();
2737 return;
2738 }
2739
2740 QTLWExtra *top = that->topData();
2741 if ( top->fId ) {
2742 // this widget has WC_FRAME
2743 SWP cswp;
2744 WinQueryWindowPos( winId(), &cswp );
2745 SWP fswp;
2746 WinQueryWindowPos( top->fId, &fswp );
2747 // flip y coordinates
2748 fswp.y = QApplication::desktop()->height() - (fswp.y + fswp.cy);
2749 cswp.y = fswp.cy - (cswp.y + cswp.cy);
2750 that->crect.setRect(
2751 fswp.x + cswp.x, fswp.y + cswp.y,
2752 cswp.cx, cswp.cy
2753 );
2754
2755 top->fleft = cswp.x;
2756 top->ftop = cswp.y;
2757 top->fright = fswp.cx - cswp.x - cswp.cx;
2758 top->fbottom = fswp.cy - cswp.y - cswp.cy;
2759 }
2760 that->fstrut_dirty = FALSE;
2761}
2762
2763void QWidget::setMouseTracking( bool enable )
2764{
2765 if ( enable )
2766 setWState( WState_MouseTracking );
2767 else
2768 clearWState( WState_MouseTracking );
2769}
2770
2771void QWidget::setWindowOpacity(double)
2772{
2773}
2774
2775double QWidget::windowOpacity() const
2776{
2777 return 1.0;
2778}
2779
2780/**
2781 * \internal
2782 * Returns the frame wihdow handle if this widget is a top-level widget and
2783 * has the standard WC_FRAME as its parent/owner (where it is FID_CLIENT).
2784 * If the widget does not have the standard frame or it is not top-level, this
2785 * function simply retuns the winId() value.
2786 */
2787WId QWidget::winFId()
2788{
2789 HWND fId = 0;
2790 if ( isTopLevel() )
2791 fId = topData()->fId;
2792 if ( !fId )
2793 fId = winId();
2794 return fId;
2795}
2796
2797#if !defined (QT_PM_NO_WIDGETMASK)
2798
2799/*!
2800 * \internal
2801 *
2802 * Validates areas of this widget covered by (intersected with) its children
2803 * and sibling widgets.
2804 *
2805 * Clip regions of all relative widgets (set by WinSetClipRegion()) are taken
2806 * into account.
2807 */
2808void QWidget::validateObstacles()
2809{
2810 RECTL updateRcl;
2811 if ( WinQueryUpdateRect( winId(), &updateRcl ) ) {
2812 // the update rectangle may be empty
2813 if ( updateRcl.xLeft != updateRcl.xRight &&
2814 updateRcl.yBottom != updateRcl.yTop ) {
2815 qt_WinProcessWindowObstacles( winId(), &updateRcl, 0, 0 );
2816 }
2817 }
2818}
2819
2820#endif // !defined (QT_PM_NO_WIDGETMASK)
2821
2822/*!
2823 * \internal
2824 *
2825 * Obtains a presentaiton space to draw on this widget, set up according
2826 * mode \a m and to widget flags.
2827 *
2828 * The returned handle must be freed using WinReleasePS() after usage.
2829 */
2830HPS QWidget::getTargetPS( ClipMode m /* = ClipDefault */ )
2831{
2832 HPS widgetPS = 0;
2833
2834 if ( isDesktop() ) {
2835 widgetPS = WinGetScreenPS( HWND_DESKTOP );
2836 return widgetPS;
2837 } else {
2838 if ( m == Unclipped || (m == ClipDefault &&
2839 testWFlags( WPaintUnclipped )) ) {
2840 widgetPS = WinGetClipPS( winId(), 0, PSF_PARENTCLIP );
2841 return widgetPS;
2842 } else {
2843 widgetPS = WinGetPS( winId() );
2844 }
2845 }
2846
2847#if !defined (QT_PM_NO_WIDGETMASK)
2848 RECTL rcl = { 0, 0, crect.width(), crect.height() };
2849 HRGN hrgn = GpiCreateRegion( widgetPS, 1, &rcl );
2850 qt_WinProcessWindowObstacles( winId(), NULL, hrgn, CRGN_DIFF );
2851 HRGN hrgnOld = 0;
2852 GpiSetClipRegion( widgetPS, hrgn, &hrgnOld );
2853 Q_ASSERT( !hrgnOld );
2854 if ( hrgnOld )
2855 GpiDestroyRegion( widgetPS, hrgnOld );
2856#endif
2857
2858 return widgetPS;
2859}
2860
Note: See TracBrowser for help on using the repository browser.