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

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

Added the PWO_TopLevel flag for qt_WinProcessWindowObstacles(): it tells to include top-level windows (children of the desktop) to the set of clipped out windows, which is necessary when moving ot scrolling windows (copies of parts of overlying top-level windows were left on the screen).

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