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

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

Kernel: Fixed: in !QT_PM_NO_WIDGETMASK mode, performing a very quick series of one-two line scroll operations could make parts of the scrolled areas look "stuck" (not updated in time but with some delay) on heavy load of the GUI thread.

  • Property svn:keywords set to Id
File size: 101.2 KB
Line 
1/****************************************************************************
2** $Id: qwidget_pm.cpp 135 2006-10-11 22:35:42Z 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 if ( isTopLevel() )
1345 x->pmIcon = QPixmap::createIcon( FALSE, 0, 0, &pixmap, &pixmap );
1346 }
1347
1348 if ( isTopLevel() )
1349 WinSendMsg( x->fId, WM_SETICON, MPFROMLONG( x->pmIcon ), 0 );
1350
1351 if ( oldIcon )
1352 WinDestroyPointer( oldIcon );
1353
1354 QEvent e( QEvent::IconChange );
1355 QApplication::sendEvent( this, &e );
1356}
1357
1358
1359void QWidget::setIconText( const QString &iconText )
1360{
1361 topData()->iconText = iconText;
1362}
1363
1364QCursor *qt_grab_cursor()
1365{
1366 return mouseGrbCur;
1367}
1368
1369void QWidget::grabMouse()
1370{
1371 if ( !qt_nograb() ) {
1372 if ( mouseGrb )
1373 mouseGrb->releaseMouse();
1374 WinSetCapture( HWND_DESKTOP, winFId() );
1375 mouseGrb = this;
1376 }
1377}
1378
1379void QWidget::grabMouse( const QCursor &cursor )
1380{
1381 if ( !qt_nograb() ) {
1382 if ( mouseGrb )
1383 mouseGrb->releaseMouse();
1384 WinSetCapture( HWND_DESKTOP, winFId() );
1385 mouseGrbCur = new QCursor( cursor );
1386 WinSetPointer( HWND_DESKTOP, mouseGrbCur->handle() );
1387 mouseGrb = this;
1388 }
1389}
1390
1391void QWidget::releaseMouse()
1392{
1393 if ( !qt_nograb() && mouseGrb == this ) {
1394 WinSetCapture( HWND_DESKTOP, 0 );
1395 if ( mouseGrbCur ) {
1396 delete mouseGrbCur;
1397 mouseGrbCur = 0;
1398 }
1399 mouseGrb = 0;
1400 }
1401}
1402
1403void QWidget::grabKeyboard()
1404{
1405 if ( !qt_nograb() ) {
1406 if ( keyboardGrb )
1407 keyboardGrb->releaseKeyboard();
1408 keyboardGrb = this;
1409 }
1410}
1411
1412void QWidget::releaseKeyboard()
1413{
1414 if ( !qt_nograb() && keyboardGrb == this )
1415 keyboardGrb = 0;
1416}
1417
1418
1419QWidget *QWidget::mouseGrabber()
1420{
1421 return mouseGrb;
1422}
1423
1424QWidget *QWidget::keyboardGrabber()
1425{
1426 return keyboardGrb;
1427}
1428
1429void QWidget::setActiveWindow()
1430{
1431 WinSetActiveWindow( HWND_DESKTOP, topLevelWidget()->winFId() );
1432}
1433
1434void QWidget::update()
1435{
1436 update( 0, 0, -1, -1 );
1437}
1438
1439void QWidget::update( int x, int y, int w, int h )
1440{
1441 if ( w && h &&
1442 (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
1443 if ( w < 0 )
1444 w = crect.width() - x;
1445 if ( h < 0 )
1446 h = crect.height() - y;
1447
1448 // flip y coordinate
1449 y = crect.height() - (y + h);
1450 RECTL rcl = { x, y, x + w, y + h };
1451
1452#if !defined (QT_PM_NO_WIDGETMASK)
1453 WinInvalidateRect( winId(), &rcl, FALSE );
1454#else
1455 // WinInvalidateRect() has such a "feature" that children are not
1456 // actually extracted from the window's update region when it has
1457 // the WS_CLIPCHILDREN flag, meaning that every child will anyway
1458 // receive a WM_PAINT message if its visible region intersects with
1459 // the update region of its parent, with its update region set to
1460 // that intersection. This in turn means that if we invalidate the
1461 // window completely, all its visible children wil completely repaint
1462 // themselves, what is not we want. The solution is to manually
1463 // substract children from the region we want to be updated.
1464 ULONG wstyle = WinQueryWindowULong( winId(), QWL_STYLE );
1465 if ( (wstyle & WS_CLIPCHILDREN) && children() ) {
1466 HPS lhps = hps;
1467 if ( !lhps ) lhps = qt_display_ps();
1468 HRGN hrgn = GpiCreateRegion( lhps, 1, &rcl );
1469 HRGN whrgn = GpiCreateRegion( lhps, 0, NULL );
1470 int hgt = crect.height();
1471
1472 QObjectListIt it(*children());
1473 register QObject *object;
1474 QWidget *w;
1475 while ( it ) {
1476 object = it.current();
1477 ++it;
1478 if ( object->isWidgetType() ) {
1479 w = (QWidget*)object;
1480 if ( !w->isTopLevel() && w->isShown() ) {
1481 const QRect &r = w->crect;
1482 rcl.xLeft = r.left();
1483 rcl.yBottom = hgt - (r.bottom() + 1);
1484 rcl.xRight = r.right() + 1;
1485 rcl.yTop = hgt - r.top();
1486 GpiSetRegion( lhps, whrgn, 1, &rcl );
1487 GpiCombineRegion( lhps, hrgn, hrgn, whrgn, CRGN_DIFF );
1488 }
1489 }
1490 }
1491 GpiDestroyRegion( lhps, whrgn );
1492 WinInvalidateRegion( winId(), hrgn, FALSE );
1493 GpiDestroyRegion( lhps, hrgn );
1494 } else {
1495 WinInvalidateRect( winId(), &rcl, FALSE );
1496 }
1497#endif
1498 }
1499}
1500
1501void QWidget::repaint( int x, int y, int w, int h, bool erase )
1502{
1503 if ( (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
1504#if defined (DEBUG_REPAINTRESIZE)
1505 qDebug( "repaint(): [%s/%s/%08X] %d,%d; %d,%d erase: %d resizeNoErase: %d",
1506 name(), className(), widget_flags, x, y, w, h, erase,
1507 (testWFlags( WResizeNoErase ) != 0) );
1508#endif
1509 if ( w < 0 )
1510 w = crect.width() - x;
1511 if ( h < 0 )
1512 h = crect.height() - y;
1513 QRect r( x, y, w, h );
1514 if ( r.isEmpty() )
1515 return; // nothing to do
1516
1517 // flip y coordinate
1518 int fy = crect.height() - (y + h);
1519 RECTL rcl = { x, fy, x + w, fy + h };
1520 WinValidateRect( winId(), &rcl, FALSE );
1521
1522 Q_ASSERT( !WinQueryWindowULong( winId(), QWL_QTCLIPRGN ) );
1523 QRegion reg;
1524 if ( r != rect() ) {
1525 reg = QRegion( r );
1526 WinSetWindowULong( winId(), QWL_QTCLIPRGN, (ULONG) &reg );
1527 }
1528
1529 QPaintEvent e( r, erase );
1530 if ( erase )
1531 this->erase( x, y, w, h );
1532 QApplication::sendEvent( this, &e );
1533
1534 WinSetWindowULong( winId(), QWL_QTCLIPRGN, 0 );
1535 }
1536}
1537
1538void QWidget::repaint( const QRegion& reg, bool erase )
1539{
1540 if ( (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
1541#if defined (DEBUG_REPAINTRESIZE)
1542 qDebug( "repaint(): [%s/%s/%08X] <region> erase: %d resizeNoErase: %d",
1543 name(), className(), widget_flags, erase,
1544 (testWFlags( WResizeNoErase ) != 0) );
1545#endif
1546 // convert region y coordinates from Qt to GPI (see qregion_pm.cpp)
1547 WinValidateRegion( winId(), reg.handle( height() ), FALSE );
1548
1549 Q_ASSERT( !WinQueryWindowULong( winId(), QWL_QTCLIPRGN ) );
1550 WinSetWindowULong( winId(), QWL_QTCLIPRGN, (ULONG) &reg );
1551
1552 QPaintEvent e( reg, erase );
1553 if ( erase )
1554 this->erase( reg );
1555 QApplication::sendEvent( this, &e );
1556
1557 WinSetWindowULong( winId(), QWL_QTCLIPRGN, 0 );
1558 }
1559}
1560
1561void QWidget::setWindowState( uint newstate )
1562{
1563 uint oldstate = windowState();
1564
1565 if ( newstate == oldstate )
1566 return;
1567
1568 ULONG fl = (newstate & WindowActive) ? SWP_ACTIVATE : 0;
1569
1570 /// @todo (dmik):
1571 // Ugrh. I cannot see any good logic in those weird window state
1572 // manipulations (see setWindowState() dox, original showMinimized(),
1573 // showMaximized(). showFullScreen() and showNormal() implementations).
1574 // So, treat all of three flags as exclusive for now (note: the below
1575 // code relies on this).
1576 uint op = 0;
1577 if ( newstate & WindowFullScreen ) op = WindowFullScreen;
1578 else if ( newstate & WindowMinimized ) op = WindowMinimized;
1579 else if ( newstate & WindowMaximized ) op = WindowMaximized;
1580
1581 if ( op == WindowMinimized )
1582 fl = SWP_DEACTIVATE;
1583
1584 if ( isTopLevel() && isVisible() ) {
1585 WId id = winFId();
1586 QTLWExtra *top = topData();
1587
1588 // set flag for the WM_WINDOWPOSCHANGED handler in QtFrameProc
1589 top->in_sendWindowState = 1;
1590
1591 if ( op == WindowMinimized || op == WindowMaximized ) {
1592 fl |= op == WindowMinimized ? SWP_MINIMIZE : SWP_MAXIMIZE;
1593 WinSetWindowPos( id, 0, 0, 0, 0, 0, fl );
1594 } else if ( op == WindowFullScreen ) {
1595 if ( !(oldstate & (WindowMinimized | WindowMaximized)) ) {
1596 top->normalGeometry = frameGeometry();
1597 } else {
1598 // extract normal geometry from window words
1599 USHORT x = WinQueryWindowUShort( id, QWS_XRESTORE );
1600 USHORT y = WinQueryWindowUShort( id, QWS_YRESTORE );
1601 USHORT w = WinQueryWindowUShort( id, QWS_CXRESTORE );
1602 USHORT h = WinQueryWindowUShort( id, QWS_CYRESTORE );
1603 // restore first to update the frame strut
1604 if ( oldstate & WindowMinimized )
1605 WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_RESTORE );
1606 // flip y coordinate
1607 y = QApplication::desktop()->height() - (y + h);
1608 top->normalGeometry = QRect( x, y, w, h );
1609 }
1610 QRect r = QApplication::desktop()->screenGeometry( this );
1611 r.addCoords( -top->fleft, -top->fbottom, top->fright, top->ftop );
1612 WinSetWindowPos( id, 0, r.x(), r.y(), r.width(), r.height(),
1613 fl | SWP_SIZE | SWP_MOVE );
1614 } else {
1615 if ( oldstate & WindowFullScreen ) {
1616 QRect r = top->normalGeometry;
1617 if ( r != frameGeometry() ) {
1618 r.addCoords( top->fleft, top->ftop, -top->fright, -top->fbottom );
1619 setGeometry( r );
1620 }
1621 top->normalGeometry.setWidth( 0 );
1622 } else {
1623 QRect r = top->normalGeometry;
1624 if ( r.isValid() ) {
1625 // store normal geometry in window words
1626 USHORT x = r.x();
1627 USHORT y = r.y();
1628 USHORT w = r.width();
1629 USHORT h = r.height();
1630 // flip y coordinate
1631 y = QApplication::desktop()->height() - (y + h);
1632 WinSetWindowUShort( id, QWS_XRESTORE, x );
1633 WinSetWindowUShort( id, QWS_YRESTORE, y );
1634 WinSetWindowUShort( id, QWS_CXRESTORE, w );
1635 WinSetWindowUShort( id, QWS_CYRESTORE, h );
1636 top->normalGeometry.setWidth( 0 );
1637 }
1638 WinSetWindowPos( id, 0, 0, 0, 0, 0, fl | SWP_RESTORE );
1639 }
1640 }
1641
1642 top->in_sendWindowState = 0;
1643 }
1644
1645 widget_state &= ~(WState_Minimized | WState_Maximized | WState_FullScreen);
1646 if (newstate & WindowMinimized)
1647 widget_state |= WState_Minimized;
1648 if (newstate & WindowMaximized)
1649 widget_state |= WState_Maximized;
1650 if (newstate & WindowFullScreen)
1651 widget_state |= WState_FullScreen;
1652
1653 QEvent e(QEvent::WindowStateChange);
1654 QApplication::sendEvent(this, &e);
1655}
1656
1657
1658/*
1659 \internal
1660 Platform-specific part of QWidget::hide().
1661*/
1662
1663void QWidget::hideWindow()
1664{
1665 deactivateWidgetCleanup();
1666 HWND id = winFId();
1667
1668#if defined (QT_PM_NO_WIDGETMASK)
1669 WinShowWindow( id, FALSE );
1670#else
1671 qt_WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_HIDE );
1672#endif
1673
1674 if ( isTopLevel() )
1675 WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_DEACTIVATE );
1676
1677 HSWITCH swEntry = topData()->swEntry;
1678 if ( swEntry ) {
1679 SWCNTRL swc;
1680 WinQuerySwitchEntry( swEntry, &swc );
1681 swc.uchVisibility = SWL_INVISIBLE;
1682 WinChangeSwitchEntry( swEntry, &swc );
1683 }
1684}
1685
1686
1687/*
1688 \internal
1689 Platform-specific part of QWidget::show().
1690*/
1691
1692void QWidget::showWindow()
1693{
1694#if defined (QT_PM_NO_WIDGETMASK)
1695 WinShowWindow( winFId(), TRUE );
1696#else
1697 qt_WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, SWP_SHOW );
1698#endif
1699
1700 ULONG fl = 0;
1701 if ( isTopLevel() ) {
1702 // we do this check here because setWindowState() does not actually
1703 // change the window state when the window is not visible, assuming
1704 // it will be done here.
1705 if (testWState(WState_Minimized))
1706 fl |= SWP_MINIMIZE;
1707 else if (testWState(WState_Maximized))
1708 fl |= SWP_MAXIMIZE;
1709 else if (testWState(WState_FullScreen)) {
1710 QTLWExtra *top = topData();
1711 topData()->normalGeometry = QRect( pos(), size() );
1712 QRect r = QApplication::desktop()->screenGeometry( this );
1713 r.addCoords( -top->fleft, -top->fbottom, top->fright, top->ftop );
1714 WinSetWindowPos( winFId(), 0, r.x(), r.y(), r.width(), r.height(),
1715 fl | SWP_SIZE | SWP_MOVE );
1716 }
1717
1718 if (
1719 !testWFlags(WType_Popup | WStyle_Tool) &&
1720 (!testWFlags(WType_Dialog) || !parentWidget())
1721 ) {
1722 HSWITCH &swEntry = topData()->swEntry;
1723 if ( !swEntry ) {
1724 // lazily create a new window list entry
1725 HWND id = winFId(); // frame handle, if any
1726 PID pid;
1727 WinQueryWindowProcess( id, &pid, NULL );
1728 SWCNTRL swc;
1729 memset( &swc, 0, sizeof(SWCNTRL) );
1730 swc.hwnd = id;
1731 swc.idProcess = pid;
1732 swc.uchVisibility = SWL_VISIBLE;
1733 swc.fbJump = SWL_JUMPABLE;
1734 WinQueryWindowText( id, sizeof(swc.szSwtitle), swc.szSwtitle );
1735 swEntry = WinAddSwitchEntry( &swc );
1736 } else {
1737 SWCNTRL swc;
1738 WinQuerySwitchEntry( swEntry, &swc );
1739 swc.uchVisibility = SWL_VISIBLE;
1740 WinChangeSwitchEntry( swEntry, &swc );
1741 }
1742 }
1743 }
1744 if (!testWFlags(WStyle_Tool) && !isPopup())
1745 fl |= SWP_ACTIVATE;
1746 if ( fl )
1747 WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, fl );
1748}
1749
1750void QWidget::raise()
1751{
1752 QWidget *p = parentWidget();
1753 if ( p && p->childObjects && p->childObjects->findRef(this) >= 0 )
1754 p->childObjects->append( p->childObjects->take() );
1755//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
1756// uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
1757
1758#if defined (QT_PM_NO_WIDGETMASK)
1759 WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
1760#else
1761 qt_WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
1762#endif
1763}
1764
1765void QWidget::lower()
1766{
1767 QWidget *p = parentWidget();
1768 if ( p && p->childObjects && p->childObjects->findRef(this) >= 0 )
1769 p->childObjects->insert( 0, p->childObjects->take() );
1770//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
1771// uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
1772
1773#if defined (QT_PM_NO_WIDGETMASK)
1774 WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
1775#else
1776 qt_WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
1777#endif
1778}
1779
1780void QWidget::stackUnder( QWidget* w )
1781{
1782 QWidget *p = parentWidget();
1783 if ( !w || isTopLevel() || p != w->parentWidget() || this == w )
1784 return;
1785 if ( p && p->childObjects && p->childObjects->findRef(w) >= 0 && p->childObjects->findRef(this) >= 0 ) {
1786 p->childObjects->take();
1787 p->childObjects->insert( p->childObjects->findRef(w), this );
1788 }
1789#if defined (QT_PM_NO_WIDGETMASK)
1790 WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
1791#else
1792 qt_WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
1793#endif
1794}
1795
1796//
1797// The internal qPMRequestConfig, defined in qeventloop_pm.cpp, stores move,
1798// resize and setGeometry requests for a widget that is already
1799// processing a config event. The purpose is to avoid recursion.
1800//
1801void qPMRequestConfig( WId, int, int, int, int, int );
1802
1803void QWidget::internalSetGeometry( int x, int y, int w, int h, bool isMove )
1804{
1805 if ( extra ) { // any size restrictions?
1806 w = QMIN(w,extra->maxw);
1807 h = QMIN(h,extra->maxh);
1808 w = QMAX(w,extra->minw);
1809 h = QMAX(h,extra->minh);
1810 }
1811 if ( w < 1 ) // invalid size
1812 w = 1;
1813 if ( h < 1 )
1814 h = 1;
1815 QSize oldSize( size() );
1816 QPoint oldPos( pos() );
1817 if ( !isTopLevel() )
1818 isMove = (crect.topLeft() != QPoint( x, y ));
1819 bool isResize = w != oldSize.width() || h != oldSize.height();
1820 if ( isMove == FALSE && isResize == FALSE )
1821 return;
1822 clearWState(WState_Maximized);
1823 clearWState(WState_FullScreen);
1824 if ( testWState(WState_ConfigPending) ) { // processing config event
1825 qPMRequestConfig( winId(), isMove ? 2 : 1, x, y, w, h );
1826 } else {
1827 setWState( WState_ConfigPending );
1828 if ( isTopLevel() ) {
1829/// @todo (dmik) optimize: use extra->topextra directly (after updating fstrut
1830// if necessary) instead of calling frameGeometry()
1831 QRect fr( frameGeometry() );
1832 int fx = fr.left() + x - crect.left();
1833 int fy = fr.top() + y - crect.top();
1834 int fw = fr.width() + w - crect.width();
1835 int fh = fr.height() + h - crect.height();
1836 // flip y coordinate
1837 fy = QApplication::desktop()->height() - (fy + fh);
1838 crect.setRect( x, y, w, h );
1839 WinSetWindowPos( winFId(), 0, fx, fy, fw, fh, SWP_MOVE | SWP_SIZE );
1840 } else {
1841#if defined (QT_PM_NO_WIDGETMASK)
1842 // flip y coordinate
1843 int fy = parentWidget()->height() - (y + h);
1844 crect.setRect( x, y, w, h );
1845 WinSetWindowPos( winId(), 0, x, fy, w, h, SWP_MOVE | SWP_SIZE );
1846#else
1847 // When WS_CLIPCHILDREN and WS_CLIPSIBLINGS are not used,
1848 // WinSetWindowPos() does not correctly update involved windows.
1849 // The fix is to do it ourselves, taking clip regions into account.
1850
1851 QWidget *parent = parentWidget();
1852 const int ph = parent->height();
1853 // flip y coordinate
1854 int fy = ph - (y + h);
1855 // set new and old rectangles
1856 const RECTL rcls [2] = {
1857 // new (y flipped, relative to parent)
1858 { x, fy, x + w, fy + h },
1859 // old (y flipped, relative to parent)
1860 { crect.left(), ph - (crect.bottom() + 1),
1861 crect.right() + 1, ph - crect.top() }
1862 };
1863 const RECTL &rclNew = rcls [0];
1864 const RECTL &rclOld = rcls [1];
1865 // delta to shift coordinate space from parent to this widget
1866 POINTL ptlToSelf = { -x, -fy };
1867 // update crect and move the widget w/o redrawing
1868 crect.setRect( x, y, w, h );
1869 WinSetWindowPos( winId(), 0, x, fy, w, h,
1870 SWP_MOVE | SWP_SIZE | SWP_NOREDRAW );
1871 // use parent PS for blitting
1872 HPS hps = WinGetPS( parent->winId() );
1873 // get old and new clip regions (relative to parent)
1874 HRGN hrgnOld = GpiCreateRegion( hps, 1, &rclOld );
1875 HRGN hrgnNew = GpiCreateRegion( hps, 1, &rclNew );
1876 if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
1877 HRGN hrgnTemp = GpiCreateRegion( hps, 0, NULL );
1878 // old (clipped to the old rect)
1879 WinQueryClipRegion( winId(), hrgnTemp );
1880 GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclOld );
1881 GpiCombineRegion( hps, hrgnOld, hrgnTemp, hrgnOld, CRGN_AND );
1882 // new (clipped to the new rect)
1883 WinQueryClipRegion( winId(), hrgnTemp );
1884 if ( oldSize.height() != h ) {
1885 // keep the clip region top-left aligned by adding the
1886 // height delta (new size - old size)
1887 POINTL ptl = { 0, h - oldSize.height() };
1888 GpiOffsetRegion( hps, hrgnTemp, &ptl );
1889 WinSetClipRegion( winId(), hrgnTemp );
1890 }
1891 GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclNew );
1892 GpiCombineRegion( hps, hrgnNew, hrgnTemp, hrgnNew, CRGN_AND );
1893 GpiDestroyRegion( hps, hrgnTemp );
1894 }
1895 // the rest is useful only when the widget is visible
1896 if ( isVisible() ) {
1897 // create affected region (old + new, relative to widget)
1898 HRGN hrgnAff = GpiCreateRegion( hps, 0, NULL );
1899 GpiCombineRegion( hps, hrgnAff, hrgnOld, hrgnNew, CRGN_OR );
1900 GpiOffsetRegion( hps, hrgnAff, &ptlToSelf );
1901 // get bounding rectangle of affected region
1902 RECTL rclAff;
1903 GpiQueryRegionBox( hps, hrgnAff, &rclAff );
1904 // get region of obstacles limited to affected rectangle
1905 HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
1906 qt_WinProcessWindowObstacles( winId(), &rclAff, hrgnObst, CRGN_OR,
1907 PWO_Sibings | PWO_Ancestors |
1908 PWO_Screen | PWO_TopLevel );
1909 // shift region of obstacles and affected region back to
1910 // parent coords
1911 GpiOffsetRegion( hps, hrgnObst, (PPOINTL) &rclNew );
1912 GpiOffsetRegion( hps, hrgnAff, (PPOINTL) &rclNew );
1913 // get parent bounds (clip region or rect)
1914 HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
1915 qt_WinQueryClipRegionOrRect( parent->winId(), hrgnUpd );
1916 // add parts of old region beyond parent bounds to
1917 // region of obstacles
1918 GpiCombineRegion( hps, hrgnOld, hrgnOld, hrgnUpd, CRGN_DIFF );
1919 GpiCombineRegion( hps, hrgnObst, hrgnObst, hrgnOld, CRGN_OR );
1920 // substract region of obstacles from affected region
1921 GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnObst, CRGN_DIFF );
1922 // remember it as parent update region (need later)
1923 GpiCombineRegion( hps, hrgnUpd, hrgnAff, 0, CRGN_COPY );
1924 // copy region of obstacles to delta region and shift it by
1925 // delta (note: movement is considered to be top-left aligned)
1926 HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
1927 GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
1928 POINTL ptlDelta = { rclNew.xLeft - rclOld.xLeft,
1929 rclNew.yTop - rclOld.yTop };
1930 GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
1931 // substract region of obstacles from delta region to get
1932 // pure delta
1933 GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
1934 // calculate minimal rectangle to blit (top-left aligned)
1935 int minw = QMIN( oldSize.width(), w );
1936 int minh = QMIN( oldSize.height(), h );
1937 POINTL blitPtls [4] = {
1938 // target (new)
1939 { rclNew.xLeft, rclNew.yTop - minh },
1940 { rclNew.xLeft + minw, rclNew.yTop },
1941 // source (old)
1942 { rclOld.xLeft, rclOld.yTop - minh },
1943 };
1944 // proceed with blitting only if target and source rects differ
1945 if ( blitPtls[0].x != blitPtls[2].x ||
1946 blitPtls[0].y != blitPtls[2].y )
1947 {
1948 // Substract delta region from affected region (to minimize
1949 // flicker)
1950 GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnDelta, CRGN_DIFF );
1951 // set affected region to parent PS
1952 GpiSetClipRegion( hps, hrgnAff, NULL );
1953 // blit minimal rectangle
1954 GpiBitBlt( hps, hps, 3, blitPtls, ROP_SRCCOPY, BBO_IGNORE );
1955 GpiSetClipRegion( hps, 0, NULL );
1956 }
1957 // substract new widget region from the parent update region
1958 // and invalidate it (with underlying children)
1959 GpiCombineRegion( hps, hrgnUpd, hrgnUpd, hrgnNew, CRGN_DIFF );
1960 qt_WinInvalidateRegionEx( parent->winId(), hrgnUpd,
1961 WinQueryWindow( winId(), QW_NEXT ),
1962 HWND_BOTTOM );
1963 // intersect pure delta region with new region
1964 // (to detect areas clipped off to minimize flicker when blitting)
1965 GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnNew, CRGN_AND );
1966 // substract blitted rectangle from new region
1967 GpiSetRegion( hps, hrgnAff, 1, (PRECTL) &blitPtls );
1968 GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnAff, CRGN_DIFF );
1969 // combine the rest with intersected delta region
1970 GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnDelta, CRGN_OR );
1971 // shift the result back to widget coords and invalidate
1972 GpiOffsetRegion( hps, hrgnNew, &ptlToSelf );
1973 WinInvalidateRegion( winId(), hrgnNew, TRUE );
1974 // free resources
1975 GpiDestroyRegion( hps, hrgnDelta );
1976 GpiDestroyRegion( hps, hrgnUpd );
1977 GpiDestroyRegion( hps, hrgnObst );
1978 GpiDestroyRegion( hps, hrgnAff );
1979 }
1980 // free resources
1981 GpiDestroyRegion( hps, hrgnOld );
1982 GpiDestroyRegion( hps, hrgnNew );
1983 WinReleasePS( hps );
1984#endif
1985 }
1986 clearWState( WState_ConfigPending );
1987 }
1988
1989 if ( isVisible() ) {
1990 if ( isMove && pos() != oldPos ) {
1991 QMoveEvent e( pos(), oldPos );
1992 QApplication::sendEvent( this, &e );
1993 }
1994 if ( isResize ) {
1995 QResizeEvent e( size(), oldSize );
1996 QApplication::sendEvent( this, &e );
1997 if ( !testWFlags( WStaticContents ) )
1998 repaint( !testWFlags(WResizeNoErase) );
1999 }
2000 } else {
2001 if ( isMove && pos() != oldPos )
2002 QApplication::postEvent( this,
2003 new QMoveEvent( pos(), oldPos ) );
2004 if ( isResize )
2005 QApplication::postEvent( this,
2006 new QResizeEvent( size(), oldSize ) );
2007 }
2008}
2009
2010void QWidget::setMinimumSize( int minw, int minh )
2011{
2012#if defined(QT_CHECK_RANGE)
2013 if ( minw < 0 || minh < 0 )
2014 qWarning("QWidget::setMinimumSize: The smallest allowed size is (0,0)");
2015#endif
2016 createExtra();
2017 if ( extra->minw == minw && extra->minh == minh )
2018 return;
2019 extra->minw = minw;
2020 extra->minh = minh;
2021 if ( minw > width() || minh > height() ) {
2022 bool resized = testWState( WState_Resized );
2023 resize( QMAX(minw,width()), QMAX(minh,height()) );
2024 if ( !resized )
2025 clearWState( WState_Resized ); //not a user resize
2026 }
2027 updateGeometry();
2028}
2029
2030void QWidget::setMaximumSize( int maxw, int maxh )
2031{
2032#if defined(QT_CHECK_RANGE)
2033 if ( maxw > QWIDGETSIZE_MAX || maxh > QWIDGETSIZE_MAX ) {
2034 qWarning("QWidget::setMaximumSize: The largest allowed size is (%d,%d)",
2035 QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
2036 maxw = QMIN( maxw, QWIDGETSIZE_MAX );
2037 maxh = QMIN( maxh, QWIDGETSIZE_MAX );
2038 }
2039 if ( maxw < 0 || maxh < 0 ) {
2040 qWarning("QWidget::setMaximumSize: (%s/%s) Negative sizes (%d,%d) "
2041 "are not possible",
2042 name( "unnamed" ), className(), maxw, maxh );
2043 maxw = QMAX( maxw, 0 );
2044 maxh = QMAX( maxh, 0 );
2045 }
2046#endif
2047 createExtra();
2048 if ( extra->maxw == maxw && extra->maxh == maxh )
2049 return;
2050 extra->maxw = maxw;
2051 extra->maxh = maxh;
2052 if ( maxw < width() || maxh < height() ) {
2053 bool resized = testWState( WState_Resized );
2054 resize( QMIN(maxw,width()), QMIN(maxh,height()) );
2055 if ( !resized )
2056 clearWState( WState_Resized ); //not a user resize
2057 }
2058 updateGeometry();
2059}
2060
2061void QWidget::setSizeIncrement( int w, int h )
2062{
2063 createTLExtra();
2064 extra->topextra->incw = w;
2065 extra->topextra->inch = h;
2066}
2067
2068void QWidget::setBaseSize( int w, int h )
2069{
2070 createTLExtra();
2071 extra->topextra->basew = w;
2072 extra->topextra->baseh = h;
2073}
2074
2075extern void qt_erase_background( HPS, int, int, int, int,
2076 const QColor &, const QPixmap *, int, int, int );
2077
2078void QWidget::erase( int x, int y, int w, int h )
2079{
2080 // SIMILAR TO region ERASE BELOW
2081
2082 if ( backgroundMode()==NoBackground )
2083 return;
2084 if ( w < 0 )
2085 w = crect.width() - x;
2086 if ( h < 0 )
2087 h = crect.height() - y;
2088
2089 HPS lhps;
2090 bool tmphps;
2091
2092 if( QPainter::redirect( this ) ) {
2093 tmphps = FALSE;
2094 lhps = QPainter::redirect( this )->handle();
2095 Q_ASSERT( lhps );
2096 } else if ( !hps ) {
2097 tmphps = TRUE;
2098 lhps = getTargetPS( ClipAll );
2099 } else {
2100 tmphps = FALSE;
2101 lhps = hps;
2102 }
2103
2104 QPoint offset = backgroundOffset();
2105 int ox = offset.x();
2106 int oy = offset.y();
2107
2108 qt_erase_background(
2109 lhps, x, y, w, h, bg_col, backgroundPixmap(),
2110 ox, oy, crect.height()
2111 );
2112
2113 if ( tmphps )
2114 WinReleasePS( lhps );
2115}
2116
2117void QWidget::erase( const QRegion& rgn )
2118{
2119 // SIMILAR TO rect ERASE ABOVE
2120
2121 if ( backgroundMode()==NoBackground )
2122 return;
2123
2124 HPS lhps;
2125 bool tmphps;
2126
2127 if( QPainter::redirect( this ) ) {
2128 tmphps = FALSE;
2129 lhps = QPainter::redirect( this )->handle();
2130 Q_ASSERT( lhps );
2131 } else if ( !hps ) {
2132 tmphps = TRUE;
2133 lhps = getTargetPS( ClipAll );
2134 } else {
2135 tmphps = FALSE;
2136 lhps = hps;
2137 }
2138
2139 HRGN oldRegion = GpiQueryClipRegion( lhps );
2140 HRGN newRegion = 0;
2141 if ( oldRegion ) {
2142 GpiSetClipRegion( lhps, 0, NULL );
2143 newRegion = GpiCreateRegion( lhps, 0, NULL );
2144 GpiCombineRegion( lhps, newRegion, oldRegion, rgn.handle( height() ),
2145 CRGN_AND );
2146 } else {
2147 newRegion = rgn.handle( height() );
2148 }
2149 GpiSetClipRegion( lhps, newRegion, NULL );
2150
2151 QPoint offset = backgroundOffset();
2152 int ox = offset.x();
2153 int oy = offset.y();
2154
2155 qt_erase_background(
2156 lhps, 0, 0, crect.width(), crect.height(),
2157 bg_col, backgroundPixmap(), ox, oy, crect.height()
2158 );
2159
2160 GpiSetClipRegion( lhps, oldRegion, NULL );
2161
2162 if ( oldRegion )
2163 GpiDestroyRegion( lhps, newRegion );
2164 if ( tmphps )
2165 WinReleasePS( lhps );
2166}
2167
2168#if defined (QT_PM_NO_WIDGETMASK)
2169
2170// helper function to extract regions of all windows that overlap the given
2171// hwnd subject to their z-order (excluding children of hwnd) from the given
2172// hrgn. hps is the presentation space of hrgn.
2173void qt_WinExcludeOverlappingWindows( HWND hwnd, HPS hps, HRGN hrgn )
2174{
2175 HRGN vr = GpiCreateRegion( hps, 0, NULL );
2176 RECTL r;
2177
2178 // enumerate all windows that are on top of this hwnd
2179 HWND id = hwnd, deskId = QApplication::desktop()->winId();
2180 do {
2181 HWND i = id;
2182 while( (i = WinQueryWindow( i, QW_PREV )) ) {
2183 if ( WinIsWindowVisible( i ) ) {
2184 WinQueryWindowRect( i, &r );
2185 WinMapWindowPoints( i, hwnd, (PPOINTL) &r, 2 );
2186 GpiSetRegion( hps, vr, 1, &r );
2187 GpiCombineRegion( hps, hrgn, hrgn, vr, CRGN_DIFF );
2188 }
2189 }
2190 id = WinQueryWindow( id, QW_PARENT );
2191 } while( id != deskId );
2192
2193 GpiDestroyRegion( hps, vr );
2194}
2195
2196// helper function to scroll window contents. WinScrollWindow() is a bit
2197// buggy and corrupts update regions sometimes (which leaves some outdated
2198// areas unpainted after scrolling), so we reimplement its functionality in
2199// this function. dy and clip->yBottom/yTop should be GPI coordinates, not Qt.
2200// all clip coordinates are inclusive.
2201void qt_WinScrollWindowWell( HWND hwnd, LONG dx, LONG dy, const PRECTL clip = NULL )
2202{
2203 WinLockVisRegions( HWND_DESKTOP, TRUE );
2204
2205 HPS lhps = WinGetClipPS(
2206 hwnd, HWND_TOP,
2207 PSF_LOCKWINDOWUPDATE | PSF_CLIPSIBLINGS
2208 );
2209 if ( clip )
2210 GpiIntersectClipRectangle( lhps, clip );
2211
2212 // remember the update region and validate it. it will be shifted and
2213 // invalidated again later
2214 HRGN update = GpiCreateRegion( lhps, 0, NULL );
2215 WinQueryUpdateRegion( hwnd, update );
2216 WinValidateRegion( hwnd, update, TRUE );
2217
2218 POINTL ptls[4];
2219 RECTL &sr = *(PRECTL) &ptls[2];
2220 RECTL &tr = *(PRECTL) &ptls[0];
2221
2222 // get the source rect for scrolling
2223 GpiQueryClipBox( lhps, &sr );
2224 sr.xRight++; sr.yTop++; // inclusive -> exclusive
2225
2226 // get the visible region ignoring areas covered by children
2227 HRGN visible = GpiCreateRegion( lhps, 1, &sr );
2228 qt_WinExcludeOverlappingWindows( hwnd, lhps, visible );
2229
2230 // scroll visible region rectangles separately to avoid the flicker
2231 // that could be produced by scrolling parts of overlapping windows
2232 RGNRECT ctl;
2233 ctl.ircStart = 1;
2234 ctl.crc = 0;
2235 ctl.crcReturned = 0;
2236 if ( dx >= 0 ) {
2237 if ( dy >= 0 ) ctl.ulDirection = RECTDIR_RTLF_TOPBOT;
2238 else ctl.ulDirection = RECTDIR_RTLF_BOTTOP;
2239 } else {
2240 if ( dy >= 0 ) ctl.ulDirection = RECTDIR_LFRT_TOPBOT;
2241 else ctl.ulDirection = RECTDIR_LFRT_BOTTOP;
2242 }
2243 GpiQueryRegionRects( lhps, visible, NULL, &ctl, NULL );
2244 ctl.crc = ctl.crcReturned;
2245 int rclcnt = ctl.crcReturned;
2246 PRECTL rcls = new RECTL[rclcnt];
2247 GpiQueryRegionRects( lhps, visible, NULL, &ctl, rcls );
2248 PRECTL r = rcls;
2249 for ( int i = 0; i < rclcnt; i++, r++ ) {
2250 // source rect
2251 sr = *r;
2252 // target rect
2253 tr.xLeft = sr.xLeft + dx;
2254 tr.xRight = sr.xRight + dx;
2255 tr.yBottom = sr.yBottom + dy;
2256 tr.yTop = sr.yTop + dy;
2257 GpiBitBlt( lhps, lhps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
2258 }
2259 delete [] rcls;
2260
2261 // make the scrolled version of the visible region
2262 HRGN scrolled = GpiCreateRegion( lhps, 0, NULL );
2263 GpiCombineRegion( lhps, scrolled, visible, 0, CRGN_COPY );
2264 // invalidate the initial update region
2265 GpiCombineRegion( lhps, scrolled, scrolled, update, CRGN_DIFF );
2266 // shift the region
2267 POINTL dp = { dx, dy };
2268 GpiOffsetRegion( lhps, scrolled, &dp );
2269 // substract scrolled from visible to get invalid areas
2270 GpiCombineRegion( lhps, scrolled, visible, scrolled, CRGN_DIFF );
2271
2272 WinInvalidateRegion( hwnd, scrolled, TRUE );
2273
2274 GpiDestroyRegion( lhps, scrolled );
2275 GpiDestroyRegion( lhps, visible );
2276 GpiDestroyRegion( lhps, update );
2277
2278 WinReleasePS( lhps );
2279
2280 WinLockVisRegions( HWND_DESKTOP, FALSE );
2281
2282 WinUpdateWindow( hwnd );
2283}
2284
2285#else
2286
2287/**
2288 * \internal
2289 * Helper to scroll window contents.
2290 * All coordinates are GPI, not Qt.
2291 */
2292static void scrollWindow( HWND hwnd, int w, int h,
2293 int dx, int dy, const PRECTL clip = NULL )
2294{
2295 POINTL ptlDelta = { dx, dy };
2296
2297 POINTL ptls[4];
2298 RECTL &rclSrc = *(PRECTL) &ptls[2];
2299 RECTL &rclDst = *(PRECTL) &ptls[0];
2300
2301 if ( clip ) {
2302 rclSrc = *clip;
2303 } else {
2304 rclSrc.xLeft = rclSrc.yBottom = 0;
2305 rclSrc.xRight = w;
2306 rclSrc.yTop = h;
2307 }
2308 rclDst = rclSrc;
2309 rclDst.xLeft += dx;
2310 rclDst.xRight += dx;
2311 rclDst.yBottom += dy;
2312 rclDst.yTop += dy;
2313
2314 if ( !clip ) {
2315 // move all child widgets silently
2316 SWP swp;
2317 HWND child = WinQueryWindow( hwnd, QW_BOTTOM );
2318 if ( child != NULLHANDLE ) {
2319 for ( ; child != HWND_TOP; child = swp.hwndInsertBehind ) {
2320 WinQueryWindowPos( child, &swp );
2321 swp.x += dx;
2322 swp.y += dy;
2323 WinSetWindowPos( child, 0, swp.x, swp.y, 0, 0,
2324 SWP_MOVE | SWP_NOADJUST | SWP_NOREDRAW );
2325 // WinSetWindowPos() doesn't send WM_MOVE to windows w/o
2326 // CS_MOVENOTIFY, but having this style for non-toplevel
2327 // widgets is unwanted, so we send them WM_MOVE manually
2328 // to let their geometry to be properly updated by
2329 // QETWidget::translateConfigEvent().
2330 WinSendMsg( child, WM_MOVE, 0, 0 );
2331 }
2332 }
2333 }
2334
2335 HPS hps = WinGetPS( hwnd );
2336
2337 // get the current update (invalid) region
2338 HRGN hrgnInv = GpiCreateRegion( hps, 0, NULL );
2339 if ( WinQueryUpdateRegion( hwnd, hrgnInv ) != RGN_NULL ) {
2340 // validate it (since it's no more up-to-date after scrolling)
2341 WinValidateRegion( hwnd, hrgnInv, clip == NULL );
2342 // scroll it to get the new invalid region
2343 GpiOffsetRegion( hps, hrgnInv, &ptlDelta );
2344 }
2345
2346 // get widget bounds (clip region or rect)
2347 HRGN hrgnClip = GpiCreateRegion( hps, 0, NULL );
2348 qt_WinQueryClipRegionOrRect( hwnd, hrgnClip );
2349
2350 if ( clip ) {
2351 // intersect it with the given clip rect
2352 HRGN hrgn = GpiCreateRegion( hps, 1, clip );
2353 GpiCombineRegion( hps, hrgnClip, hrgn, hrgnClip, CRGN_AND );
2354 GpiDestroyRegion( hps, hrgn );
2355 }
2356
2357 // compose a region uncovered after scrolling
2358 HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
2359 GpiCombineRegion( hps, hrgnUpd, hrgnClip, 0, CRGN_COPY );
2360 GpiOffsetRegion( hps, hrgnUpd, &ptlDelta );
2361 GpiCombineRegion( hps, hrgnUpd, hrgnClip, hrgnUpd, CRGN_DIFF );
2362
2363 int pwoFlags = PWO_Ancestors | PWO_Sibings | PWO_TopLevel | PWO_Screen;
2364 if ( clip )
2365 pwoFlags |= PWO_Children;
2366
2367 // get the region of obstacles
2368 HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
2369 qt_WinProcessWindowObstacles( hwnd, &rclSrc, hrgnObst, CRGN_OR, pwoFlags );
2370 // create the delta region of obstacles
2371 HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
2372 GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
2373 GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
2374 // substract the region of obstaces from the delta region to get pure delta
2375 GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
2376 // substract obstacles from the clip region
2377 GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnObst, CRGN_DIFF );
2378 // substract pure delta from the clip region (to reduce flicker)
2379 GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnDelta, CRGN_DIFF );
2380 // substract the new invalid region from the clip region (to reduce flicker)
2381 GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnInv, CRGN_DIFF );
2382
2383 // scroll the area
2384 GpiSetClipRegion( hps, hrgnClip, NULL );
2385 GpiBitBlt( hps, hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
2386 GpiSetClipRegion( hps, 0, NULL );
2387
2388 // invalidate the delta region (clipped off when blitting)
2389 WinInvalidateRegion( hwnd, hrgnDelta, clip == NULL );
2390
2391 // invalidate the region uncovered after scrolling
2392 WinInvalidateRegion( hwnd, hrgnUpd, clip == NULL );
2393
2394 // put the new invalid region back
2395 WinInvalidateRegion( hwnd, hrgnInv, clip == NULL );
2396
2397 GpiDestroyRegion( hps, hrgnInv );
2398 GpiDestroyRegion( hps, hrgnDelta );
2399 GpiDestroyRegion( hps, hrgnObst );
2400 GpiDestroyRegion( hps, hrgnUpd );
2401 GpiDestroyRegion( hps, hrgnClip );
2402 WinReleasePS( hps );
2403
2404 // In order to get the effect of "instant" scrolling, we process WM_PAINT
2405 // messages pending after invalidation manually instead of calling
2406 // WinUpdateWindow(). The latter tends to skip WM_PAINT messages under the
2407 // heavy load of the GUI thread (probably due to the low WM_PAINT priority),
2408 // which may cause parts of scrolled areas to look "stuck" (not updated in
2409 // time but with some delay).
2410 QMSG qmsg;
2411 while( WinPeekMsg( 0, &qmsg, NULLHANDLE, WM_PAINT, WM_PAINT, PM_REMOVE ) )
2412 WinDispatchMsg( 0, &qmsg );
2413}
2414
2415#endif
2416
2417void QWidget::scroll( int dx, int dy )
2418{
2419 if ( testWState( WState_BlockUpdates ) && !children() )
2420 return;
2421
2422#if defined (QT_PM_NO_WIDGETMASK)
2423
2424 // move non-toplevel children
2425 if ( children() ) {
2426 QObjectListIt it(*children());
2427 register QObject *obj;
2428 int h = crect.height();
2429 while ( (obj=it.current()) ) {
2430 ++it;
2431 if ( obj->isWidgetType() ) {
2432 QWidget *w = (QWidget*)obj;
2433 if ( !w->isTopLevel() ) {
2434 WinSetWindowPos(
2435 w->winId(), 0,
2436 w->crect.left() + dx,
2437 // flip y coordinate
2438 h - (w->crect.bottom() + dy + 1),
2439 0, 0,
2440 SWP_MOVE | SWP_NOADJUST | SWP_NOREDRAW
2441 );
2442 // WinSetWindowPos() doesn't send WM_MOVE to windows w/o
2443 // CS_MOVENOTIFY, but having this style for non-toplevel
2444 // widgets is unwanted, so we send them WM_MOVE manually
2445 // to let their geometry to be properly updated by
2446 // QETWidget::translateConfigEvent().
2447 WinSendMsg( w->winId(), WM_MOVE, 0, 0 );
2448 }
2449 }
2450 }
2451 }
2452
2453 qt_WinScrollWindowWell( winId(), dx, -dy, NULL );
2454
2455#else
2456
2457 scrollWindow( winId(), width(), height(), dx, -dy, NULL );
2458
2459#endif
2460}
2461
2462void QWidget::scroll( int dx, int dy, const QRect& r )
2463{
2464 if ( testWState( WState_BlockUpdates ) )
2465 return;
2466
2467#if defined (QT_PM_NO_WIDGETMASK)
2468
2469 int h = crect.height();
2470 // flip y coordinate (all coordinates are inclusive)
2471 RECTL rcl = { r.left(), h - (r.bottom() + 1), r.right(), h - (r.top() + 1) };
2472 qt_WinScrollWindowWell( winId(), dx, -dy, &rcl );
2473
2474#else
2475
2476 int h = crect.height();
2477 // flip y coordinate
2478 RECTL rcl = { r.left(), h - (r.bottom() + 1),
2479 r.right() + 1, h - r.top() };
2480 scrollWindow( winId(), width(), height(), dx, -dy, &rcl );
2481
2482#endif
2483}
2484
2485void QWidget::drawText( int x, int y, const QString &str )
2486{
2487 if ( testWState(WState_Visible) ) {
2488 QPainter paint;
2489 paint.begin( this );
2490 paint.drawText( x, y, str );
2491 paint.end();
2492 }
2493}
2494
2495
2496int QWidget::metric( int m ) const
2497{
2498 LONG val;
2499 if ( m == QPaintDeviceMetrics::PdmWidth ) {
2500 val = crect.width();
2501 } else if ( m == QPaintDeviceMetrics::PdmHeight ) {
2502 val = crect.height();
2503 } else {
2504 HDC hdc = GpiQueryDevice( qt_display_ps() );
2505 switch ( m ) {
2506 case QPaintDeviceMetrics::PdmDpiX:
2507 case QPaintDeviceMetrics::PdmPhysicalDpiX:
2508 DevQueryCaps( hdc, CAPS_HORIZONTAL_FONT_RES, 1, &val );
2509 break;
2510 case QPaintDeviceMetrics::PdmDpiY:
2511 case QPaintDeviceMetrics::PdmPhysicalDpiY:
2512 DevQueryCaps( hdc, CAPS_VERTICAL_FONT_RES, 1, &val );
2513 break;
2514 case QPaintDeviceMetrics::PdmWidthMM:
2515 DevQueryCaps( hdc, CAPS_HORIZONTAL_RESOLUTION, 1, &val );
2516 val = width() * 1000 / val;
2517 break;
2518 case QPaintDeviceMetrics::PdmHeightMM:
2519 DevQueryCaps( hdc, CAPS_VERTICAL_RESOLUTION, 1, &val );
2520 val = width() * 1000 / val;
2521 break;
2522 case QPaintDeviceMetrics::PdmNumColors:
2523 DevQueryCaps( hdc, CAPS_COLORS, 1, &val );
2524 break;
2525 case QPaintDeviceMetrics::PdmDepth:
2526 LONG colorInfo [2];
2527 DevQueryCaps( hdc, CAPS_COLOR_PLANES, 2, colorInfo );
2528 val = colorInfo [0] * colorInfo [1];
2529 break;
2530 default:
2531 val = 0;
2532#if defined(QT_CHECK_RANGE)
2533 qWarning( "QWidget::metric: Invalid metric command" );
2534#endif
2535 }
2536 }
2537 return val;
2538}
2539
2540void QWidget::createSysExtra()
2541{
2542}
2543
2544void QWidget::deleteSysExtra()
2545{
2546}
2547
2548void QWidget::createTLSysExtra()
2549{
2550 extra->topextra->fId = 0;
2551 extra->topextra->swEntry = 0;
2552 extra->topextra->pmIcon = 0;
2553 extra->topextra->in_sendWindowState = 0;
2554}
2555
2556void QWidget::deleteTLSysExtra()
2557{
2558 if ( extra->topextra->pmIcon )
2559 WinDestroyPointer( extra->topextra->pmIcon );
2560 if ( extra->topextra->swEntry )
2561 WinRemoveSwitchEntry( extra->topextra->swEntry );
2562 // frame window (extra->topextra->fId) is destroyed in
2563 // destroy() if it exists
2564}
2565
2566bool QWidget::acceptDrops() const
2567{
2568 return testWState( WState_DND );
2569}
2570
2571void QWidget::setAcceptDrops( bool on )
2572{
2573 if ( testWState(WState_DND) != on ) {
2574 if ( on )
2575 setWState( WState_DND );
2576 else
2577 clearWState( WState_DND );
2578 }
2579}
2580
2581#if !defined (QT_PM_NO_WIDGETMASK)
2582
2583// helper for QWidget::setMask()
2584static void setClipRegion( HWND hwnd, int x, int y, int w, int h, HRGN hrgn,
2585 HWND parent )
2586{
2587 if ( !WinIsWindowVisible( hwnd ) ) {
2588 // if the window is hidden, no need to invalidate anything
2589 WinSetClipRegion( hwnd, hrgn );
2590 return;
2591 }
2592
2593 HPS hps = qt_display_ps();
2594 const RECTL rcl = { 0, 0, w, h };
2595
2596 // get the old bounds (clip region or rect)
2597 HRGN hrgnOld = GpiCreateRegion( hps, 0, NULL );
2598 qt_WinQueryClipRegionOrRect( hwnd, hrgnOld );
2599 // set the new clip region
2600 WinSetClipRegion( hwnd, hrgn );
2601
2602 HRGN hrgnUpd;
2603 if ( hrgn != 0 ) {
2604 hrgnUpd = GpiCreateRegion( hps, 0, NULL );
2605 // substract the new clip region from the old one
2606 GpiCombineRegion( hps, hrgnUpd, hrgnOld, hrgn, CRGN_DIFF );
2607 // move the result to the parent coordinate space
2608 POINTL ptl = { x, y };
2609 GpiOffsetRegion( hps, hrgnUpd, &ptl );
2610 // invalidate areas in parent uncovered by the new clip region
2611 qt_WinInvalidateRegionEx( parent, hrgnUpd,
2612 WinQueryWindow( hwnd, QW_NEXT ), HWND_BOTTOM );
2613 } else {
2614 // the new region is being set to NULL, which means to widget bounds
2615 // (no need to substract new from old, because it will produce RGN_NULL)
2616 hrgnUpd = GpiCreateRegion( hps, 1, &rcl );
2617 hrgn = hrgnUpd;
2618 }
2619 // substract the old clip region from the new one
2620 GpiCombineRegion( hps, hrgnUpd, hrgn, hrgnOld, CRGN_DIFF );
2621 // invalidate areas in hwnd uncovered by the new clip region
2622 WinInvalidateRegion( hwnd, hrgnUpd, TRUE );
2623
2624 GpiDestroyRegion( hps, hrgnUpd );
2625 GpiDestroyRegion( hps, hrgnOld );
2626}
2627
2628#endif
2629
2630/*!
2631 \overload
2632
2633 Causes only the parts of the widget which overlap \a region to be
2634 visible. If the region includes pixels outside the rect() of the
2635 widget, window system controls in that area may or may not be
2636 visible, depending on the platform.
2637
2638 Note that this effect can be slow if the region is particularly
2639 complex.
2640
2641 Note that on OS/2, masks for top-level widgets are not currently
2642 supported, so setting a mask on such a widget has no effect.
2643
2644 \sa setMask(), clearMask()
2645*/
2646
2647void QWidget::setMask( const QRegion &region )
2648{
2649#if !defined (QT_PM_NO_WIDGETMASK)
2650 if (isTopLevel()) {
2651#if defined (QT_CHECK_STATE)
2652 qWarning( "QWidget::setMask() for top-level widgets "
2653 "is not implemented on OS/2" );
2654#endif
2655 return;
2656 }
2657 setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
2658 width(), height(), region.handle( height() ),
2659 parentWidget()->winId() );
2660#else
2661 Q_UNUSED( region );
2662#endif
2663}
2664
2665/*!
2666 Causes only the pixels of the widget for which \a bitmap has a
2667 corresponding 1 bit to be visible. If the region includes pixels
2668 outside the rect() of the widget, window system controls in that
2669 area may or may not be visible, depending on the platform.
2670
2671 Note that this effect can be slow if the region is particularly
2672 complex.
2673
2674 Note that on OS/2, masks for top-level widgets are not currently
2675 supported, so setting a mask on such a widget has no effect.
2676
2677 See \c examples/tux for an example of masking for transparency.
2678
2679 \sa setMask(), clearMask()
2680*/
2681
2682void QWidget::setMask( const QBitmap &bitmap )
2683{
2684#if !defined (QT_PM_NO_WIDGETMASK)
2685 if (isTopLevel()) {
2686#if defined (QT_CHECK_STATE)
2687 qWarning( "QWidget::setMask() for top-level widgets "
2688 "is not implemented on OS/2" );
2689#endif
2690 return;
2691 }
2692 QRegion rgn = QRegion( bitmap );
2693 setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
2694 width(), height(), rgn.handle( height() ),
2695 parentWidget()->winId() );
2696#else
2697 Q_UNUSED( bitmap );
2698#endif
2699}
2700
2701void QWidget::clearMask()
2702{
2703#if !defined (QT_PM_NO_WIDGETMASK)
2704 if (isTopLevel())
2705 return;
2706 setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
2707 width(), height(), 0,
2708 parentWidget()->winId() );
2709#endif
2710}
2711
2712void QWidget::setName( const char *name )
2713{
2714 QObject::setName( name );
2715}
2716
2717void QWidget::updateFrameStrut() const
2718{
2719 QWidget *that = (QWidget *) this;
2720
2721 if ( !isVisible() || isDesktop() ) {
2722 that->fstrut_dirty = isVisible();
2723 return;
2724 }
2725
2726 QTLWExtra *top = that->topData();
2727 if ( top->fId ) {
2728 // this widget has WC_FRAME
2729 SWP cswp;
2730 WinQueryWindowPos( winId(), &cswp );
2731 SWP fswp;
2732 WinQueryWindowPos( top->fId, &fswp );
2733 // flip y coordinates
2734 fswp.y = QApplication::desktop()->height() - (fswp.y + fswp.cy);
2735 cswp.y = fswp.cy - (cswp.y + cswp.cy);
2736 that->crect.setRect(
2737 fswp.x + cswp.x, fswp.y + cswp.y,
2738 cswp.cx, cswp.cy
2739 );
2740
2741 top->fleft = cswp.x;
2742 top->ftop = cswp.y;
2743 top->fright = fswp.cx - cswp.x - cswp.cx;
2744 top->fbottom = fswp.cy - cswp.y - cswp.cy;
2745 }
2746 that->fstrut_dirty = FALSE;
2747}
2748
2749void QWidget::setMouseTracking( bool enable )
2750{
2751 if ( enable )
2752 setWState( WState_MouseTracking );
2753 else
2754 clearWState( WState_MouseTracking );
2755}
2756
2757void QWidget::setWindowOpacity(double)
2758{
2759}
2760
2761double QWidget::windowOpacity() const
2762{
2763 return 1.0;
2764}
2765
2766/**
2767 * \internal
2768 * Returns the frame wihdow handle if this widget is a top-level widget and
2769 * has the standard WC_FRAME as its parent/owner (where it is FID_CLIENT).
2770 * If the widget does not have the standard frame or it is not top-level, this
2771 * function simply retuns the winId() value.
2772 */
2773WId QWidget::winFId()
2774{
2775 HWND fId = 0;
2776 if ( isTopLevel() )
2777 fId = topData()->fId;
2778 if ( !fId )
2779 fId = winId();
2780 return fId;
2781}
2782
2783#if !defined (QT_PM_NO_WIDGETMASK)
2784
2785/*!
2786 * \internal
2787 *
2788 * Validates areas of this widget covered by (intersected with) its children
2789 * and sibling widgets.
2790 *
2791 * Clip regions of all relative widgets (set by WinSetClipRegion()) are taken
2792 * into account.
2793 */
2794void QWidget::validateObstacles()
2795{
2796 RECTL updateRcl;
2797 if ( WinQueryUpdateRect( winId(), &updateRcl ) ) {
2798 // the update rectangle may be empty
2799 if ( updateRcl.xLeft != updateRcl.xRight &&
2800 updateRcl.yBottom != updateRcl.yTop ) {
2801 qt_WinProcessWindowObstacles( winId(), &updateRcl, 0, 0 );
2802 }
2803 }
2804}
2805
2806#endif // !defined (QT_PM_NO_WIDGETMASK)
2807
2808/*!
2809 * \internal
2810 *
2811 * Obtains a presentaiton space to draw on this widget, set up according
2812 * mode \a m and to widget flags.
2813 *
2814 * The returned handle must be freed using WinReleasePS() after usage.
2815 */
2816HPS QWidget::getTargetPS( ClipMode m /* = ClipDefault */ )
2817{
2818 HPS widgetPS = 0;
2819
2820 if ( isDesktop() ) {
2821 widgetPS = WinGetScreenPS( HWND_DESKTOP );
2822 return widgetPS;
2823 } else {
2824 if ( m == Unclipped || (m == ClipDefault &&
2825 testWFlags( WPaintUnclipped )) ) {
2826 widgetPS = WinGetClipPS( winId(), 0, PSF_PARENTCLIP );
2827 return widgetPS;
2828 } else {
2829 widgetPS = WinGetPS( winId() );
2830 }
2831 }
2832
2833#if !defined (QT_PM_NO_WIDGETMASK)
2834 RECTL rcl = { 0, 0, crect.width(), crect.height() };
2835 HRGN hrgn = GpiCreateRegion( widgetPS, 1, &rcl );
2836 qt_WinProcessWindowObstacles( winId(), NULL, hrgn, CRGN_DIFF );
2837 HRGN hrgnOld = 0;
2838 GpiSetClipRegion( widgetPS, hrgn, &hrgnOld );
2839 Q_ASSERT( !hrgnOld );
2840 if ( hrgnOld )
2841 GpiDestroyRegion( widgetPS, hrgnOld );
2842#endif
2843
2844 return widgetPS;
2845}
2846
Note: See TracBrowser for help on using the repository browser.