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

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

Widgets:

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