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

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

gui: Added modality implementation.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Date Revision Author Id
File size: 48.0 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 "qapplication.h"
47#include "qapplication_p.h"
48
49#include "qwidget.h"
50#include "qpointer.h"
51#include "qcolormap.h"
52#include "qpixmapcache.h"
53#include "qdesktopwidget.h"
54
55#include "qset.h"
56
57#include "private/qeventdispatcher_pm_p.h"
58
59#include "qwidget_p.h"
60#include "qkeymapper_p.h"
61#include "qcursor_p.h"
62
63QT_BEGIN_NAMESPACE
64
65/*****************************************************************************
66 Internal variables and functions
67 *****************************************************************************/
68
69static HWND curWin = 0; // current window
70static HPS displayPS = 0; // display presentation space
71
72#if !defined (QT_NO_SESSIONMANAGER)
73
74// Session management
75static bool sm_blockUserInput = FALSE;
76
77//#define DEBUG_SESSIONMANAGER
78
79#endif
80
81static bool replayPopupMouseEvent = false; // replay handling when popups close
82
83// ignore the next release event if return from a modal widget
84static bool ignoreNextMouseReleaseEvent = false;
85
86#if defined(QT_DEBUG)
87static bool appNoGrab = false; // mouse/keyboard grabbing
88#endif
89
90static bool app_do_modal = false; // modal mode
91extern QWidgetList *qt_modal_stack;
92extern QDesktopWidget *qt_desktopWidget;
93static QPointer<QWidget> popupButtonFocus;
94static bool qt_try_modal(QWidget*, QMSG*, MRESULT&);
95
96QWidget *qt_button_down = 0; // widget got last button-down
97QPointer<QWidget> qt_last_mouse_receiver = 0;
98
99static HWND autoCaptureWnd = NULLHANDLE;
100static bool autoCaptureReleased = FALSE;
101static void setAutoCapture(HWND); // automatic capture
102static void releaseAutoCapture();
103
104extern QCursor *qt_grab_cursor();
105
106extern void qt_WinQueryClipRegionOrRect(HWND hwnd, HRGN hrgn); // qwidget_pm.cpp
107
108MRESULT EXPENTRY QtWndProc(HWND, ULONG, MPARAM, MPARAM);
109
110class QETWidget : public QWidget // event translator widget
111{
112public:
113 QWExtra *xtra() { return d_func()->extraData(); }
114 QTLWExtra *topData() { return d_func()->topData(); }
115// @todo later
116// QTLWExtra *maybeTopData() { return d_func()->maybeTopData(); }
117// void syncBackingStore(const QRegion &rgn) { d_func()->syncBackingStore(rgn); }
118// void syncBackingStore() { d_func()->syncBackingStore(); }
119// QWidgetData *dataPtr() { return data; }
120// QWidgetPrivate *dptr() { return d_func(); }
121// QRect frameStrut() const { return d_func()->frameStrut(); }
122 bool pmEvent(QMSG *m, MRESULT *r) { return QWidget::pmEvent(m, r); }
123// void markFrameStrutDirty() { data->fstrut_dirty = 1; }
124 bool translateMouseEvent(const QMSG &qmsg);
125#ifndef QT_NO_WHEELEVENT
126 bool translateWheelEvent(const QMSG &qmsg);
127#endif
128 bool translatePaintEvent(const QMSG &qmsg);
129// bool translateConfigEvent(const QMSG &msg);
130 bool translateCloseEvent(const QMSG &qmsg);
131// void repolishStyle(QStyle &style);
132// inline void showChildren(bool spontaneous) { d_func()->showChildren(spontaneous); }
133// inline void hideChildren(bool spontaneous) { d_func()->hideChildren(spontaneous); }
134// inline uint testWindowState(uint teststate){ return dataPtr()->window_state & teststate; }
135// inline void forceUpdate() {
136// QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
137// if (tlwExtra && tlwExtra->backingStore)
138// tlwExtra->backingStore->markDirty(rect(), this, true, true);
139// }
140};
141
142static void qt_set_pm_resources()
143{
144 // @todo later: take colors, fonts, etc. from the system theme
145};
146
147/*****************************************************************************
148 qt_init() - initializes Qt for PM
149 *****************************************************************************/
150
151void qt_init(QApplicationPrivate *priv, int)
152{
153
154 int argc = priv->argc;
155 char **argv = priv->argv;
156 int i, j;
157
158 // Get command line params
159
160 j = argc ? 1 : 0;
161 for (i=1; i<argc; i++) {
162 if (argv[i] && *argv[i] != '-') {
163 argv[j++] = argv[i];
164 continue;
165 }
166#if defined(QT_DEBUG)
167 if (qstrcmp(argv[i], "-nograb") == 0)
168 appNoGrab = !appNoGrab;
169 else
170#endif // QT_DEBUG
171 argv[j++] = argv[i];
172 }
173 if(j < priv->argc) {
174 priv->argv[j] = 0;
175 priv->argc = j;
176 }
177
178 // initialize key mapper
179 QKeyMapper::changeKeyboard();
180
181 QColormap::initialize();
182 QFont::initialize();
183#ifndef QT_NO_CURSOR
184 QCursorData::initialize();
185#endif
186 qApp->setObjectName(priv->appName());
187
188 // default font
189 QApplicationPrivate::setSystemFont(
190 QFont(QLatin1String("System Proportional"), 10));
191
192 // QFont::locale_init(); ### Uncomment when it does something on OS/2
193
194 if (QApplication::desktopSettingsAware())
195 qt_set_pm_resources();
196}
197
198/*****************************************************************************
199 qt_cleanup() - cleans up when the application is finished
200 *****************************************************************************/
201
202void qt_cleanup()
203{
204 QPixmapCache::clear();
205
206#ifndef QT_NO_CURSOR
207 QCursorData::cleanup();
208#endif
209 QFont::cleanup();
210 QColormap::cleanup();
211
212 if (displayPS) {
213 WinReleasePS(displayPS);
214 displayPS = 0;
215 }
216}
217
218/*****************************************************************************
219 Platform specific global and internal functions
220 *****************************************************************************/
221
222Q_GUI_EXPORT HPS qt_display_ps()
223{
224 Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
225 if (!displayPS)
226 displayPS = WinGetScreenPS(HWND_DESKTOP);
227 return displayPS;
228}
229
230// application no-grab option
231bool qt_nograb()
232{
233#if defined(QT_DEBUG)
234 return appNoGrab;
235#else
236 return false;
237#endif
238}
239
240/*****************************************************************************
241 Safe configuration (move,resize,setGeometry) mechanism to avoid
242 recursion when processing messages.
243 *****************************************************************************/
244
245struct QPMConfigRequest {
246 WId id; // widget to be configured
247 int req; // 0=move, 1=resize, 2=setGeo
248 int x, y, w, h; // request parameters
249};
250
251Q_GLOBAL_STATIC(QList<QPMConfigRequest*>, configRequests);
252
253void qPMRequestConfig(WId id, int req, int x, int y, int w, int h)
254{
255 QPMConfigRequest *r = new QPMConfigRequest;
256 r->id = id;
257 r->req = req;
258 r->x = x;
259 r->y = y;
260 r->w = w;
261 r->h = h;
262 configRequests()->append(r);
263}
264
265/*****************************************************************************
266 GUI event dispatcher
267 *****************************************************************************/
268
269class QGuiEventDispatcherPM : public QEventDispatcherPM
270{
271public:
272 QGuiEventDispatcherPM(QObject *parent = 0);
273 bool processEvents(QEventLoop::ProcessEventsFlags flags);
274};
275
276QGuiEventDispatcherPM::QGuiEventDispatcherPM(QObject *parent)
277 : QEventDispatcherPM(parent)
278{
279 // pre-create the message queue early as we'll need it anyway in GUI mode
280 createMsgQueue();
281}
282
283bool QGuiEventDispatcherPM::processEvents(QEventLoop::ProcessEventsFlags flags)
284{
285 if (!QEventDispatcherPM::processEvents(flags))
286 return false;
287
288 QPMConfigRequest *r;
289 for (;;) {
290 if (configRequests()->isEmpty())
291 break;
292 r = configRequests()->takeLast();
293 QWidget *w = QWidget::find(r->id);
294 QRect rect(r->x, r->y, r->w, r->h);
295 int req = r->req;
296 delete r;
297
298 if (w) { // widget exists
299 if (w->testAttribute(Qt::WA_WState_ConfigPending))
300 break; // biting our tail
301 if (req == 0)
302 w->move(rect.topLeft());
303 else if (req == 1)
304 w->resize(rect.size());
305 else
306 w->setGeometry(rect);
307 }
308 }
309
310 return true;
311}
312
313void QApplicationPrivate::createEventDispatcher()
314{
315 Q_Q(QApplication);
316 if (q->type() != QApplication::Tty)
317 eventDispatcher = new QGuiEventDispatcherPM(q);
318 else
319 eventDispatcher = new QEventDispatcherPM(q);
320}
321
322/*****************************************************************************
323 Platform specific QApplication members
324 *****************************************************************************/
325
326void QApplicationPrivate::initializeWidgetPaletteHash()
327{
328}
329
330QString QApplicationPrivate::appName() const
331{
332 return QCoreApplicationPrivate::appName();
333}
334
335void QApplication::setCursorFlashTime(int msecs)
336{
337 WinSetSysValue(HWND_DESKTOP, SV_CURSORRATE, msecs / 2);
338 QApplicationPrivate::cursor_flash_time = msecs;
339}
340
341int QApplication::cursorFlashTime()
342{
343 int blink = (int)WinQuerySysValue(HWND_DESKTOP, SV_CURSORRATE);
344 if (!blink)
345 return QApplicationPrivate::cursor_flash_time;
346 if (blink > 0)
347 return 2 * blink;
348 return 0;
349}
350
351void QApplication::setDoubleClickInterval(int ms)
352{
353 WinSetSysValue(HWND_DESKTOP, SV_DBLCLKTIME, ms);
354 QApplicationPrivate::mouse_double_click_time = ms;
355}
356
357int QApplication::doubleClickInterval()
358{
359 int ms = (int) WinQuerySysValue(HWND_DESKTOP, SV_DBLCLKTIME);
360 if (ms != 0)
361 return ms;
362 return QApplicationPrivate::mouse_double_click_time;
363}
364
365void QApplication::setKeyboardInputInterval(int ms)
366{
367 QApplicationPrivate::keyboard_input_time = ms;
368}
369
370int QApplication::keyboardInputInterval()
371{
372 // FIXME: get from the system
373 return QApplicationPrivate::keyboard_input_time;
374}
375
376#ifndef QT_NO_WHEELEVENT
377void QApplication::setWheelScrollLines(int n)
378{
379 QApplicationPrivate::wheel_scroll_lines = n;
380}
381
382int QApplication::wheelScrollLines()
383{
384 return QApplicationPrivate::wheel_scroll_lines;
385}
386#endif //QT_NO_WHEELEVENT
387
388void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
389{
390 // @todo implement
391}
392
393bool QApplication::isEffectEnabled(Qt::UIEffect effect)
394{
395 // @todo implement
396 return false;
397}
398
399void QApplication::beep()
400{
401 WinAlarm(HWND_DESKTOP, WA_WARNING);
402}
403
404void QApplication::alert(QWidget *widget, int duration)
405{
406 // @todo implement
407}
408
409/*****************************************************************************
410 QApplication cursor stack
411 *****************************************************************************/
412
413#ifndef QT_NO_CURSOR
414
415void QApplication::setOverrideCursor(const QCursor &cursor)
416{
417 // @todo implement
418}
419
420void QApplication::restoreOverrideCursor()
421{
422 // @todo implement
423}
424
425#endif
426
427/*****************************************************************************
428 Routines to find a Qt widget from a screen position
429 *****************************************************************************/
430
431QWidget *QApplication::topLevelAt(const QPoint &pos)
432{
433 // @todo implement
434 return 0;
435}
436
437/*****************************************************************************
438 Main event loop
439 *****************************************************************************/
440
441// sent to hwnd that has been entered to by a mouse pointer.
442// FID_CLIENT also receives enter messages of its WC_FRAME.
443// mp1 = hwnd that is entered, mp2 = hwnd that is left
444#define WM_U_MOUSEENTER 0x41E
445// sent to hwnd that has been left by a mouse pointer.
446// FID_CLIENT also receives leave messages of its WC_FRAME.
447// mp1 = hwnd that is left, mp2 = hwnd that is entered
448#define WM_U_MOUSELEAVE 0x41F
449
450// some undocumented system values
451#define SV_WORKAREA_YTOP 51
452#define SV_WORKAREA_YBOTTOM 52
453#define SV_WORKAREA_XRIGHT 53
454#define SV_WORKAREA_XLEFT 54
455
456// QtWndProc() receives all messages from the main event loop
457
458MRESULT EXPENTRY QtWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
459{
460 do {
461 if (!qApp) // unstable app state
462 break;
463#if 0
464 // make sure we show widgets (e.g. scrollbars) when the user resizes
465 if (qApp->loopLevel())
466 qApp->sendPostedEvents(0, QEvent::ShowWindowRequest);
467#endif
468
469 MRESULT rc = (MRESULT) FALSE;
470 QETWidget *widget = 0;
471
472 bool isTranslatableMouseEvent =
473 (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
474 (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST);
475
476 QMSG qmsg; // create QMSG structure
477 qmsg.hwnd = hwnd;
478 qmsg.msg = msg;
479 qmsg.mp1 = mp1;
480 qmsg.mp2 = mp2;
481 qmsg.time = WinQueryMsgTime(0);
482
483 if (isTranslatableMouseEvent || msg == WM_CONTEXTMENU) {
484 qmsg.ptl.x = (short)SHORT1FROMMP(mp1);
485 qmsg.ptl.y = (short)SHORT2FROMMP(mp1);
486 WinMapWindowPoints(qmsg.hwnd, HWND_DESKTOP, &qmsg.ptl, 1);
487 } else {
488 WinQueryMsgPos(0, &qmsg.ptl);
489 }
490 // flip y coordinate
491 qmsg.ptl.y = QApplication::desktop()->height() - (qmsg.ptl.y + 1);
492
493 // send through app filter
494 if (qApp->filterEvent(&qmsg, reinterpret_cast<long *>(&rc)))
495 return rc;
496
497 switch(msg) {
498
499 case WM_BUTTON1DOWN:
500 case WM_BUTTON2DOWN:
501 case WM_BUTTON3DOWN:
502 if (ignoreNextMouseReleaseEvent)
503 ignoreNextMouseReleaseEvent = false;
504 break;
505 case WM_BUTTON1UP:
506 case WM_BUTTON2UP:
507 case WM_BUTTON3UP:
508 if (ignoreNextMouseReleaseEvent) {
509 ignoreNextMouseReleaseEvent = false;
510 if (qt_button_down && qt_button_down->internalWinId() == autoCaptureWnd) {
511 releaseAutoCapture();
512 qt_button_down = 0;
513 }
514 return (MRESULT)TRUE;
515 }
516 break;
517
518 default:
519 break;
520 }
521
522 if (!widget)
523 widget = (QETWidget*)QWidget::find(hwnd);
524 if (!widget) // don't know this widget
525 break;
526
527 if (app_do_modal) { // modal event handling
528 if (!qt_try_modal(widget, &qmsg, rc))
529 return rc;
530 }
531
532 if (widget->pmEvent(&qmsg, &rc)) // send through widget filter
533 return rc;
534
535 if (isTranslatableMouseEvent) {
536 if (qApp->activePopupWidget() != 0) { // in popup mode
537 QWidget *w = QApplication::widgetAt(qmsg.ptl.x, qmsg.ptl.y);
538 if (w) {
539 POINTL ptl = { SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1) };
540 WinMapWindowPoints(qmsg.hwnd, w->winId(), &ptl, 1);
541 qmsg.mp1 = MPFROM2SHORT(ptl.x, ptl.y);
542 widget = (QETWidget*)w;
543 }
544 }
545 if (widget->translateMouseEvent(qmsg)) // mouse event
546 return (MRESULT)TRUE;
547#ifndef QT_NO_WHEELEVENT
548 } else if (msg == WM_VSCROLL || msg == WM_HSCROLL) {
549 if (widget->translateWheelEvent(qmsg))
550 return (MRESULT)TRUE;
551#endif
552#ifndef QT_NO_DRAGANDDROP
553 } else if (msg >= WM_DRAGFIRST && msg <= WM_DRAGLAST) {
554 return qt_dispatchDragAndDrop(widget, qmsg);
555#endif
556 } else {
557 switch(msg) {
558
559 case WM_SHOW: {
560 // @todo there is some more processing in Qt4, see
561 // WM_SHOWWINDOW in qapplication_win.cpp
562 if (!SHORT1FROMMP(mp1) && autoCaptureWnd == widget->internalWinId())
563 releaseAutoCapture();
564 break;
565 }
566
567 case WM_CLOSE: { // close window
568 widget->translateCloseEvent(qmsg);
569 return (MRESULT)TRUE;
570 }
571
572 case WM_DESTROY: { // destroy window
573 if (hwnd == curWin) {
574 QWidget *enter = QWidget::mouseGrabber();
575 if (enter == widget)
576 enter = 0;
577 QApplicationPrivate::dispatchEnterLeave(enter, widget);
578 curWin = enter ? enter->effectiveWinId() : 0;
579 qt_last_mouse_receiver = enter;
580 }
581 if (widget == popupButtonFocus)
582 popupButtonFocus = 0;
583 break;
584 }
585
586#ifndef QT_NO_CONTEXTMENU
587 case WM_CONTEXTMENU: {
588 if (SHORT2FROMMP(mp2)) {
589 // keyboard event
590 QWidget *fw = qApp->focusWidget();
591 if (fw && fw->isEnabled()) {
592 QContextMenuEvent e(QContextMenuEvent::Keyboard,
593 QPoint(5, 5),
594 fw->mapToGlobal(QPoint(5, 5)), 0);
595 if (qt_sendSpontaneousEvent(fw, &e))
596 return (MRESULT)TRUE;
597 }
598 } else {
599 // mouse event
600 if (widget->translateMouseEvent(qmsg))
601 return (MRESULT)TRUE;
602 }
603 break;
604 }
605#endif
606
607 case WM_U_MOUSELEAVE: {
608 // We receive a mouse leave for curWin, meaning
609 // the mouse was moved outside our widgets
610 if (widget->internalWinId() == curWin) {
611 bool dispatch = !widget->underMouse();
612 // hasMouse is updated when dispatching enter/leave,
613 // so test if it is actually up-to-date
614 if (!dispatch) {
615 QRect geom = widget->geometry();
616 if (widget->parentWidget() && !widget->isWindow()) {
617 QPoint gp = widget->parentWidget()->mapToGlobal(widget->pos());
618 geom.setX(gp.x());
619 geom.setY(gp.y());
620 }
621 QPoint cpos = QCursor::pos();
622 dispatch = !geom.contains(cpos);
623 if ( !dispatch && !QWidget::mouseGrabber()) {
624 QWidget *hittest = QApplication::widgetAt(cpos);
625 dispatch = !hittest || hittest->internalWinId() != curWin;
626 }
627 if (!dispatch) {
628 HPS hps = qt_display_ps();
629 HRGN hrgn = GpiCreateRegion(hps, 0, NULL);
630 qt_WinQueryClipRegionOrRect(hwnd, hrgn);
631 QPoint lcpos = widget->mapFromGlobal(cpos);
632 // flip y coordinate
633 POINTL pt = { lcpos.x(), widget->height() - (lcpos.y() + 1) };
634 dispatch = !GpiPtInRegion(hps, hrgn, &pt);
635 GpiDestroyRegion(hps, hrgn);
636 }
637 }
638 if (dispatch) {
639 if (qt_last_mouse_receiver && !qt_last_mouse_receiver->internalWinId())
640 QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
641 else
642 QApplicationPrivate::dispatchEnterLeave(0, QWidget::find((WId)curWin));
643 curWin = 0;
644 qt_last_mouse_receiver = 0;
645 }
646 }
647 break;
648 }
649
650 default:
651 break;
652 }
653 }
654
655 } while(0);
656
657 return WinDefWindowProc(hwnd, msg, mp1, mp2);
658}
659
660PFNWP QtOldFrameProc = 0;
661
662MRESULT EXPENTRY QtFrameProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
663{
664 do {
665 if (!qApp) // unstable app state
666 break;
667#if 0
668 // make sure we show widgets (e.g. scrollbars) when the user resizes
669 if (qApp->loopLevel())
670 qApp->sendPostedEvents(0, QEvent::ShowWindowRequest);
671#endif
672
673 HWND hwndC = WinWindowFromID(hwnd, FID_CLIENT);
674 QETWidget *widget = (QETWidget*)QWidget::find(hwndC);
675 if (!widget) // don't know this widget
676 break;
677
678 switch(msg) {
679 default:
680 break;
681 }
682 } while(0);
683
684 return QtOldFrameProc(hwnd, msg, mp1, mp2);
685}
686
687/*****************************************************************************
688 Modal widgets; We have implemented our own modal widget mechanism
689 to get total control.
690 A modal widget without a parent becomes application-modal.
691 A modal widget with a parent becomes modal to its parent and grandparents..
692
693 QApplicationPrivate::enterModal()
694 Enters modal state
695 Arguments:
696 QWidget *widget A modal widget
697
698 QApplicationPrivate::leaveModal()
699 Leaves modal state for a widget
700 Arguments:
701 QWidget *widget A modal widget
702 *****************************************************************************/
703
704bool QApplicationPrivate::modalState()
705{
706 return app_do_modal;
707}
708
709void QApplicationPrivate::enterModal_sys(QWidget *widget)
710{
711 if (!qt_modal_stack)
712 qt_modal_stack = new QWidgetList;
713
714 releaseAutoCapture();
715 QWidget *leave = qt_last_mouse_receiver;
716 if (!leave)
717 leave = QWidget::find(curWin);
718 QApplicationPrivate::dispatchEnterLeave(0, leave);
719 qt_modal_stack->insert(0, widget);
720 app_do_modal = true;
721 curWin = 0;
722 qt_last_mouse_receiver = 0;
723 ignoreNextMouseReleaseEvent = false;
724}
725
726void QApplicationPrivate::leaveModal_sys(QWidget *widget)
727{
728 if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
729 if (qt_modal_stack->isEmpty()) {
730 delete qt_modal_stack;
731 qt_modal_stack = 0;
732 QPoint p(QCursor::pos());
733 app_do_modal = false; // necessary, we may get recursively into qt_try_modal below
734 QWidget* w = QApplication::widgetAt(p.x(), p.y());
735 QWidget *leave = qt_last_mouse_receiver;
736 if (!leave)
737 leave = QWidget::find(curWin);
738 if (QWidget *grabber = QWidget::mouseGrabber()) {
739 w = grabber;
740 if (leave == w)
741 leave = 0;
742 }
743 QApplicationPrivate::dispatchEnterLeave(w, leave); // send synthetic enter event
744 curWin = w ? w->effectiveWinId() : 0;
745 qt_last_mouse_receiver = w;
746 }
747 ignoreNextMouseReleaseEvent = true;
748 }
749 app_do_modal = qt_modal_stack != 0;
750}
751
752bool qt_try_modal(QWidget *widget, QMSG *qmsg, MRESULT &rc)
753{
754 QWidget *top = 0;
755
756 if (QApplicationPrivate::tryModalHelper(widget, &top))
757 return true;
758
759 int type = qmsg->msg;
760
761 bool block_event = false;
762 if ((type >= WM_MOUSEFIRST && type <= WM_MOUSELAST) ||
763 (type >= WM_EXTMOUSEFIRST && type <= WM_EXTMOUSELAST) ||
764 type == WM_VSCROLL || type == WM_HSCROLL ||
765 type == WM_U_MOUSELEAVE ||
766 type == WM_CHAR) {
767 if (type == WM_MOUSEMOVE) {
768#ifndef QT_NO_CURSOR
769 QCursor *c = qt_grab_cursor();
770 if (!c)
771 c = QApplication::overrideCursor();
772 if (c) // application cursor defined
773 WinSetPointer(HWND_DESKTOP, c->handle());
774 else
775 WinSetPointer(HWND_DESKTOP, QCursor(Qt::ArrowCursor).handle());
776#endif // QT_NO_CURSOR
777 } else if (type == WM_BUTTON1DOWN || type == type == WM_BUTTON2DOWN ||
778 type == WM_BUTTON3DOWN) {
779 if (!top->isActiveWindow()) {
780 top->activateWindow();
781 } else {
782 QApplication::beep();
783 }
784 }
785 block_event = true;
786 } else if (type == WM_CLOSE) {
787 block_event = true;
788 } else if (type == WM_SYSCOMMAND) {
789 if (!(SHORT1FROMMP(qmsg->mp1) == SC_RESTORE && widget->isMinimized()))
790 block_event = true;
791 }
792
793 return !block_event;
794}
795
796/*****************************************************************************
797 Popup widget mechanism
798
799 openPopup()
800 Adds a widget to the list of popup widgets
801 Arguments:
802 QWidget *widget The popup widget to be added
803
804 closePopup()
805 Removes a widget from the list of popup widgets
806 Arguments:
807 QWidget *widget The popup widget to be removed
808 *****************************************************************************/
809
810void QApplicationPrivate::openPopup(QWidget *popup)
811{
812 // @todo implement
813}
814
815void QApplicationPrivate::closePopup(QWidget *popup)
816{
817 // @todo implement
818}
819
820/*****************************************************************************
821 Event translation; translates PM events to Qt events
822 *****************************************************************************/
823
824// State holder for LWIN/RWIN and ALTGr keys
825// (ALTGr is also necessary since OS/2 doesn't report ALTGr as KC_ALT)
826static int qt_extraKeyState = 0;
827
828static int mouseButtonState()
829{
830 int state = 0;
831
832 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)
833 state |= Qt::LeftButton;
834 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000)
835 state |= Qt::RightButton;
836 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000)
837 state |= Qt::MidButton;
838
839 return state;
840}
841
842//
843// Auto-capturing for mouse press and mouse release
844//
845
846static void setAutoCapture(HWND h)
847{
848 if (autoCaptureWnd)
849 releaseAutoCapture();
850 autoCaptureWnd = h;
851
852 if (!mouseButtonState()) {
853 // all buttons released, we don't actually capture the mouse
854 // (see QWidget::translateMouseEvent())
855 autoCaptureReleased = true;
856 } else {
857 autoCaptureReleased = false;
858 WinSetCapture(HWND_DESKTOP, h);
859 }
860}
861
862static void releaseAutoCapture()
863{
864 if (autoCaptureWnd) {
865 if (!autoCaptureReleased) {
866 WinSetCapture(HWND_DESKTOP, NULLHANDLE);
867 autoCaptureReleased = true;
868 }
869 autoCaptureWnd = NULLHANDLE;
870 }
871}
872
873//
874// Mouse event translation
875//
876
877static ushort mouseTbl[] = {
878 WM_MOUSEMOVE, QEvent::MouseMove, 0,
879 WM_BUTTON1DOWN, QEvent::MouseButtonPress, Qt::LeftButton,
880 WM_BUTTON1UP, QEvent::MouseButtonRelease, Qt::LeftButton,
881 WM_BUTTON1DBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
882 WM_BUTTON2DOWN, QEvent::MouseButtonPress, Qt::RightButton,
883 WM_BUTTON2UP, QEvent::MouseButtonRelease, Qt::RightButton,
884 WM_BUTTON2DBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
885 WM_BUTTON3DOWN, QEvent::MouseButtonPress, Qt::MidButton,
886 WM_BUTTON3UP, QEvent::MouseButtonRelease, Qt::MidButton,
887 WM_BUTTON3DBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
888 WM_CONTEXTMENU, QEvent::ContextMenu, 0,
889 0, 0, 0
890};
891
892static int translateButtonState(USHORT s, int type, int button)
893{
894 Q_UNUSED(button);
895
896 int bst = mouseButtonState();
897
898 if (type == QEvent::ContextMenu) {
899 if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000)
900 bst |= Qt::ShiftModifier;
901 if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000)
902 bst |= Qt::AltModifier;
903 if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
904 bst |= Qt::ControlModifier;
905 } else {
906 if (s & KC_SHIFT)
907 bst |= Qt::ShiftModifier;
908 if ((s & KC_ALT))
909 bst |= Qt::AltModifier;
910 if (s & KC_CTRL)
911 bst |= Qt::ControlModifier;
912 }
913 if ((qt_extraKeyState & Qt::AltModifier))
914 bst |= Qt::AltModifier;
915 if (qt_extraKeyState & Qt::MetaModifier)
916 bst |= Qt::MetaModifier;
917
918 return bst;
919}
920
921bool QETWidget::translateMouseEvent(const QMSG &qmsg)
922{
923#if 0
924 static const char *msgNames[] = { // 11 items
925 "WM_MOUSEMOVE",
926 "WM_BUTTON1DOWN", "WM_BUTTON1UP", "WM_BUTTON1DBLCLK",
927 "WM_BUTTON2DOWN", "WM_BUTTON2UP", "WM_BUTTON2DBLCLK",
928 "WM_BUTTON3DOWN", "WM_BUTTON3UP", "WM_BUTTON3DBLCLK",
929 "WM_???"
930 };
931 int msgIdx = qmsg.msg - WM_MOUSEMOVE;
932 if (msgIdx < 0 || msgIdx > 9)
933 msgIdx = 10;
934 qDebug("%s (%04lX): [%08lX/%p:%s] %04hd,%04hd hit=%04hX fl=%04hX",
935 msgNames[msgIdx], qmsg.msg, qmsg.hwnd, this, widgetName(this),
936 SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1),
937 SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2));
938#endif
939
940 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
941 Q_ASSERT(internalWinId() != NULLHANDLE);
942
943 static QPoint pos; // window pos (y flipped)
944 static POINTL gpos = { -1, -1 }; // global pos (y flipped)
945 QEvent::Type type; // event parameters
946 int button;
947 int state;
948 int i;
949
950 // candidate for the double click event
951 static HWND dblClickCandidateWin = 0;
952
953#if !defined (QT_NO_SESSIONMANAGER)
954 if (sm_blockUserInput) //block user interaction during session management
955 return true;
956#endif
957
958 // Compress mouse move events
959 if (qmsg.msg == WM_MOUSEMOVE) {
960 QMSG mouseMsg;
961 mouseMsg.msg = WM_NULL;
962 while (WinPeekMsg(0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
963 WM_MOUSEMOVE, PM_NOREMOVE)) {
964 if (mouseMsg.mp2 != qmsg.mp2)
965 break; // leave the message in the queue because
966 // the key state has changed
967 // Remove the mouse move message
968 WinPeekMsg(0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
969 WM_MOUSEMOVE, PM_REMOVE);
970 }
971 // Update the passed in QMSG structure with the
972 // most recent one.
973 if (mouseMsg.msg != WM_NULL) {
974 PQMSG pqmsg = (PQMSG)&qmsg;
975 pqmsg->mp1 = mouseMsg.mp1;
976 pqmsg->mp2 = mouseMsg.mp2;
977 pqmsg->time = mouseMsg.time;
978 pqmsg->ptl.x = (short)SHORT1FROMMP(mouseMsg.mp1);
979 pqmsg->ptl.y = (short)SHORT2FROMMP(mouseMsg.mp1);
980 WinMapWindowPoints(pqmsg->hwnd, HWND_DESKTOP, &pqmsg->ptl, 1);
981 // flip y coordinate
982 pqmsg->ptl.y = QApplication::desktop()->height() - (pqmsg->ptl.y + 1);
983 }
984 }
985
986 for (i = 0; mouseTbl[i] && (ULONG)mouseTbl[i] != qmsg.msg; i += 3)
987 ;
988 if (!mouseTbl[i])
989 return true;
990
991 type = (QEvent::Type)mouseTbl[++i]; // event type
992 button = mouseTbl[++i]; // which button
993 state = translateButtonState(SHORT2FROMMP(qmsg.mp2), type, button); // button state
994
995 // It seems, that PM remembers only the WM_BUTTONxDOWN message (instead of
996 // the WM_BUTTONxDOWN + WM_BUTTONxUP pair) to detect whether the next button
997 // press should be converted to WM_BUTTONxDBLCLK or not. As a result, the
998 // window gets WM_BUTTONxDBLCLK even if it didn't receive the preceeding
999 // WM_BUTTONxUP (this happens if we issue WinSetCapture() on the first
1000 // WM_BUTTONxDOWN), which is obviously wrong and makes problems for QWorkspace
1001 // and QTitleBar system menu handlers that don't expect a double click after
1002 // they opened a popup menu. dblClickCandidateWin is reset to 0 (see a ***
1003 // remmark below) when WinSetCapture is issued that directs messages
1004 // to a window other than one received the first WM_BUTTONxDOWN,
1005 // so we can fix it here. Note that if there is more than one popup window,
1006 // WinSetCapture is issued only for the first of them, so this code doesn't
1007 // prevent MouseButtonDblClick from being delivered to a popup when another
1008 // popup gets closed on the first WM_BUTTONxDOWN (Qt/Win32 behaves in the
1009 // same way, so it's left for compatibility).
1010 if (type == QEvent::MouseButtonPress) {
1011 dblClickCandidateWin = qmsg.hwnd;
1012 } else if (type == QEvent::MouseButtonDblClick) {
1013 if (dblClickCandidateWin != qmsg.hwnd)
1014 type = QEvent::MouseButtonPress;
1015 dblClickCandidateWin = 0;
1016 }
1017
1018 const QPoint widgetPos = mapFromGlobal(QPoint(qmsg.ptl.x, qmsg.ptl.y));
1019
1020 QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos);
1021 if (alienWidget && alienWidget->internalWinId())
1022 alienWidget = 0;
1023
1024 if (type == QEvent::MouseMove) {
1025 if (!(state & Qt::MouseButtonMask))
1026 qt_button_down = 0;
1027#ifndef QT_NO_CURSOR
1028 QCursor *c = qt_grab_cursor();
1029 if (!c)
1030 c = QApplication::overrideCursor();
1031 if (c) // application cursor defined
1032 WinSetPointer(HWND_DESKTOP, c->handle());
1033 else if (!qt_button_down) {
1034 QWidget *w = alienWidget ? alienWidget : this;
1035 while (!w->isWindow() && !w->isEnabled())
1036 w = w->parentWidget();
1037 WinSetPointer(HWND_DESKTOP, w->cursor().handle());
1038 }
1039#else
1040 // pass the msg to the default proc to let it change the pointer shape
1041 WinDefWindowProc(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
1042#endif
1043
1044 HWND id = effectiveWinId();
1045 QWidget *mouseGrabber = QWidget::mouseGrabber();
1046 QWidget *activePopupWidget = qApp->activePopupWidget();
1047 if (mouseGrabber) {
1048 if (!activePopupWidget || (activePopupWidget == this && !rect().contains(widgetPos)))
1049 id = mouseGrabber->effectiveWinId();
1050 } else if (type == QEvent::NonClientAreaMouseMove) {
1051 id = 0;
1052 }
1053
1054 if (curWin != id) { // new current window
1055 // @todo
1056 // add CS_HITTEST to our window classes and handle WM_HITTEST,
1057 // otherwise disabled windows will not get mouse events?
1058 if (id == 0) {
1059 QWidget *leave = qt_last_mouse_receiver;
1060 if (!leave)
1061 leave = QWidget::find(curWin);
1062 QApplicationPrivate::dispatchEnterLeave(0, leave);
1063 qt_last_mouse_receiver = 0;
1064 curWin = 0;
1065 } else {
1066 QWidget *leave = 0;
1067 if (curWin && qt_last_mouse_receiver)
1068 leave = qt_last_mouse_receiver;
1069 else
1070 leave = QWidget::find(curWin);
1071 QWidget *enter = alienWidget ? alienWidget : this;
1072 if (mouseGrabber && activePopupWidget) {
1073 if (leave != mouseGrabber)
1074 enter = mouseGrabber;
1075 else
1076 enter = activePopupWidget == this ? this : mouseGrabber;
1077 }
1078 QApplicationPrivate::dispatchEnterLeave(enter, leave);
1079 qt_last_mouse_receiver = enter;
1080 curWin = enter ? enter->effectiveWinId() : 0;
1081 }
1082 }
1083
1084 // *** PM posts a dummy WM_MOUSEMOVE message (with the same, uncahnged
1085 // pointer coordinates) after every WinSetCapture that actually changes
1086 // the capture target. I.e., if the argument of WinSetCapture is
1087 // NULLHANDLE, a window under the mouse pointer gets this message,
1088 // otherwise the specified window gets it unless it is already under the
1089 // pointer. We use this info to check whether the window can be a double
1090 // click candidate (see above).
1091 if (qmsg.ptl.x == gpos.x && qmsg.ptl.y == gpos.y) {
1092 if (dblClickCandidateWin != qmsg.hwnd)
1093 dblClickCandidateWin = 0;
1094 return true;
1095 }
1096
1097 gpos = qmsg.ptl;
1098
1099 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1100
1101 POINTL curPos = gpos;
1102 WinMapWindowPoints(internalWinId(), HWND_DESKTOP, &gpos, 1);
1103
1104 pos.rx() = curPos.x;
1105 pos.ry() = curPos.y;
1106 pos = d_func()->mapFromWS(pos);
1107 } else {
1108 if (type == QEvent::MouseButtonPress && !isActiveWindow())
1109 setActiveWindow();
1110
1111 gpos = qmsg.ptl;
1112 pos = mapFromGlobal(QPoint(gpos.x, gpos.y));
1113
1114 // mouse button pressed
1115 if (!qt_button_down && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick)) {
1116 QWidget *tlw = window();
1117 if (QWidget *child = tlw->childAt(mapTo(tlw, pos)))
1118 qt_button_down = child;
1119 else
1120 qt_button_down = this;
1121 }
1122 }
1123
1124 // detect special button states
1125 enum { Other, SinglePressed, AllReleased } btnState = Other;
1126 int bs = state & Qt::MouseButtonMask;
1127 if ((type == QEvent::MouseButtonPress ||
1128 type == QEvent::MouseButtonDblClick) && bs == 0) {
1129 btnState = SinglePressed;
1130 } else if (type == QEvent::MouseButtonRelease && bs == button) {
1131 btnState = AllReleased;
1132 }
1133
1134 bool res = false;
1135
1136 if (qApp->d_func()->inPopupMode()) { // in popup mode
1137 if (!autoCaptureReleased && btnState == AllReleased) {
1138 // in order to give non-Qt windows the opportunity to see mouse
1139 // messages while our popups are active we need to release the
1140 // mouse capture which is absolute in OS/2. we do it directly
1141 // (not through releaseAutoCapture()) in order to keep
1142 // autoCaptureWnd nonzero to keep forwarding mouse move events
1143 // (actually sent to one of Qt widgets) to the active popup.
1144 autoCaptureReleased = true;
1145 WinSetCapture(HWND_DESKTOP, 0);
1146 } else if (autoCaptureReleased && btnState == SinglePressed) {
1147 // set the mouse capture back if a button is pressed.
1148 if ( autoCaptureWnd ) {
1149 autoCaptureReleased = false;
1150 WinSetCapture(HWND_DESKTOP, autoCaptureWnd);
1151 }
1152 }
1153
1154 replayPopupMouseEvent = false;
1155 QWidget* activePopupWidget = qApp->activePopupWidget();
1156 QWidget *target = activePopupWidget;
1157 const QPoint globalPos(gpos.x, gpos.y);
1158
1159 if (target != this) {
1160 if ((windowType() == Qt::Popup) && rect().contains(pos) && 0)
1161 target = this;
1162 else // send to last popup
1163 pos = target->mapFromGlobal(globalPos);
1164 }
1165 QWidget *popupChild = target->childAt(pos);
1166 bool releaseAfter = false;
1167 switch (type) {
1168 case QEvent::MouseButtonPress:
1169 case QEvent::MouseButtonDblClick:
1170 popupButtonFocus = popupChild;
1171 break;
1172 case QEvent::MouseButtonRelease:
1173 releaseAfter = true;
1174 break;
1175 default:
1176 break; // nothing for mouse move
1177 }
1178
1179 if (target->isEnabled()) {
1180 if (popupButtonFocus) {
1181 target = popupButtonFocus;
1182 } else if (popupChild) {
1183 // forward mouse events to the popup child. mouse move events
1184 // are only forwarded to popup children that enable mouse tracking.
1185 if (type != QEvent::MouseMove || popupChild->hasMouseTracking())
1186 target = popupChild;
1187 }
1188
1189 pos = target->mapFromGlobal(globalPos);
1190#ifndef QT_NO_CONTEXTMENU
1191 if (type == QEvent::ContextMenu) {
1192 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, state);
1193 res = QApplication::sendSpontaneousEvent(target, &e);
1194 res = res && e.isAccepted();
1195 }
1196 else
1197#endif
1198 {
1199 QMouseEvent e(type, pos, globalPos,
1200 Qt::MouseButton(button),
1201 Qt::MouseButtons(state & Qt::MouseButtonMask),
1202 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
1203 res = QApplicationPrivate::sendMouseEvent(target, &e, alienWidget, this, &qt_button_down,
1204 qt_last_mouse_receiver);
1205 res = res && e.isAccepted();
1206 }
1207 } else {
1208 // close disabled popups when a mouse button is pressed or released
1209 switch (type) {
1210 case QEvent::MouseButtonPress:
1211 case QEvent::MouseButtonDblClick:
1212 case QEvent::MouseButtonRelease:
1213 target->close();
1214 break;
1215 default:
1216 break;
1217 }
1218 }
1219
1220 if (releaseAfter) {
1221 popupButtonFocus = 0;
1222 qt_button_down = 0;
1223 }
1224
1225 if (type == QEvent::MouseButtonPress
1226 && qApp->activePopupWidget() != activePopupWidget
1227 && replayPopupMouseEvent) {
1228 // the popup dissappeared. Replay the event
1229 QWidget* w = QApplication::widgetAt(gpos.x, gpos.y);
1230 if (w && !QApplicationPrivate::isBlockedByModal(w)) {
1231 Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
1232 HWND hwndTarget = w->effectiveWinId();
1233 if (QWidget::mouseGrabber() == 0)
1234 setAutoCapture(hwndTarget);
1235 if (!w->isActiveWindow())
1236 w->activateWindow();
1237 POINTL pt = gpos;
1238 WinMapWindowPoints(HWND_DESKTOP, hwndTarget, &pt, 1);
1239 // flip y coordinate
1240 pt.y = w->height() - (pt.y + 1);
1241 WinPostMsg(hwndTarget, qmsg.msg,
1242 MPFROM2SHORT(pt.x, pt.y), qmsg.mp2);
1243 }
1244 }
1245 } else { // not popup mode
1246 if (btnState == SinglePressed && QWidget::mouseGrabber() == 0) {
1247 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1248 setAutoCapture(internalWinId());
1249 } else if (btnState == AllReleased && QWidget::mouseGrabber() == 0) {
1250 releaseAutoCapture();
1251 }
1252
1253 const QPoint globalPos(gpos.x,gpos.y);
1254 QWidget *widget = QApplicationPrivate::pickMouseReceiver(this, globalPos, pos, type,
1255 Qt::MouseButtons(bs),
1256 qt_button_down, alienWidget);
1257 if (!widget)
1258 return false; // don't send event
1259
1260#ifndef QT_NO_CONTEXTMENU
1261 if (type == QEvent::ContextMenu) {
1262 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, state);
1263 res = QApplication::sendSpontaneousEvent(widget, &e);
1264 res = res && e.isAccepted();
1265 } else
1266#endif
1267 {
1268 QMouseEvent e(type, pos, globalPos, Qt::MouseButton(button),
1269 Qt::MouseButtons(state & Qt::MouseButtonMask),
1270 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
1271
1272 res = QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
1273 qt_last_mouse_receiver);
1274 res = res && e.isAccepted();
1275 }
1276
1277 if (type != QEvent::MouseMove)
1278 pos.rx() = pos.ry() = -9999; // init for move compression
1279 }
1280
1281 return res;
1282}
1283
1284#ifndef QT_NO_WHEELEVENT
1285bool QETWidget::translateWheelEvent(const QMSG &qmsg)
1286{
1287 enum { WHEEL_DELTA = 120 };
1288
1289#ifndef QT_NO_SESSIONMANAGER
1290 if (sm_blockUserInput) // block user interaction during session management
1291 return true;
1292#endif
1293
1294 // consume duplicate wheel events sent by the AMouse driver to emulate
1295 // multiline scrolls. we need this since currently Qt (QScrollBar, for
1296 // instance) maintains the number of lines to scroll per wheel rotation
1297 // (including the special handling of CTRL and SHIFT modifiers) on its own
1298 // and doesn't have a setting to tell it to be aware of system settings
1299 // for the mouse wheel. if we had processed events as they are, we would
1300 // get a confusing behavior (too many lines scrolled etc.).
1301 {
1302 int devh = QApplication::desktop()->height();
1303 QMSG wheelMsg;
1304 while (WinPeekMsg(0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_NOREMOVE)) {
1305 // PM bug: ptl contains SHORT coordinates although fields are LONG
1306 wheelMsg.ptl.x = (short) wheelMsg.ptl.x;
1307 wheelMsg.ptl.y = (short) wheelMsg.ptl.y;
1308 // flip y coordinate
1309 wheelMsg.ptl.y = devh - (wheelMsg.ptl.y + 1);
1310 if (wheelMsg.mp1 != qmsg.mp1 ||
1311 wheelMsg.mp2 != qmsg.mp2 ||
1312 wheelMsg.ptl.x != qmsg.ptl.x ||
1313 wheelMsg.ptl.y != qmsg.ptl.y)
1314 break;
1315 WinPeekMsg(0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_REMOVE);
1316 }
1317 }
1318
1319 int delta;
1320 USHORT cmd = SHORT2FROMMP(qmsg.mp2);
1321 switch (cmd) {
1322 case SB_LINEUP:
1323 case SB_PAGEUP:
1324 delta = WHEEL_DELTA;
1325 break;
1326 case SB_LINEDOWN:
1327 case SB_PAGEDOWN:
1328 delta = -WHEEL_DELTA;
1329 break;
1330 default:
1331 return false;
1332 }
1333
1334 int state = 0;
1335 if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT ) & 0x8000)
1336 state |= Qt::ShiftModifier;
1337 if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000 ||
1338 (qt_extraKeyState & Qt::AltModifier))
1339 state |= Qt::AltModifier;
1340 if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
1341 state |= Qt::ControlModifier;
1342 if (qt_extraKeyState & Qt::MetaModifier)
1343 state |= Qt::MetaModifier;
1344
1345 Qt::Orientation orient;
1346 // Alt inverts scroll orientation (Qt/Win32 behavior)
1347 if (state & Qt::AltModifier)
1348 orient = qmsg.msg == WM_VSCROLL ? Qt::Horizontal : Qt::Vertical;
1349 else
1350 orient = qmsg.msg == WM_VSCROLL ? Qt::Vertical : Qt::Horizontal;
1351
1352 QPoint globalPos(qmsg.ptl.x, qmsg.ptl.y);
1353
1354 // if there is a widget under the mouse and it is not shadowed
1355 // by modality, we send the event to it first
1356 MRESULT rc = FALSE;
1357 QWidget* w = QApplication::widgetAt(globalPos);
1358 if (!w || !qt_try_modal(w, (QMSG*)&qmsg, rc)) {
1359 //synaptics touchpad shows its own widget at this position
1360 //so widgetAt() will fail with that HWND, try child of this widget
1361 w = this->childAt(this->mapFromGlobal(globalPos));
1362 if (!w)
1363 w = this;
1364 }
1365
1366 // send the event to the widget or its ancestors
1367 {
1368 QWidget* popup = qApp->activePopupWidget();
1369 if (popup && w->window() != popup)
1370 popup->close();
1371#ifndef QT_NO_WHEELEVENT
1372 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
1373 Qt::MouseButtons(state & Qt::MouseButtonMask),
1374 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
1375
1376 if (QApplication::sendSpontaneousEvent(w, &e))
1377#else
1378 Q_UNUSED(orient);
1379#endif //QT_NO_WHEELEVENT
1380 return true;
1381 }
1382
1383 // send the event to the widget that has the focus or its ancestors, if different
1384 if (w != qApp->focusWidget() && (w = qApp->focusWidget())) {
1385 QWidget* popup = qApp->activePopupWidget();
1386 if (popup && w->window() != popup)
1387 popup->close();
1388#ifndef QT_NO_WHEELEVENT
1389 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
1390 Qt::MouseButtons(state & Qt::MouseButtonMask),
1391 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
1392 if (QApplication::sendSpontaneousEvent(w, &e))
1393#endif //QT_NO_WHEELEVENT
1394 return true;
1395 }
1396
1397 return false;
1398}
1399#endif
1400
1401//
1402// Close window event translation.
1403//
1404// This class is a friend of QApplication because it needs to emit the
1405// lastWindowClosed() signal when the last top level widget is closed.
1406//
1407
1408bool QETWidget::translateCloseEvent(const QMSG &)
1409{
1410 return d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
1411}
1412
1413QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.