source: trunk/src/kernel/qwidget_pm.cpp

Last change on this file was 195, checked in by rudi, 14 years ago

Fix for redrawing problems (ticket #47)

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