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

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

Widgets: Fixed:

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