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

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

Implemented QWidget::setMask() functionality.

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