source: trunk/src/gui/kernel/qapplication_pm.cpp@ 122

Last change on this file since 122 was 122, checked in by Dmitry A. Kuminov, 16 years ago

gui: Don't change top level window size/position in Qt when it gets minimized (makes it similar to other platforms like Windows).

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Date Revision Author Id
File size: 65.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** Copyright (C) 2009 netlabs.org. OS/2 parts.
7**
8** This file is part of the QtGui module of the Qt Toolkit.
9**
10** $QT_BEGIN_LICENSE:LGPL$
11** Commercial Usage
12** Licensees holding valid Qt Commercial licenses may use this file in
13** accordance with the Qt Commercial License Agreement provided with the
14** Software or, alternatively, in accordance with the terms contained in
15** a written agreement between you and Nokia.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Nokia gives you certain
26** additional rights. These rights are described in the Nokia Qt LGPL
27** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28** package.
29**
30** GNU General Public License Usage
31** Alternatively, this file may be used under the terms of the GNU
32** General Public License version 3.0 as published by the Free Software
33** Foundation and appearing in the file LICENSE.GPL included in the
34** packaging of this file. Please review the following information to
35** ensure the GNU General Public License version 3.0 requirements will be
36** met: http://www.gnu.org/copyleft/gpl.html.
37**
38** If you are unsure which license is appropriate for your use, please
39** contact the sales department at [email protected].
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include "qt_os2.h"
45
46#include "qdebug.h"
47
48#include "qapplication.h"
49#include "qapplication_p.h"
50
51#include "qwidget.h"
52#include "qpointer.h"
53#include "qcolormap.h"
54#include "qpixmapcache.h"
55#include "qdesktopwidget.h"
56
57#include "qset.h"
58
59#include "private/qeventdispatcher_pm_p.h"
60#include "private/qbackingstore_p.h"
61
62#include "qwidget_p.h"
63#include "qkeymapper_p.h"
64#include "qcursor_p.h"
65
66#define QT_DEBUGMSGFLOW
67
68QT_BEGIN_NAMESPACE
69
70/*****************************************************************************
71 Internal variables and functions
72 *****************************************************************************/
73
74static HWND curWin = 0; // current window
75static HPS displayPS = 0; // display presentation space
76
77#if !defined (QT_NO_SESSIONMANAGER)
78
79// Session management
80static bool sm_blockUserInput = FALSE;
81
82//#define DEBUG_SESSIONMANAGER
83
84#endif
85
86static bool replayPopupMouseEvent = false; // replay handling when popups close
87
88// ignore the next release event if return from a modal widget
89static bool ignoreNextMouseReleaseEvent = false;
90
91#if defined(QT_DEBUG)
92static bool appNoGrab = false; // mouse/keyboard grabbing
93#endif
94
95static bool app_do_modal = false; // modal mode
96extern QWidgetList *qt_modal_stack;
97extern QDesktopWidget *qt_desktopWidget;
98static QPointer<QWidget> popupButtonFocus;
99static bool qt_try_modal(QWidget*, QMSG*, MRESULT&);
100
101QWidget *qt_button_down = 0; // widget got last button-down
102QPointer<QWidget> qt_last_mouse_receiver = 0;
103
104static HWND autoCaptureWnd = NULLHANDLE;
105static bool autoCaptureReleased = FALSE;
106static void setAutoCapture(HWND); // automatic capture
107static void releaseAutoCapture();
108
109extern QCursor *qt_grab_cursor();
110
111extern void qt_WinQueryClipRegionOrRect(HWND hwnd, HRGN hrgn); // qwidget_pm.cpp
112
113extern QRegion qt_dirtyRegion(QWidget *); // qbackingstore.cpp
114
115MRESULT EXPENTRY QtWndProc(HWND, ULONG, MPARAM, MPARAM);
116
117class QETWidget : public QWidget // event translator widget
118{
119public:
120 QWExtra *xtra() { return d_func()->extraData(); }
121 QTLWExtra *topData() { return d_func()->topData(); }
122// @todo later
123// QTLWExtra *maybeTopData() { return d_func()->maybeTopData(); }
124// void syncBackingStore(const QRegion &rgn) { d_func()->syncBackingStore(rgn); }
125// void syncBackingStore() { d_func()->syncBackingStore(); }
126 QWidgetData *dataPtr() { return data; }
127 QWidgetPrivate *dptr() { return d_func(); }
128// QRect frameStrut() const { return d_func()->frameStrut(); }
129 bool pmEvent(QMSG *m, MRESULT *r) { return QWidget::pmEvent(m, r); }
130// void markFrameStrutDirty() { data->fstrut_dirty = 1; }
131 bool translateMouseEvent(const QMSG &qmsg);
132#ifndef QT_NO_WHEELEVENT
133 bool translateWheelEvent(const QMSG &qmsg);
134#endif
135 bool translatePaintEvent(const QMSG &qmsg);
136 bool translateConfigEvent(const QMSG &qmsg);
137 bool translateCloseEvent(const QMSG &qmsg);
138// void repolishStyle(QStyle &style);
139// inline void showChildren(bool spontaneous) { d_func()->showChildren(spontaneous); }
140// inline void hideChildren(bool spontaneous) { d_func()->hideChildren(spontaneous); }
141// inline void validateObstacles() { d_func()->validateObstacles(); }
142// inline uint testWindowState(uint teststate){ return dataPtr()->window_state & teststate; }
143// inline void forceUpdate() {
144// QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
145// if (tlwExtra && tlwExtra->backingStore)
146// tlwExtra->backingStore->markDirty(rect(), this, true, true);
147// }
148};
149
150static void qt_set_pm_resources()
151{
152 // @todo later: take colors, fonts, etc. from the system theme
153};
154
155/*****************************************************************************
156 qt_init() - initializes Qt for PM
157 *****************************************************************************/
158
159void qt_init(QApplicationPrivate *priv, int)
160{
161
162 int argc = priv->argc;
163 char **argv = priv->argv;
164 int i, j;
165
166 // Get command line params
167
168 j = argc ? 1 : 0;
169 for (i=1; i<argc; i++) {
170 if (argv[i] && *argv[i] != '-') {
171 argv[j++] = argv[i];
172 continue;
173 }
174#if defined(QT_DEBUG)
175 if (qstrcmp(argv[i], "-nograb") == 0)
176 appNoGrab = !appNoGrab;
177 else
178#endif // QT_DEBUG
179 argv[j++] = argv[i];
180 }
181 if(j < priv->argc) {
182 priv->argv[j] = 0;
183 priv->argc = j;
184 }
185
186 // initialize key mapper
187 QKeyMapper::changeKeyboard();
188
189 QColormap::initialize();
190 QFont::initialize();
191#ifndef QT_NO_CURSOR
192 QCursorData::initialize();
193#endif
194 qApp->setObjectName(priv->appName());
195
196 // default font
197 QApplicationPrivate::setSystemFont(
198 QFont(QLatin1String("System Proportional"), 10));
199
200 // QFont::locale_init(); ### Uncomment when it does something on OS/2
201
202 if (QApplication::desktopSettingsAware())
203 qt_set_pm_resources();
204}
205
206/*****************************************************************************
207 qt_cleanup() - cleans up when the application is finished
208 *****************************************************************************/
209
210void qt_cleanup()
211{
212 QPixmapCache::clear();
213
214#ifndef QT_NO_CURSOR
215 QCursorData::cleanup();
216#endif
217 QFont::cleanup();
218 QColormap::cleanup();
219
220 if (displayPS) {
221 WinReleasePS(displayPS);
222 displayPS = 0;
223 }
224}
225
226/*****************************************************************************
227 Platform specific global and internal functions
228 *****************************************************************************/
229
230Q_GUI_EXPORT HPS qt_display_ps()
231{
232 Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
233 if (!displayPS)
234 displayPS = WinGetScreenPS(HWND_DESKTOP);
235 return displayPS;
236}
237
238// application no-grab option
239bool qt_nograb()
240{
241#if defined(QT_DEBUG)
242 return appNoGrab;
243#else
244 return false;
245#endif
246}
247
248/*****************************************************************************
249 Safe configuration (move,resize,setGeometry) mechanism to avoid
250 recursion when processing messages.
251 *****************************************************************************/
252
253struct QPMConfigRequest {
254 WId id; // widget to be configured
255 int req; // 0=move, 1=resize, 2=setGeo
256 int x, y, w, h; // request parameters
257};
258
259Q_GLOBAL_STATIC(QList<QPMConfigRequest*>, configRequests);
260
261void qPMRequestConfig(WId id, int req, int x, int y, int w, int h)
262{
263 QPMConfigRequest *r = new QPMConfigRequest;
264 r->id = id;
265 r->req = req;
266 r->x = x;
267 r->y = y;
268 r->w = w;
269 r->h = h;
270 configRequests()->append(r);
271}
272
273/*****************************************************************************
274 GUI event dispatcher
275 *****************************************************************************/
276
277class QGuiEventDispatcherPM : public QEventDispatcherPM
278{
279public:
280 QGuiEventDispatcherPM(QObject *parent = 0);
281 bool processEvents(QEventLoop::ProcessEventsFlags flags);
282};
283
284QGuiEventDispatcherPM::QGuiEventDispatcherPM(QObject *parent)
285 : QEventDispatcherPM(parent)
286{
287 // pre-create the message queue early as we'll need it anyway in GUI mode
288 createMsgQueue();
289}
290
291bool QGuiEventDispatcherPM::processEvents(QEventLoop::ProcessEventsFlags flags)
292{
293 if (!QEventDispatcherPM::processEvents(flags))
294 return false;
295
296 QPMConfigRequest *r;
297 for (;;) {
298 if (configRequests()->isEmpty())
299 break;
300 r = configRequests()->takeLast();
301 QWidget *w = QWidget::find(r->id);
302 QRect rect(r->x, r->y, r->w, r->h);
303 int req = r->req;
304 delete r;
305
306 if (w) { // widget exists
307 if (w->testAttribute(Qt::WA_WState_ConfigPending))
308 break; // biting our tail
309 if (req == 0)
310 w->move(rect.topLeft());
311 else if (req == 1)
312 w->resize(rect.size());
313 else
314 w->setGeometry(rect);
315 }
316 }
317
318 return true;
319}
320
321void QApplicationPrivate::createEventDispatcher()
322{
323 Q_Q(QApplication);
324 if (q->type() != QApplication::Tty)
325 eventDispatcher = new QGuiEventDispatcherPM(q);
326 else
327 eventDispatcher = new QEventDispatcherPM(q);
328}
329
330/*****************************************************************************
331 Platform specific QApplication members
332 *****************************************************************************/
333
334void QApplicationPrivate::initializeWidgetPaletteHash()
335{
336}
337
338QString QApplicationPrivate::appName() const
339{
340 return QCoreApplicationPrivate::appName();
341}
342
343void QApplication::setCursorFlashTime(int msecs)
344{
345 WinSetSysValue(HWND_DESKTOP, SV_CURSORRATE, msecs / 2);
346 QApplicationPrivate::cursor_flash_time = msecs;
347}
348
349int QApplication::cursorFlashTime()
350{
351 int blink = (int)WinQuerySysValue(HWND_DESKTOP, SV_CURSORRATE);
352 if (!blink)
353 return QApplicationPrivate::cursor_flash_time;
354 if (blink > 0)
355 return 2 * blink;
356 return 0;
357}
358
359void QApplication::setDoubleClickInterval(int ms)
360{
361 WinSetSysValue(HWND_DESKTOP, SV_DBLCLKTIME, ms);
362 QApplicationPrivate::mouse_double_click_time = ms;
363}
364
365int QApplication::doubleClickInterval()
366{
367 int ms = (int) WinQuerySysValue(HWND_DESKTOP, SV_DBLCLKTIME);
368 if (ms != 0)
369 return ms;
370 return QApplicationPrivate::mouse_double_click_time;
371}
372
373void QApplication::setKeyboardInputInterval(int ms)
374{
375 QApplicationPrivate::keyboard_input_time = ms;
376}
377
378int QApplication::keyboardInputInterval()
379{
380 // FIXME: get from the system
381 return QApplicationPrivate::keyboard_input_time;
382}
383
384#ifndef QT_NO_WHEELEVENT
385void QApplication::setWheelScrollLines(int n)
386{
387 QApplicationPrivate::wheel_scroll_lines = n;
388}
389
390int QApplication::wheelScrollLines()
391{
392 return QApplicationPrivate::wheel_scroll_lines;
393}
394#endif //QT_NO_WHEELEVENT
395
396void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
397{
398 // @todo implement
399}
400
401bool QApplication::isEffectEnabled(Qt::UIEffect effect)
402{
403 // @todo implement
404 return false;
405}
406
407void QApplication::beep()
408{
409 WinAlarm(HWND_DESKTOP, WA_WARNING);
410}
411
412void QApplication::alert(QWidget *widget, int duration)
413{
414 // @todo implement
415}
416
417/*****************************************************************************
418 QApplication cursor stack
419 *****************************************************************************/
420
421#ifndef QT_NO_CURSOR
422
423void QApplication::setOverrideCursor(const QCursor &cursor)
424{
425 // @todo implement
426}
427
428void QApplication::restoreOverrideCursor()
429{
430 // @todo implement
431}
432
433#endif
434
435/*****************************************************************************
436 Routines to find a Qt widget from a screen position
437 *****************************************************************************/
438
439QWidget *QApplication::topLevelAt(const QPoint &pos)
440{
441 // @todo implement
442 return 0;
443}
444
445/*****************************************************************************
446 Main event loop
447 *****************************************************************************/
448
449// sent to hwnd that has been entered to by a mouse pointer.
450// FID_CLIENT also receives enter messages of its WC_FRAME.
451// mp1 = hwnd that is entered, mp2 = hwnd that is left
452#define WM_U_MOUSEENTER 0x41E
453// sent to hwnd that has been left by a mouse pointer.
454// FID_CLIENT also receives leave messages of its WC_FRAME.
455// mp1 = hwnd that is left, mp2 = hwnd that is entered
456#define WM_U_MOUSELEAVE 0x41F
457
458// some undocumented system values
459#define SV_WORKAREA_YTOP 51
460#define SV_WORKAREA_YBOTTOM 52
461#define SV_WORKAREA_XRIGHT 53
462#define SV_WORKAREA_XLEFT 54
463
464// QtWndProc() receives all messages from the main event loop
465
466MRESULT EXPENTRY QtWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
467{
468 do {
469 if (!qApp) // unstable app state
470 break;
471#if 0
472 // make sure we show widgets (e.g. scrollbars) when the user resizes
473 if (qApp->loopLevel())
474 qApp->sendPostedEvents(0, QEvent::ShowWindowRequest);
475#endif
476
477 MRESULT rc = (MRESULT) FALSE;
478 QETWidget *widget = 0;
479
480 bool isTranslatableMouseEvent =
481 (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
482 (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST);
483
484 QMSG qmsg; // create QMSG structure
485 qmsg.hwnd = hwnd;
486 qmsg.msg = msg;
487 qmsg.mp1 = mp1;
488 qmsg.mp2 = mp2;
489 qmsg.time = WinQueryMsgTime(0);
490
491 if (isTranslatableMouseEvent || msg == WM_CONTEXTMENU) {
492 qmsg.ptl.x = (short)SHORT1FROMMP(mp1);
493 qmsg.ptl.y = (short)SHORT2FROMMP(mp1);
494 WinMapWindowPoints(qmsg.hwnd, HWND_DESKTOP, &qmsg.ptl, 1);
495 } else {
496 WinQueryMsgPos(0, &qmsg.ptl);
497 }
498 // flip y coordinate
499 qmsg.ptl.y = QApplication::desktop()->height() - (qmsg.ptl.y + 1);
500
501#if defined(QT_DEBUGMSGFLOW)
502 {
503 QString str = qStrQMSG(qmsg);
504 if (!str.isEmpty())
505 qDebug() << "*** [W]" << str.toUtf8().constData();
506 }
507#endif
508
509 // send through app filter
510 if (qApp->filterEvent(&qmsg, reinterpret_cast<long *>(&rc)))
511 return rc;
512
513 switch(msg) {
514
515 case WM_BUTTON1DOWN:
516 case WM_BUTTON2DOWN:
517 case WM_BUTTON3DOWN:
518 if (ignoreNextMouseReleaseEvent)
519 ignoreNextMouseReleaseEvent = false;
520 break;
521 case WM_BUTTON1UP:
522 case WM_BUTTON2UP:
523 case WM_BUTTON3UP:
524 if (ignoreNextMouseReleaseEvent) {
525 ignoreNextMouseReleaseEvent = false;
526 if (qt_button_down && qt_button_down->internalWinId() == autoCaptureWnd) {
527 releaseAutoCapture();
528 qt_button_down = 0;
529 }
530 return (MRESULT)TRUE;
531 }
532 break;
533
534 default:
535 break;
536 }
537
538 if (!widget)
539 widget = (QETWidget*)QWidget::find(hwnd);
540 if (!widget) // don't know this widget
541 break;
542
543 if (app_do_modal) { // modal event handling
544 if (!qt_try_modal(widget, &qmsg, rc))
545 return rc;
546 }
547
548 if (widget->pmEvent(&qmsg, &rc)) // send through widget filter
549 return rc;
550
551 if (isTranslatableMouseEvent) {
552 if (qApp->activePopupWidget() != 0) { // in popup mode
553 QWidget *w = QApplication::widgetAt(qmsg.ptl.x, qmsg.ptl.y);
554 if (w) {
555 POINTL ptl = { SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1) };
556 WinMapWindowPoints(qmsg.hwnd, w->winId(), &ptl, 1);
557 qmsg.mp1 = MPFROM2SHORT(ptl.x, ptl.y);
558 widget = (QETWidget*)w;
559 }
560 }
561 if (widget->translateMouseEvent(qmsg)) // mouse event
562 return (MRESULT)TRUE;
563#ifndef QT_NO_WHEELEVENT
564 } else if (msg == WM_VSCROLL || msg == WM_HSCROLL) {
565 if (widget->translateWheelEvent(qmsg))
566 return (MRESULT)TRUE;
567#endif
568#ifndef QT_NO_DRAGANDDROP
569 } else if (msg >= WM_DRAGFIRST && msg <= WM_DRAGLAST) {
570 return qt_dispatchDragAndDrop(widget, qmsg);
571#endif
572 } else {
573 switch(msg) {
574
575 case WM_PAINT: { // paint event
576 if (widget->translatePaintEvent(qmsg))
577 return (MRESULT)TRUE;
578 break;
579 }
580
581 case WM_ERASEBACKGROUND: { // erase window background
582 // flush WM_PAINT messages here to update window contents
583 // instantly while tracking the resize frame (normally these
584 // messages are delivered after the user has stopped resizing
585 // for some time). this slows down resizing slightly but gives a
586 // better look (no invalid window contents can be seen during
587 // resize). the alternative could be to erase the background only,
588 // but we need to do it for every non-toplevel window, which can
589 // also be time-consuming (WM_ERASEBACKGROUND is sent to WC_FRAME
590 // clients only, so we would have to do all calculations ourselves).
591 WinUpdateWindow(widget->effectiveWinId());
592 return FALSE;
593 }
594
595 case WM_CALCVALIDRECTS: {
596 // we must always return this value here to cause PM to reposition
597 // our children accordingly (othwerwise we would have to do it
598 // ourselves to keep them top-left aligned).
599 return (MRESULT)(CVR_ALIGNLEFT | CVR_ALIGNTOP);
600 }
601
602 case WM_SIZE: { // resize window
603 if (widget->translateConfigEvent(qmsg))
604 return (MRESULT)TRUE;
605 break;
606 }
607
608 case WM_SHOW: {
609 // @todo there is some more processing in Qt4, see
610 // WM_SHOWWINDOW in qapplication_win.cpp
611 if (!SHORT1FROMMP(mp1) && autoCaptureWnd == widget->internalWinId())
612 releaseAutoCapture();
613 break;
614 }
615
616 case WM_CLOSE: { // close window
617 widget->translateCloseEvent(qmsg);
618 return (MRESULT)TRUE;
619 }
620
621 case WM_DESTROY: { // destroy window
622 if (hwnd == curWin) {
623 QWidget *enter = QWidget::mouseGrabber();
624 if (enter == widget)
625 enter = 0;
626 QApplicationPrivate::dispatchEnterLeave(enter, widget);
627 curWin = enter ? enter->effectiveWinId() : 0;
628 qt_last_mouse_receiver = enter;
629 }
630 if (widget == popupButtonFocus)
631 popupButtonFocus = 0;
632 break;
633 }
634
635#ifndef QT_NO_CONTEXTMENU
636 case WM_CONTEXTMENU: {
637 if (SHORT2FROMMP(mp2)) {
638 // keyboard event
639 QWidget *fw = qApp->focusWidget();
640 if (fw && fw->isEnabled()) {
641 QContextMenuEvent e(QContextMenuEvent::Keyboard,
642 QPoint(5, 5),
643 fw->mapToGlobal(QPoint(5, 5)), 0);
644 if (qt_sendSpontaneousEvent(fw, &e))
645 return (MRESULT)TRUE;
646 }
647 } else {
648 // mouse event
649 if (widget->translateMouseEvent(qmsg))
650 return (MRESULT)TRUE;
651 }
652 break;
653 }
654#endif
655
656 case WM_U_MOUSELEAVE: {
657 // We receive a mouse leave for curWin, meaning
658 // the mouse was moved outside our widgets
659 if (widget->internalWinId() == curWin) {
660 bool dispatch = !widget->underMouse();
661 // hasMouse is updated when dispatching enter/leave,
662 // so test if it is actually up-to-date
663 if (!dispatch) {
664 QRect geom = widget->geometry();
665 if (widget->parentWidget() && !widget->isWindow()) {
666 QPoint gp = widget->parentWidget()->mapToGlobal(widget->pos());
667 geom.setX(gp.x());
668 geom.setY(gp.y());
669 }
670 QPoint cpos = QCursor::pos();
671 dispatch = !geom.contains(cpos);
672 if ( !dispatch && !QWidget::mouseGrabber()) {
673 QWidget *hittest = QApplication::widgetAt(cpos);
674 dispatch = !hittest || hittest->internalWinId() != curWin;
675 }
676 if (!dispatch) {
677 HPS hps = qt_display_ps();
678 HRGN hrgn = GpiCreateRegion(hps, 0, NULL);
679 qt_WinQueryClipRegionOrRect(hwnd, hrgn);
680 QPoint lcpos = widget->mapFromGlobal(cpos);
681 // flip y coordinate
682 POINTL pt = { lcpos.x(), widget->height() - (lcpos.y() + 1) };
683 dispatch = !GpiPtInRegion(hps, hrgn, &pt);
684 GpiDestroyRegion(hps, hrgn);
685 }
686 }
687 if (dispatch) {
688 if (qt_last_mouse_receiver && !qt_last_mouse_receiver->internalWinId())
689 QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
690 else
691 QApplicationPrivate::dispatchEnterLeave(0, QWidget::find((WId)curWin));
692 curWin = 0;
693 qt_last_mouse_receiver = 0;
694 }
695 }
696 break;
697 }
698
699 case WM_MINMAXFRAME: {
700 PSWP pswp = (PSWP)mp1;
701
702 bool window_state_change = false;
703 Qt::WindowStates oldstate = Qt::WindowStates(widget->dataPtr()->window_state);
704
705 if (pswp->fl & SWP_MINIMIZE) {
706 window_state_change = true;
707 widget->dataPtr()->window_state |= Qt::WindowMinimized;
708 if (widget->isVisible()) {
709 QHideEvent e;
710 qt_sendSpontaneousEvent(widget, &e);
711 widget->dptr()->hideChildren(true);
712 const QString title = widget->windowIconText();
713 if (!title.isEmpty())
714 widget->dptr()->setWindowTitle_helper(title);
715 }
716 } else if (pswp->fl & (SWP_MAXIMIZE | SWP_RESTORE)) {
717 window_state_change = true;
718 if (pswp->fl & SWP_MAXIMIZE) {
719 widget->topData()->normalGeometry = widget->geometry();
720 widget->dataPtr()->window_state |= Qt::WindowMaximized;
721 }
722 else if (!widget->isMinimized()) {
723 widget->dataPtr()->window_state &= ~Qt::WindowMaximized;
724 }
725
726 if (widget->isMinimized()) {
727 widget->dataPtr()->window_state &= ~Qt::WindowMinimized;
728 widget->dptr()->showChildren(true);
729 QShowEvent e;
730 qt_sendSpontaneousEvent(widget, &e);
731 const QString title = widget->windowTitle();
732 if (!title.isEmpty())
733 widget->dptr()->setWindowTitle_helper(title);
734 }
735 }
736
737 if (window_state_change) {
738 QWindowStateChangeEvent e(oldstate);
739 qt_sendSpontaneousEvent(widget, &e);
740 }
741
742 break;
743 }
744
745 default:
746 break;
747 }
748 }
749
750 } while(0);
751
752 return WinDefWindowProc(hwnd, msg, mp1, mp2);
753}
754
755PFNWP QtOldFrameProc = 0;
756
757MRESULT EXPENTRY QtFrameProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
758{
759 do {
760 if (!qApp) // unstable app state
761 break;
762#if 0
763 // make sure we show widgets (e.g. scrollbars) when the user resizes
764 if (qApp->loopLevel())
765 qApp->sendPostedEvents(0, QEvent::ShowWindowRequest);
766#endif
767
768 HWND hwndC = WinWindowFromID(hwnd, FID_CLIENT);
769 QETWidget *widget = (QETWidget*)QWidget::find(hwndC);
770 if (!widget) // don't know this widget
771 break;
772
773 Q_ASSERT(widget->isWindow());
774
775 QMSG qmsg; // create QMSG structure
776 qmsg.hwnd = hwnd;
777 qmsg.msg = msg;
778 qmsg.mp1 = mp1;
779 qmsg.mp2 = mp2;
780
781#if defined(QT_DEBUGMSGFLOW)
782 {
783 QString str = qStrQMSG(qmsg);
784 if (!str.isEmpty())
785 qDebug() << "*** [F]" << str.toUtf8().constData();
786 }
787#endif
788
789 switch(msg) {
790
791 case WM_MOVE: { // move window
792 // note that we handle it nere instead of having CS_MOVENOTIFY
793 // on the client and handling in QtWndProc because we don't want
794 // client inside frame window move messages that would appear during
795 // minimize/maximize otherwise
796 if (widget->translateConfigEvent(qmsg))
797 return (MRESULT)TRUE;
798 break;
799 }
800
801 default:
802 break;
803 }
804 } while(0);
805
806 return QtOldFrameProc(hwnd, msg, mp1, mp2);
807}
808
809/*****************************************************************************
810 Modal widgets; We have implemented our own modal widget mechanism
811 to get total control.
812 A modal widget without a parent becomes application-modal.
813 A modal widget with a parent becomes modal to its parent and grandparents..
814
815 QApplicationPrivate::enterModal()
816 Enters modal state
817 Arguments:
818 QWidget *widget A modal widget
819
820 QApplicationPrivate::leaveModal()
821 Leaves modal state for a widget
822 Arguments:
823 QWidget *widget A modal widget
824 *****************************************************************************/
825
826bool QApplicationPrivate::modalState()
827{
828 return app_do_modal;
829}
830
831void QApplicationPrivate::enterModal_sys(QWidget *widget)
832{
833 if (!qt_modal_stack)
834 qt_modal_stack = new QWidgetList;
835
836 releaseAutoCapture();
837 QWidget *leave = qt_last_mouse_receiver;
838 if (!leave)
839 leave = QWidget::find(curWin);
840 QApplicationPrivate::dispatchEnterLeave(0, leave);
841 qt_modal_stack->insert(0, widget);
842 app_do_modal = true;
843 curWin = 0;
844 qt_last_mouse_receiver = 0;
845 ignoreNextMouseReleaseEvent = false;
846}
847
848void QApplicationPrivate::leaveModal_sys(QWidget *widget)
849{
850 if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
851 if (qt_modal_stack->isEmpty()) {
852 delete qt_modal_stack;
853 qt_modal_stack = 0;
854 QPoint p(QCursor::pos());
855 app_do_modal = false; // necessary, we may get recursively into qt_try_modal below
856 QWidget* w = QApplication::widgetAt(p.x(), p.y());
857 QWidget *leave = qt_last_mouse_receiver;
858 if (!leave)
859 leave = QWidget::find(curWin);
860 if (QWidget *grabber = QWidget::mouseGrabber()) {
861 w = grabber;
862 if (leave == w)
863 leave = 0;
864 }
865 QApplicationPrivate::dispatchEnterLeave(w, leave); // send synthetic enter event
866 curWin = w ? w->effectiveWinId() : 0;
867 qt_last_mouse_receiver = w;
868 }
869 ignoreNextMouseReleaseEvent = true;
870 }
871 app_do_modal = qt_modal_stack != 0;
872}
873
874bool qt_try_modal(QWidget *widget, QMSG *qmsg, MRESULT &rc)
875{
876 QWidget *top = 0;
877
878 if (QApplicationPrivate::tryModalHelper(widget, &top))
879 return true;
880
881 int type = qmsg->msg;
882
883 bool block_event = false;
884 if ((type >= WM_MOUSEFIRST && type <= WM_MOUSELAST) ||
885 (type >= WM_EXTMOUSEFIRST && type <= WM_EXTMOUSELAST) ||
886 type == WM_VSCROLL || type == WM_HSCROLL ||
887 type == WM_U_MOUSELEAVE ||
888 type == WM_CHAR) {
889 if (type == WM_MOUSEMOVE) {
890#ifndef QT_NO_CURSOR
891 QCursor *c = qt_grab_cursor();
892 if (!c)
893 c = QApplication::overrideCursor();
894 if (c) // application cursor defined
895 WinSetPointer(HWND_DESKTOP, c->handle());
896 else
897 WinSetPointer(HWND_DESKTOP, QCursor(Qt::ArrowCursor).handle());
898#endif // QT_NO_CURSOR
899 } else if (type == WM_BUTTON1DOWN || type == type == WM_BUTTON2DOWN ||
900 type == WM_BUTTON3DOWN) {
901 if (!top->isActiveWindow()) {
902 top->activateWindow();
903 } else {
904 QApplication::beep();
905 }
906 }
907 block_event = true;
908 } else if (type == WM_CLOSE) {
909 block_event = true;
910 } else if (type == WM_SYSCOMMAND) {
911 if (!(SHORT1FROMMP(qmsg->mp1) == SC_RESTORE && widget->isMinimized()))
912 block_event = true;
913 }
914
915 return !block_event;
916}
917
918/*****************************************************************************
919 Popup widget mechanism
920
921 openPopup()
922 Adds a widget to the list of popup widgets
923 Arguments:
924 QWidget *widget The popup widget to be added
925
926 closePopup()
927 Removes a widget from the list of popup widgets
928 Arguments:
929 QWidget *widget The popup widget to be removed
930 *****************************************************************************/
931
932void QApplicationPrivate::openPopup(QWidget *popup)
933{
934 // @todo implement
935}
936
937void QApplicationPrivate::closePopup(QWidget *popup)
938{
939 // @todo implement
940}
941
942/*****************************************************************************
943 Event translation; translates PM events to Qt events
944 *****************************************************************************/
945
946// State holder for LWIN/RWIN and ALTGr keys
947// (ALTGr is also necessary since OS/2 doesn't report ALTGr as KC_ALT)
948static int qt_extraKeyState = 0;
949
950static int mouseButtonState()
951{
952 int state = 0;
953
954 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)
955 state |= Qt::LeftButton;
956 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000)
957 state |= Qt::RightButton;
958 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000)
959 state |= Qt::MidButton;
960
961 return state;
962}
963
964//
965// Auto-capturing for mouse press and mouse release
966//
967
968static void setAutoCapture(HWND h)
969{
970 if (autoCaptureWnd)
971 releaseAutoCapture();
972 autoCaptureWnd = h;
973
974 if (!mouseButtonState()) {
975 // all buttons released, we don't actually capture the mouse
976 // (see QWidget::translateMouseEvent())
977 autoCaptureReleased = true;
978 } else {
979 autoCaptureReleased = false;
980 WinSetCapture(HWND_DESKTOP, h);
981 }
982}
983
984static void releaseAutoCapture()
985{
986 if (autoCaptureWnd) {
987 if (!autoCaptureReleased) {
988 WinSetCapture(HWND_DESKTOP, NULLHANDLE);
989 autoCaptureReleased = true;
990 }
991 autoCaptureWnd = NULLHANDLE;
992 }
993}
994
995//
996// Mouse event translation
997//
998
999static ushort mouseTbl[] = {
1000 WM_MOUSEMOVE, QEvent::MouseMove, 0,
1001 WM_BUTTON1DOWN, QEvent::MouseButtonPress, Qt::LeftButton,
1002 WM_BUTTON1UP, QEvent::MouseButtonRelease, Qt::LeftButton,
1003 WM_BUTTON1DBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
1004 WM_BUTTON2DOWN, QEvent::MouseButtonPress, Qt::RightButton,
1005 WM_BUTTON2UP, QEvent::MouseButtonRelease, Qt::RightButton,
1006 WM_BUTTON2DBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
1007 WM_BUTTON3DOWN, QEvent::MouseButtonPress, Qt::MidButton,
1008 WM_BUTTON3UP, QEvent::MouseButtonRelease, Qt::MidButton,
1009 WM_BUTTON3DBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
1010 WM_CONTEXTMENU, QEvent::ContextMenu, 0,
1011 0, 0, 0
1012};
1013
1014static int translateButtonState(USHORT s, int type, int button)
1015{
1016 Q_UNUSED(button);
1017
1018 int bst = mouseButtonState();
1019
1020 if (type == QEvent::ContextMenu) {
1021 if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000)
1022 bst |= Qt::ShiftModifier;
1023 if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000)
1024 bst |= Qt::AltModifier;
1025 if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
1026 bst |= Qt::ControlModifier;
1027 } else {
1028 if (s & KC_SHIFT)
1029 bst |= Qt::ShiftModifier;
1030 if ((s & KC_ALT))
1031 bst |= Qt::AltModifier;
1032 if (s & KC_CTRL)
1033 bst |= Qt::ControlModifier;
1034 }
1035 if ((qt_extraKeyState & Qt::AltModifier))
1036 bst |= Qt::AltModifier;
1037 if (qt_extraKeyState & Qt::MetaModifier)
1038 bst |= Qt::MetaModifier;
1039
1040 return bst;
1041}
1042
1043bool QETWidget::translateMouseEvent(const QMSG &qmsg)
1044{
1045#if 0
1046 static const char *msgNames[] = { // 11 items
1047 "WM_MOUSEMOVE",
1048 "WM_BUTTON1DOWN", "WM_BUTTON1UP", "WM_BUTTON1DBLCLK",
1049 "WM_BUTTON2DOWN", "WM_BUTTON2UP", "WM_BUTTON2DBLCLK",
1050 "WM_BUTTON3DOWN", "WM_BUTTON3UP", "WM_BUTTON3DBLCLK",
1051 "WM_???"
1052 };
1053 int msgIdx = qmsg.msg - WM_MOUSEMOVE;
1054 if (msgIdx < 0 || msgIdx > 9)
1055 msgIdx = 10;
1056 qDebug("%s (%04lX): [%08lX/%p:%s] %04hd,%04hd hit=%04hX fl=%04hX",
1057 msgNames[msgIdx], qmsg.msg, qmsg.hwnd, this, widgetName(this),
1058 SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1),
1059 SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2));
1060#endif
1061
1062 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
1063 Q_ASSERT(internalWinId() != NULLHANDLE);
1064
1065 static QPoint pos; // window pos (y flipped)
1066 static POINTL gpos = { -1, -1 }; // global pos (y flipped)
1067 QEvent::Type type; // event parameters
1068 int button;
1069 int state;
1070 int i;
1071
1072 // candidate for the double click event
1073 static HWND dblClickCandidateWin = 0;
1074
1075#if !defined (QT_NO_SESSIONMANAGER)
1076 if (sm_blockUserInput) //block user interaction during session management
1077 return true;
1078#endif
1079
1080 // Compress mouse move events
1081 if (qmsg.msg == WM_MOUSEMOVE) {
1082 QMSG mouseMsg;
1083 mouseMsg.msg = WM_NULL;
1084 while (WinPeekMsg(0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
1085 WM_MOUSEMOVE, PM_NOREMOVE)) {
1086 if (mouseMsg.mp2 != qmsg.mp2)
1087 break; // leave the message in the queue because
1088 // the key state has changed
1089 // Remove the mouse move message
1090 WinPeekMsg(0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
1091 WM_MOUSEMOVE, PM_REMOVE);
1092 }
1093 // Update the passed in QMSG structure with the
1094 // most recent one.
1095 if (mouseMsg.msg != WM_NULL) {
1096 PQMSG pqmsg = (PQMSG)&qmsg;
1097 pqmsg->mp1 = mouseMsg.mp1;
1098 pqmsg->mp2 = mouseMsg.mp2;
1099 pqmsg->time = mouseMsg.time;
1100 pqmsg->ptl.x = (short)SHORT1FROMMP(mouseMsg.mp1);
1101 pqmsg->ptl.y = (short)SHORT2FROMMP(mouseMsg.mp1);
1102 WinMapWindowPoints(pqmsg->hwnd, HWND_DESKTOP, &pqmsg->ptl, 1);
1103 // flip y coordinate
1104 pqmsg->ptl.y = QApplication::desktop()->height() - (pqmsg->ptl.y + 1);
1105 }
1106 }
1107
1108 for (i = 0; mouseTbl[i] && (ULONG)mouseTbl[i] != qmsg.msg; i += 3)
1109 ;
1110 if (!mouseTbl[i])
1111 return true;
1112
1113 type = (QEvent::Type)mouseTbl[++i]; // event type
1114 button = mouseTbl[++i]; // which button
1115 state = translateButtonState(SHORT2FROMMP(qmsg.mp2), type, button); // button state
1116
1117 // It seems, that PM remembers only the WM_BUTTONxDOWN message (instead of
1118 // the WM_BUTTONxDOWN + WM_BUTTONxUP pair) to detect whether the next button
1119 // press should be converted to WM_BUTTONxDBLCLK or not. As a result, the
1120 // window gets WM_BUTTONxDBLCLK even if it didn't receive the preceeding
1121 // WM_BUTTONxUP (this happens if we issue WinSetCapture() on the first
1122 // WM_BUTTONxDOWN), which is obviously wrong and makes problems for QWorkspace
1123 // and QTitleBar system menu handlers that don't expect a double click after
1124 // they opened a popup menu. dblClickCandidateWin is reset to 0 (see a ***
1125 // remmark below) when WinSetCapture is issued that directs messages
1126 // to a window other than one received the first WM_BUTTONxDOWN,
1127 // so we can fix it here. Note that if there is more than one popup window,
1128 // WinSetCapture is issued only for the first of them, so this code doesn't
1129 // prevent MouseButtonDblClick from being delivered to a popup when another
1130 // popup gets closed on the first WM_BUTTONxDOWN (Qt/Win32 behaves in the
1131 // same way, so it's left for compatibility).
1132 if (type == QEvent::MouseButtonPress) {
1133 dblClickCandidateWin = qmsg.hwnd;
1134 } else if (type == QEvent::MouseButtonDblClick) {
1135 if (dblClickCandidateWin != qmsg.hwnd)
1136 type = QEvent::MouseButtonPress;
1137 dblClickCandidateWin = 0;
1138 }
1139
1140 const QPoint widgetPos = mapFromGlobal(QPoint(qmsg.ptl.x, qmsg.ptl.y));
1141
1142 QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos);
1143 if (alienWidget && alienWidget->internalWinId())
1144 alienWidget = 0;
1145
1146 if (type == QEvent::MouseMove) {
1147 if (!(state & Qt::MouseButtonMask))
1148 qt_button_down = 0;
1149#ifndef QT_NO_CURSOR
1150 QCursor *c = qt_grab_cursor();
1151 if (!c)
1152 c = QApplication::overrideCursor();
1153 if (c) // application cursor defined
1154 WinSetPointer(HWND_DESKTOP, c->handle());
1155 else if (!qt_button_down) {
1156 QWidget *w = alienWidget ? alienWidget : this;
1157 while (!w->isWindow() && !w->isEnabled())
1158 w = w->parentWidget();
1159 WinSetPointer(HWND_DESKTOP, w->cursor().handle());
1160 }
1161#else
1162 // pass the msg to the default proc to let it change the pointer shape
1163 WinDefWindowProc(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
1164#endif
1165
1166 HWND id = effectiveWinId();
1167 QWidget *mouseGrabber = QWidget::mouseGrabber();
1168 QWidget *activePopupWidget = qApp->activePopupWidget();
1169 if (mouseGrabber) {
1170 if (!activePopupWidget || (activePopupWidget == this && !rect().contains(widgetPos)))
1171 id = mouseGrabber->effectiveWinId();
1172 } else if (type == QEvent::NonClientAreaMouseMove) {
1173 id = 0;
1174 }
1175
1176 if (curWin != id) { // new current window
1177 // @todo
1178 // add CS_HITTEST to our window classes and handle WM_HITTEST,
1179 // otherwise disabled windows will not get mouse events?
1180 if (id == 0) {
1181 QWidget *leave = qt_last_mouse_receiver;
1182 if (!leave)
1183 leave = QWidget::find(curWin);
1184 QApplicationPrivate::dispatchEnterLeave(0, leave);
1185 qt_last_mouse_receiver = 0;
1186 curWin = 0;
1187 } else {
1188 QWidget *leave = 0;
1189 if (curWin && qt_last_mouse_receiver)
1190 leave = qt_last_mouse_receiver;
1191 else
1192 leave = QWidget::find(curWin);
1193 QWidget *enter = alienWidget ? alienWidget : this;
1194 if (mouseGrabber && activePopupWidget) {
1195 if (leave != mouseGrabber)
1196 enter = mouseGrabber;
1197 else
1198 enter = activePopupWidget == this ? this : mouseGrabber;
1199 }
1200 QApplicationPrivate::dispatchEnterLeave(enter, leave);
1201 qt_last_mouse_receiver = enter;
1202 curWin = enter ? enter->effectiveWinId() : 0;
1203 }
1204 }
1205
1206 // *** PM posts a dummy WM_MOUSEMOVE message (with the same, uncahnged
1207 // pointer coordinates) after every WinSetCapture that actually changes
1208 // the capture target. I.e., if the argument of WinSetCapture is
1209 // NULLHANDLE, a window under the mouse pointer gets this message,
1210 // otherwise the specified window gets it unless it is already under the
1211 // pointer. We use this info to check whether the window can be a double
1212 // click candidate (see above).
1213 if (qmsg.ptl.x == gpos.x && qmsg.ptl.y == gpos.y) {
1214 if (dblClickCandidateWin != qmsg.hwnd)
1215 dblClickCandidateWin = 0;
1216 return true;
1217 }
1218
1219 gpos = qmsg.ptl;
1220
1221 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1222
1223 POINTL curPos = gpos;
1224 WinMapWindowPoints(internalWinId(), HWND_DESKTOP, &gpos, 1);
1225
1226 pos.rx() = curPos.x;
1227 pos.ry() = curPos.y;
1228 pos = d_func()->mapFromWS(pos);
1229 } else {
1230 if (type == QEvent::MouseButtonPress && !isActiveWindow())
1231 setActiveWindow();
1232
1233 gpos = qmsg.ptl;
1234 pos = mapFromGlobal(QPoint(gpos.x, gpos.y));
1235
1236 // mouse button pressed
1237 if (!qt_button_down && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick)) {
1238 QWidget *tlw = window();
1239 if (QWidget *child = tlw->childAt(mapTo(tlw, pos)))
1240 qt_button_down = child;
1241 else
1242 qt_button_down = this;
1243 }
1244 }
1245
1246 // detect special button states
1247 enum { Other, SinglePressed, AllReleased } btnState = Other;
1248 int bs = state & Qt::MouseButtonMask;
1249 if ((type == QEvent::MouseButtonPress ||
1250 type == QEvent::MouseButtonDblClick) && bs == 0) {
1251 btnState = SinglePressed;
1252 } else if (type == QEvent::MouseButtonRelease && bs == button) {
1253 btnState = AllReleased;
1254 }
1255
1256 bool res = false;
1257
1258 if (qApp->d_func()->inPopupMode()) { // in popup mode
1259 if (!autoCaptureReleased && btnState == AllReleased) {
1260 // in order to give non-Qt windows the opportunity to see mouse
1261 // messages while our popups are active we need to release the
1262 // mouse capture which is absolute in OS/2. we do it directly
1263 // (not through releaseAutoCapture()) in order to keep
1264 // autoCaptureWnd nonzero to keep forwarding mouse move events
1265 // (actually sent to one of Qt widgets) to the active popup.
1266 autoCaptureReleased = true;
1267 WinSetCapture(HWND_DESKTOP, 0);
1268 } else if (autoCaptureReleased && btnState == SinglePressed) {
1269 // set the mouse capture back if a button is pressed.
1270 if ( autoCaptureWnd ) {
1271 autoCaptureReleased = false;
1272 WinSetCapture(HWND_DESKTOP, autoCaptureWnd);
1273 }
1274 }
1275
1276 replayPopupMouseEvent = false;
1277 QWidget* activePopupWidget = qApp->activePopupWidget();
1278 QWidget *target = activePopupWidget;
1279 const QPoint globalPos(gpos.x, gpos.y);
1280
1281 if (target != this) {
1282 if ((windowType() == Qt::Popup) && rect().contains(pos) && 0)
1283 target = this;
1284 else // send to last popup
1285 pos = target->mapFromGlobal(globalPos);
1286 }
1287 QWidget *popupChild = target->childAt(pos);
1288 bool releaseAfter = false;
1289 switch (type) {
1290 case QEvent::MouseButtonPress:
1291 case QEvent::MouseButtonDblClick:
1292 popupButtonFocus = popupChild;
1293 break;
1294 case QEvent::MouseButtonRelease:
1295 releaseAfter = true;
1296 break;
1297 default:
1298 break; // nothing for mouse move
1299 }
1300
1301 if (target->isEnabled()) {
1302 if (popupButtonFocus) {
1303 target = popupButtonFocus;
1304 } else if (popupChild) {
1305 // forward mouse events to the popup child. mouse move events
1306 // are only forwarded to popup children that enable mouse tracking.
1307 if (type != QEvent::MouseMove || popupChild->hasMouseTracking())
1308 target = popupChild;
1309 }
1310
1311 pos = target->mapFromGlobal(globalPos);
1312#ifndef QT_NO_CONTEXTMENU
1313 if (type == QEvent::ContextMenu) {
1314 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, state);
1315 res = QApplication::sendSpontaneousEvent(target, &e);
1316 res = res && e.isAccepted();
1317 }
1318 else
1319#endif
1320 {
1321 QMouseEvent e(type, pos, globalPos,
1322 Qt::MouseButton(button),
1323 Qt::MouseButtons(state & Qt::MouseButtonMask),
1324 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
1325 res = QApplicationPrivate::sendMouseEvent(target, &e, alienWidget, this, &qt_button_down,
1326 qt_last_mouse_receiver);
1327 res = res && e.isAccepted();
1328 }
1329 } else {
1330 // close disabled popups when a mouse button is pressed or released
1331 switch (type) {
1332 case QEvent::MouseButtonPress:
1333 case QEvent::MouseButtonDblClick:
1334 case QEvent::MouseButtonRelease:
1335 target->close();
1336 break;
1337 default:
1338 break;
1339 }
1340 }
1341
1342 if (releaseAfter) {
1343 popupButtonFocus = 0;
1344 qt_button_down = 0;
1345 }
1346
1347 if (type == QEvent::MouseButtonPress
1348 && qApp->activePopupWidget() != activePopupWidget
1349 && replayPopupMouseEvent) {
1350 // the popup dissappeared. Replay the event
1351 QWidget* w = QApplication::widgetAt(gpos.x, gpos.y);
1352 if (w && !QApplicationPrivate::isBlockedByModal(w)) {
1353 Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
1354 HWND hwndTarget = w->effectiveWinId();
1355 if (QWidget::mouseGrabber() == 0)
1356 setAutoCapture(hwndTarget);
1357 if (!w->isActiveWindow())
1358 w->activateWindow();
1359 POINTL pt = gpos;
1360 WinMapWindowPoints(HWND_DESKTOP, hwndTarget, &pt, 1);
1361 // flip y coordinate
1362 pt.y = w->height() - (pt.y + 1);
1363 WinPostMsg(hwndTarget, qmsg.msg,
1364 MPFROM2SHORT(pt.x, pt.y), qmsg.mp2);
1365 }
1366 }
1367 } else { // not popup mode
1368 if (btnState == SinglePressed && QWidget::mouseGrabber() == 0) {
1369 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1370 setAutoCapture(internalWinId());
1371 } else if (btnState == AllReleased && QWidget::mouseGrabber() == 0) {
1372 releaseAutoCapture();
1373 }
1374
1375 const QPoint globalPos(gpos.x,gpos.y);
1376 QWidget *widget = QApplicationPrivate::pickMouseReceiver(this, globalPos, pos, type,
1377 Qt::MouseButtons(bs),
1378 qt_button_down, alienWidget);
1379 if (!widget)
1380 return false; // don't send event
1381
1382#ifndef QT_NO_CONTEXTMENU
1383 if (type == QEvent::ContextMenu) {
1384 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, state);
1385 res = QApplication::sendSpontaneousEvent(widget, &e);
1386 res = res && e.isAccepted();
1387 } else
1388#endif
1389 {
1390 QMouseEvent e(type, pos, globalPos, Qt::MouseButton(button),
1391 Qt::MouseButtons(state & Qt::MouseButtonMask),
1392 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
1393
1394 res = QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
1395 qt_last_mouse_receiver);
1396 res = res && e.isAccepted();
1397 }
1398
1399 if (type != QEvent::MouseMove)
1400 pos.rx() = pos.ry() = -9999; // init for move compression
1401 }
1402
1403 return res;
1404}
1405
1406#ifndef QT_NO_WHEELEVENT
1407bool QETWidget::translateWheelEvent(const QMSG &qmsg)
1408{
1409 enum { WHEEL_DELTA = 120 };
1410
1411#ifndef QT_NO_SESSIONMANAGER
1412 if (sm_blockUserInput) // block user interaction during session management
1413 return true;
1414#endif
1415
1416 // consume duplicate wheel events sent by the AMouse driver to emulate
1417 // multiline scrolls. we need this since currently Qt (QScrollBar, for
1418 // instance) maintains the number of lines to scroll per wheel rotation
1419 // (including the special handling of CTRL and SHIFT modifiers) on its own
1420 // and doesn't have a setting to tell it to be aware of system settings
1421 // for the mouse wheel. if we had processed events as they are, we would
1422 // get a confusing behavior (too many lines scrolled etc.).
1423 {
1424 int devh = QApplication::desktop()->height();
1425 QMSG wheelMsg;
1426 while (WinPeekMsg(0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_NOREMOVE)) {
1427 // PM bug: ptl contains SHORT coordinates although fields are LONG
1428 wheelMsg.ptl.x = (short) wheelMsg.ptl.x;
1429 wheelMsg.ptl.y = (short) wheelMsg.ptl.y;
1430 // flip y coordinate
1431 wheelMsg.ptl.y = devh - (wheelMsg.ptl.y + 1);
1432 if (wheelMsg.mp1 != qmsg.mp1 ||
1433 wheelMsg.mp2 != qmsg.mp2 ||
1434 wheelMsg.ptl.x != qmsg.ptl.x ||
1435 wheelMsg.ptl.y != qmsg.ptl.y)
1436 break;
1437 WinPeekMsg(0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_REMOVE);
1438 }
1439 }
1440
1441 int delta;
1442 USHORT cmd = SHORT2FROMMP(qmsg.mp2);
1443 switch (cmd) {
1444 case SB_LINEUP:
1445 case SB_PAGEUP:
1446 delta = WHEEL_DELTA;
1447 break;
1448 case SB_LINEDOWN:
1449 case SB_PAGEDOWN:
1450 delta = -WHEEL_DELTA;
1451 break;
1452 default:
1453 return false;
1454 }
1455
1456 int state = 0;
1457 if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT ) & 0x8000)
1458 state |= Qt::ShiftModifier;
1459 if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000 ||
1460 (qt_extraKeyState & Qt::AltModifier))
1461 state |= Qt::AltModifier;
1462 if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
1463 state |= Qt::ControlModifier;
1464 if (qt_extraKeyState & Qt::MetaModifier)
1465 state |= Qt::MetaModifier;
1466
1467 Qt::Orientation orient;
1468 // Alt inverts scroll orientation (Qt/Win32 behavior)
1469 if (state & Qt::AltModifier)
1470 orient = qmsg.msg == WM_VSCROLL ? Qt::Horizontal : Qt::Vertical;
1471 else
1472 orient = qmsg.msg == WM_VSCROLL ? Qt::Vertical : Qt::Horizontal;
1473
1474 QPoint globalPos(qmsg.ptl.x, qmsg.ptl.y);
1475
1476 // if there is a widget under the mouse and it is not shadowed
1477 // by modality, we send the event to it first
1478 MRESULT rc = FALSE;
1479 QWidget* w = QApplication::widgetAt(globalPos);
1480 if (!w || !qt_try_modal(w, (QMSG*)&qmsg, rc)) {
1481 //synaptics touchpad shows its own widget at this position
1482 //so widgetAt() will fail with that HWND, try child of this widget
1483 w = this->childAt(this->mapFromGlobal(globalPos));
1484 if (!w)
1485 w = this;
1486 }
1487
1488 // send the event to the widget or its ancestors
1489 {
1490 QWidget* popup = qApp->activePopupWidget();
1491 if (popup && w->window() != popup)
1492 popup->close();
1493#ifndef QT_NO_WHEELEVENT
1494 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
1495 Qt::MouseButtons(state & Qt::MouseButtonMask),
1496 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
1497
1498 if (QApplication::sendSpontaneousEvent(w, &e))
1499#else
1500 Q_UNUSED(orient);
1501#endif //QT_NO_WHEELEVENT
1502 return true;
1503 }
1504
1505 // send the event to the widget that has the focus or its ancestors, if different
1506 if (w != qApp->focusWidget() && (w = qApp->focusWidget())) {
1507 QWidget* popup = qApp->activePopupWidget();
1508 if (popup && w->window() != popup)
1509 popup->close();
1510#ifndef QT_NO_WHEELEVENT
1511 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
1512 Qt::MouseButtons(state & Qt::MouseButtonMask),
1513 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
1514 if (QApplication::sendSpontaneousEvent(w, &e))
1515#endif //QT_NO_WHEELEVENT
1516 return true;
1517 }
1518
1519 return false;
1520}
1521#endif
1522
1523//
1524// Paint event translation
1525//
1526bool QETWidget::translatePaintEvent(const QMSG &qmsg)
1527{
1528 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
1529 Q_ASSERT(internalWinId());
1530
1531 HPS displayPS = qt_display_ps();
1532
1533 // Since we don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN bits (see
1534 // qwidget_pm.cpp), we have to validate areas that intersect with our
1535 // children and siblings, taking their clip regions into account.
1536 d_func()->validateObstacles();
1537
1538 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1539
1540 HRGN hrgn = GpiCreateRegion(displayPS, 0, NULL);
1541 LONG rc = WinQueryUpdateRegion(internalWinId(), hrgn);
1542 if (rc == RGN_ERROR) { // The update bounding rect is invalid
1543 GpiDestroyRegion(displayPS, hrgn);
1544 d_func()->hd = NULLHANDLE;
1545 setAttribute(Qt::WA_PendingUpdate, false);
1546 return false;
1547 }
1548
1549 setAttribute(Qt::WA_PendingUpdate, false);
1550
1551 // @todo not sure we need it
1552 const QRegion dirtyInBackingStore(qt_dirtyRegion(this));
1553 // Make sure the invalidated region contains the region we're about to repaint.
1554 // BeginPaint will set the clip to the invalidated region and it is impossible
1555 // to enlarge it afterwards (only shrink it).
1556 if (!dirtyInBackingStore.isEmpty())
1557 WinInvalidateRegion(internalWinId(), dirtyInBackingStore.handle(), FALSE);
1558
1559 RECTL rcl;
1560 d_func()->hd = WinBeginPaint(internalWinId(), 0, &rcl);
1561
1562#if defined(QT_DEBUGMSGFLOW)
1563 qDebug() << " PAINT BEGIN:" << rcl << "hps:" << qStrHPS(d_func()->hd);
1564#endif
1565
1566 // it's possible that the update rectangle is empty
1567 if (rcl.xRight <= rcl.xLeft || rcl.yTop <= rcl.yBottom) {
1568 WinEndPaint(d_func()->hd);
1569 GpiDestroyRegion(displayPS, hrgn);
1570 d_func()->hd = NULLHANDLE;
1571 setAttribute(Qt::WA_PendingUpdate, false);
1572 return true;
1573 }
1574
1575 // flip y coordinate
1576 rcl.yBottom = height() - (rcl.yBottom + 1);
1577 rcl.yTop = height() - (rcl.yTop + 1);
1578
1579 // note: right top point is exlusive in rcl
1580 QRect updRect(QPoint(rcl.xLeft, rcl.yTop + 1),
1581 QPoint(rcl.xRight - 1, rcl.yBottom));
1582
1583 // Mapping region from system to qt (32 bit) coordinate system.
1584 updRect.translate(data->wrect.topLeft());
1585#if defined(QT_DEBUGMSGFLOW)
1586 qDebug() << " PAINT updRect:" << updRect;
1587#endif
1588
1589 // @todo use hrgn here converted to QRegion?
1590 d_func()->syncBackingStore(updRect);
1591
1592 WinEndPaint(d_func()->hd);
1593 d_func()->hd = NULLHANDLE;
1594
1595#if defined(QT_DEBUGMSGFLOW)
1596 qDebug() << " PAINT END";
1597#endif
1598
1599 return true;
1600}
1601
1602//
1603// Window move and resize (configure) events
1604//
1605
1606bool QETWidget::translateConfigEvent(const QMSG &qmsg)
1607{
1608 if (!testAttribute(Qt::WA_WState_Created)) // in QWidget::create()
1609 return true;
1610
1611 if (testAttribute(Qt::WA_WState_ConfigPending)) {
1612 // it's possible that we're trying to set the frame size smaller
1613 // than it possible for WC_FRAME in QWidget::setGeometry_sys().
1614 // here we correct this (crect there is set before WinSetWindowPos()
1615 // that sends WM_SIZE).
1616 QSize newSize(SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2));
1617 if (qmsg.msg == WM_SIZE && size() != newSize)
1618 data->crect.setSize(newSize);
1619 return true;
1620 }
1621
1622 if (testAttribute(Qt::WA_DontShowOnScreen))
1623 return true;
1624 // @todo check if this is actually called for !isWindow() widget
1625// if (!isWindow())
1626// return true;
1627
1628 // When the window is minimized, PM moves it to -32000,-32000 and resizes
1629 // to 48x50. We don't want these useless actions to be seen by Qt.
1630 if (isMinimized())
1631 return true;
1632
1633 setAttribute(Qt::WA_WState_ConfigPending); // set config flag
1634
1635 HWND fId = NULLHANDLE;
1636 ULONG fStyle = 0;
1637 if (isWindow()) {
1638 fId = d_func()->frameWinId();
1639 fStyle = WinQueryWindowULong(fId, QWL_STYLE);
1640 }
1641
1642 if (qmsg.msg == WM_SIZE) { // resize event
1643 QSize oldSize = data->crect.size();
1644 QSize newSize = QSize(SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2));
1645 data->crect.setSize(newSize);
1646 if (isWindow()) { // update title/icon text
1647 d_func()->createTLExtra();
1648 QString title;
1649 if ((fStyle & WS_MINIMIZED))
1650 title = windowIconText();
1651 if (title.isEmpty())
1652 title = windowTitle();
1653 if (!title.isEmpty())
1654 d_func()->setWindowTitle_helper(title);
1655 }
1656 if (oldSize != newSize) {
1657 // Spontaneous (external to Qt) WM_SIZE messages should occur only
1658 // on top-level widgets. If we get them for a non top-level widget,
1659 // the result will most likely be incorrect because widget masks will
1660 // not be properly processed (i.e. in the way it is done in
1661 // QWidget::setGeometry_sys() when the geometry is changed from
1662 // within Qt). So far, I see no need to support this (who will ever
1663 // need to move a non top-level window of a foreign process?).
1664 Q_ASSERT(isWindow());
1665 if (isVisible()) {
1666 QTLWExtra *tlwExtra = d_func()->maybeTopData();
1667 static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
1668 const bool hasStaticContents = tlwExtra && tlwExtra->backingStore
1669 && tlwExtra->backingStore->hasStaticContents();
1670 // If we have a backing store with static contents, we have to disable the top-level
1671 // resize optimization in order to get invalidated regions for resized widgets.
1672 // The optimization discards all invalidateBuffer() calls since we're going to
1673 // repaint everything anyways, but that's not the case with static contents.
1674 if (!slowResize && tlwExtra && !hasStaticContents)
1675 tlwExtra->inTopLevelResize = true;
1676 QResizeEvent e(newSize, oldSize);
1677 QApplication::sendSpontaneousEvent(this, &e);
1678 if (d_func()->paintOnScreen()) {
1679 QRegion updateRegion(rect());
1680 if (testAttribute(Qt::WA_StaticContents))
1681 updateRegion -= QRect(0, 0, oldSize.width(), oldSize.height());
1682 // syncBackingStore() should have already flushed the widget
1683 // contents to the screen, so no need to redraw the exposed
1684 // areas in WM_PAINT once more
1685 d_func()->syncBackingStore(updateRegion);
1686 WinValidateRegion(internalWinId(),
1687 updateRegion.handle(newSize.height()), FALSE);
1688 } else {
1689 d_func()->syncBackingStore();
1690 // see above
1691 RECTL rcl = { 0, 0, newSize.width(), newSize.height() };
1692 WinValidateRect(internalWinId(), &rcl, FALSE);
1693 }
1694 if (!slowResize && tlwExtra)
1695 tlwExtra->inTopLevelResize = false;
1696 } else {
1697 QResizeEvent *e = new QResizeEvent(newSize, oldSize);
1698 QApplication::postEvent(this, e);
1699 }
1700 }
1701 } else if (qmsg.msg == WM_MOVE) { // move event
1702 QPoint oldPos = data->crect.topLeft();
1703 SWP swp;
1704 if (isWindow()) {
1705 WinQueryWindowPos(fId, &swp);
1706 // flip y coordinate
1707 swp.y = QApplication::desktop()->height() - (swp.y + swp.cy);
1708 QTLWExtra *top = d_func()->topData();
1709 swp.x += top->frameStrut.left();
1710 swp.y += top->frameStrut.top();
1711 } else {
1712 WinQueryWindowPos(internalWinId(), &swp);
1713 // flip y coordinate
1714 swp.y = parentWidget()->height() - (swp.y + swp.cy);
1715 }
1716 QPoint newCPos(swp.x, swp.y);
1717 if (newCPos != oldPos) {
1718 data->crect.moveTopLeft(newCPos);
1719 if (isVisible()) {
1720 QMoveEvent e(newCPos, oldPos); // cpos (client position)
1721 QApplication::sendSpontaneousEvent(this, &e);
1722 } else {
1723 QMoveEvent *e = new QMoveEvent(newCPos, oldPos);
1724 QApplication::postEvent(this, e);
1725 }
1726 }
1727 }
1728 setAttribute(Qt::WA_WState_ConfigPending, false); // clear config flag
1729 return true;
1730}
1731
1732//
1733// Close window event translation.
1734//
1735// This class is a friend of QApplication because it needs to emit the
1736// lastWindowClosed() signal when the last top level widget is closed.
1737//
1738
1739bool QETWidget::translateCloseEvent(const QMSG &)
1740{
1741 return d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
1742}
1743
1744
1745/*!
1746 Returns a QWidget pointer or 0 if there is no widget corresponding to the
1747 given HWND. As opposed to QWidget::find(), correctly handles WC_FRAME
1748 windows created for top level widgets. Used for debugging.
1749 */
1750QWidget *qWidgetFromHWND(HWND hwnd)
1751{
1752 char buf[10];
1753 if (WinQueryClassName(hwnd, sizeof(buf), buf)) {
1754 if (!strcmp(buf, "#1")) // WC_FRAME
1755 hwnd = WinWindowFromID(hwnd, FID_CLIENT);
1756 return QWidget::find(hwnd);
1757 }
1758 return 0;
1759}
1760
1761/*!
1762 \internal
1763
1764 Returns a human readable widget name in the form "class/name". Used for
1765 debugging.
1766 */
1767QDbgStr qWidgetName(QWidget *w)
1768{
1769 if (w)
1770 return QString()
1771 .sprintf("%s.%s", w->metaObject()->className(),
1772 w->objectName().isEmpty() ? "<noname>" :
1773 w->objectName().toUtf8().constData());
1774 return QString(QLatin1String("<no-widget>"));
1775}
1776
1777/*****************************************************************************
1778 PM struct/message debug helpers
1779 *****************************************************************************/
1780
1781typedef QLatin1String QCStr;
1782
1783#define myDefFlagEx(var,fl,varstr,flstr) if (var & fl) { \
1784 if (!varstr.isEmpty()) varstr += QCStr("|"); varstr += QCStr(flstr); \
1785} else do {} while(0)
1786
1787#define myDefFlag(var,fl,varstr) myDefFlagEx(var,fl,varstr,#fl)
1788#define myDefFlagCut(var,fl,varstr,pos) myDefFlagEx(var,fl,varstr,#fl + pos)
1789
1790QDbgStr qStrHWND(HWND hwnd)
1791{
1792 return QString().sprintf("%08lX/", hwnd) +
1793 qWidgetName(qWidgetFromHWND(hwnd));
1794}
1795
1796QDbgStr qStrHPS(HPS hps)
1797{
1798 return QString().sprintf("%08lX", hps);
1799}
1800
1801QDbgStr qStrHPOINTER(HPOINTER hptr)
1802{
1803 return QString().sprintf("%08lX", hptr);
1804}
1805
1806QDbgStr qStrHRGN(HRGN hrgn)
1807{
1808 return QString().sprintf("%08lX", hrgn);
1809}
1810
1811QDbgStr qStrQMSG(const QMSG &qmsg)
1812{
1813 QString str;
1814
1815 #define myCaseBegin(a) case a: { \
1816 str = QString().sprintf(#a ": hwnd %08lX.", qmsg.hwnd); \
1817 str += qWidgetName(qWidgetFromHWND(qmsg.hwnd));
1818 #define myCaseEnd() }
1819
1820 switch (qmsg.msg) {
1821
1822 myCaseBegin(WM_PAINT)
1823 break;
1824 myCaseEnd()
1825
1826 myCaseBegin(WM_SIZE)
1827 str += QString().
1828 sprintf(" old (%hd,%hd) new (%hd,%hd)",
1829 SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1),
1830 SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2));
1831 SWP swp;
1832 WinQueryWindowPos(qmsg.hwnd, &swp);
1833 str += QCStr(" ") + qStrSWP(swp);
1834 HWND p = WinQueryWindow(qmsg.hwnd, QW_PARENT);
1835 if (p != NULLHANDLE && p != WinQueryDesktopWindow(0, 0)) {
1836 WinQueryWindowPos(p, &swp);
1837 str += QCStr(" p ") + qStrSWP(swp);
1838 }
1839 break;
1840 myCaseEnd()
1841
1842 myCaseBegin(WM_MOVE)
1843 SWP swp;
1844 WinQueryWindowPos(qmsg.hwnd, &swp);
1845 str += QCStr(" ") + qStrSWP(swp);
1846 HWND p = WinQueryWindow(qmsg.hwnd, QW_PARENT);
1847 if (p != NULLHANDLE && p != WinQueryDesktopWindow(0, 0)) {
1848 WinQueryWindowPos(p, &swp);
1849 str += QCStr(" p ") + qStrSWP(swp);
1850 }
1851 break;
1852 myCaseEnd()
1853
1854 myCaseBegin(WM_WINDOWPOSCHANGED)
1855 str += QCStr(" ") + qStrSWP(*((PSWP) qmsg.mp1));
1856 ULONG awp = LONGFROMMP(qmsg.mp2);
1857 QString awpstr;
1858 myDefFlagEx(awp, AWP_MINIMIZED, awpstr, "MIN");
1859 myDefFlagEx(awp, AWP_MAXIMIZED, awpstr, "MAX");
1860 myDefFlagEx(awp, AWP_RESTORED, awpstr, "REST");
1861 myDefFlagEx(awp, AWP_ACTIVATE, awpstr, "ACT");
1862 myDefFlagEx(awp, AWP_DEACTIVATE, awpstr, "DEACT");
1863 str += QCStr(" AWP(") + awpstr + QCStr(")");
1864 break;
1865 myCaseEnd()
1866
1867 myCaseBegin(WM_MINMAXFRAME)
1868 str += QCStr(" ") + qStrSWP(*((PSWP) qmsg.mp1));
1869 break;
1870 myCaseEnd()
1871
1872 default:
1873 break;
1874 }
1875
1876 return str;
1877
1878 #undef myCaseEnd
1879 #undef myCaseBegin
1880}
1881
1882QDbgStr qStrRECTL(const RECTL &rcl)
1883{
1884 return QString().sprintf("RECTL(%ld,%ld %ld,%ld)",
1885 rcl.xLeft, rcl.yBottom, rcl.xRight, rcl.yTop);
1886}
1887
1888QDbgStr qStrSWP(const SWP &swp)
1889{
1890 QString fl;
1891 myDefFlagEx(swp.fl, SWP_SHOW, fl, "SHOW");
1892 myDefFlagEx(swp.fl, SWP_HIDE, fl, "HIDE");
1893 myDefFlagEx(swp.fl, SWP_ACTIVATE, fl, "ACT");
1894 myDefFlagEx(swp.fl, SWP_DEACTIVATE, fl, "DEACT");
1895 myDefFlagEx(swp.fl, SWP_MAXIMIZE, fl, "MAX");
1896 myDefFlagEx(swp.fl, SWP_MINIMIZE, fl, "MIN");
1897 myDefFlagEx(swp.fl, SWP_RESTORE, fl, "REST");
1898 myDefFlagEx(swp.fl, SWP_MOVE, fl, "MOVE");
1899 myDefFlagEx(swp.fl, SWP_SIZE, fl, "SIZE");
1900 myDefFlagEx(swp.fl, SWP_ZORDER, fl, "ZORD");
1901
1902 return QString().sprintf("SWP(%ld,%ld %ldx%ld %08lX ",
1903 swp.x, swp.y, swp.cx, swp.cy, swp.hwndInsertBehind) +
1904 fl + QLatin1String(")");
1905}
1906
1907#undef myDefFlagCut
1908#undef myDefFlag
1909#undef myDefFlagEx
1910
1911QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.