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

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

kernel: Created the initial implementation of the Drag'n'Drop support for OS/2 (not fully functiona yet: updating widget contents under the drag pointer will cause screen corruption, setting the drag object's pixmap is not possible). See ticket:22 for more info.

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