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

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

Widgets: Added the non-scaling threshold when setting a top-level widgets's icon. This allows to avoid scaling pixmaps close to the target icon size (e.g. 16x16 to 20x20) to give them a better look (such pixmaps are centered instead of scaling).

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