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

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

gui: Paint event translation.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Date Revision Author Id
File size: 52.5 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 &qmsg);
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_PAINT: { // paint event
560 if (widget->translatePaintEvent(qmsg))
561 return (MRESULT)TRUE;
562 break;
563 }
564
565 case WM_ERASEBACKGROUND: { // erase window background
566 // flush WM_PAINT messages here to update window contents
567 // instantly while tracking the resize frame (normally these
568 // messages are delivered after the user has stopped resizing
569 // for some time). this slows down resizing slightly but gives a
570 // better look (no invalid window contents can be seen during
571 // resize). the alternative could be to erase the background only,
572 // but we need to do it for every non-toplevel window, which can
573 // also be time-consuming (WM_ERASEBACKGROUND is sent to WC_FRAME
574 // clients only, so we would have to do all calculations ourselves).
575 WinUpdateWindow(widget->effectiveWinId());
576 return FALSE;
577 }
578
579 case WM_CALCVALIDRECTS: {
580 // we must always return this value here to cause PM to reposition
581 // our children accordingly (othwerwise we would have to do it
582 // ourselves to keep them top-left aligned).
583 return (MRESULT)(CVR_ALIGNLEFT | CVR_ALIGNTOP);
584 }
585
586 case WM_MOVE: // move window
587 case WM_SIZE: { // resize window
588 if (widget->translateConfigEvent(qmsg))
589 return (MRESULT)TRUE;
590 break;
591 }
592
593 case WM_SHOW: {
594 // @todo there is some more processing in Qt4, see
595 // WM_SHOWWINDOW in qapplication_win.cpp
596 if (!SHORT1FROMMP(mp1) && autoCaptureWnd == widget->internalWinId())
597 releaseAutoCapture();
598 break;
599 }
600
601 case WM_CLOSE: { // close window
602 widget->translateCloseEvent(qmsg);
603 return (MRESULT)TRUE;
604 }
605
606 case WM_DESTROY: { // destroy window
607 if (hwnd == curWin) {
608 QWidget *enter = QWidget::mouseGrabber();
609 if (enter == widget)
610 enter = 0;
611 QApplicationPrivate::dispatchEnterLeave(enter, widget);
612 curWin = enter ? enter->effectiveWinId() : 0;
613 qt_last_mouse_receiver = enter;
614 }
615 if (widget == popupButtonFocus)
616 popupButtonFocus = 0;
617 break;
618 }
619
620#ifndef QT_NO_CONTEXTMENU
621 case WM_CONTEXTMENU: {
622 if (SHORT2FROMMP(mp2)) {
623 // keyboard event
624 QWidget *fw = qApp->focusWidget();
625 if (fw && fw->isEnabled()) {
626 QContextMenuEvent e(QContextMenuEvent::Keyboard,
627 QPoint(5, 5),
628 fw->mapToGlobal(QPoint(5, 5)), 0);
629 if (qt_sendSpontaneousEvent(fw, &e))
630 return (MRESULT)TRUE;
631 }
632 } else {
633 // mouse event
634 if (widget->translateMouseEvent(qmsg))
635 return (MRESULT)TRUE;
636 }
637 break;
638 }
639#endif
640
641 case WM_U_MOUSELEAVE: {
642 // We receive a mouse leave for curWin, meaning
643 // the mouse was moved outside our widgets
644 if (widget->internalWinId() == curWin) {
645 bool dispatch = !widget->underMouse();
646 // hasMouse is updated when dispatching enter/leave,
647 // so test if it is actually up-to-date
648 if (!dispatch) {
649 QRect geom = widget->geometry();
650 if (widget->parentWidget() && !widget->isWindow()) {
651 QPoint gp = widget->parentWidget()->mapToGlobal(widget->pos());
652 geom.setX(gp.x());
653 geom.setY(gp.y());
654 }
655 QPoint cpos = QCursor::pos();
656 dispatch = !geom.contains(cpos);
657 if ( !dispatch && !QWidget::mouseGrabber()) {
658 QWidget *hittest = QApplication::widgetAt(cpos);
659 dispatch = !hittest || hittest->internalWinId() != curWin;
660 }
661 if (!dispatch) {
662 HPS hps = qt_display_ps();
663 HRGN hrgn = GpiCreateRegion(hps, 0, NULL);
664 qt_WinQueryClipRegionOrRect(hwnd, hrgn);
665 QPoint lcpos = widget->mapFromGlobal(cpos);
666 // flip y coordinate
667 POINTL pt = { lcpos.x(), widget->height() - (lcpos.y() + 1) };
668 dispatch = !GpiPtInRegion(hps, hrgn, &pt);
669 GpiDestroyRegion(hps, hrgn);
670 }
671 }
672 if (dispatch) {
673 if (qt_last_mouse_receiver && !qt_last_mouse_receiver->internalWinId())
674 QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
675 else
676 QApplicationPrivate::dispatchEnterLeave(0, QWidget::find((WId)curWin));
677 curWin = 0;
678 qt_last_mouse_receiver = 0;
679 }
680 }
681 break;
682 }
683
684 default:
685 break;
686 }
687 }
688
689 } while(0);
690
691 return WinDefWindowProc(hwnd, msg, mp1, mp2);
692}
693
694PFNWP QtOldFrameProc = 0;
695
696MRESULT EXPENTRY QtFrameProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
697{
698 do {
699 if (!qApp) // unstable app state
700 break;
701#if 0
702 // make sure we show widgets (e.g. scrollbars) when the user resizes
703 if (qApp->loopLevel())
704 qApp->sendPostedEvents(0, QEvent::ShowWindowRequest);
705#endif
706
707 HWND hwndC = WinWindowFromID(hwnd, FID_CLIENT);
708 QETWidget *widget = (QETWidget*)QWidget::find(hwndC);
709 if (!widget) // don't know this widget
710 break;
711
712 switch(msg) {
713 default:
714 break;
715 }
716 } while(0);
717
718 return QtOldFrameProc(hwnd, msg, mp1, mp2);
719}
720
721/*****************************************************************************
722 Modal widgets; We have implemented our own modal widget mechanism
723 to get total control.
724 A modal widget without a parent becomes application-modal.
725 A modal widget with a parent becomes modal to its parent and grandparents..
726
727 QApplicationPrivate::enterModal()
728 Enters modal state
729 Arguments:
730 QWidget *widget A modal widget
731
732 QApplicationPrivate::leaveModal()
733 Leaves modal state for a widget
734 Arguments:
735 QWidget *widget A modal widget
736 *****************************************************************************/
737
738bool QApplicationPrivate::modalState()
739{
740 return app_do_modal;
741}
742
743void QApplicationPrivate::enterModal_sys(QWidget *widget)
744{
745 if (!qt_modal_stack)
746 qt_modal_stack = new QWidgetList;
747
748 releaseAutoCapture();
749 QWidget *leave = qt_last_mouse_receiver;
750 if (!leave)
751 leave = QWidget::find(curWin);
752 QApplicationPrivate::dispatchEnterLeave(0, leave);
753 qt_modal_stack->insert(0, widget);
754 app_do_modal = true;
755 curWin = 0;
756 qt_last_mouse_receiver = 0;
757 ignoreNextMouseReleaseEvent = false;
758}
759
760void QApplicationPrivate::leaveModal_sys(QWidget *widget)
761{
762 if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
763 if (qt_modal_stack->isEmpty()) {
764 delete qt_modal_stack;
765 qt_modal_stack = 0;
766 QPoint p(QCursor::pos());
767 app_do_modal = false; // necessary, we may get recursively into qt_try_modal below
768 QWidget* w = QApplication::widgetAt(p.x(), p.y());
769 QWidget *leave = qt_last_mouse_receiver;
770 if (!leave)
771 leave = QWidget::find(curWin);
772 if (QWidget *grabber = QWidget::mouseGrabber()) {
773 w = grabber;
774 if (leave == w)
775 leave = 0;
776 }
777 QApplicationPrivate::dispatchEnterLeave(w, leave); // send synthetic enter event
778 curWin = w ? w->effectiveWinId() : 0;
779 qt_last_mouse_receiver = w;
780 }
781 ignoreNextMouseReleaseEvent = true;
782 }
783 app_do_modal = qt_modal_stack != 0;
784}
785
786bool qt_try_modal(QWidget *widget, QMSG *qmsg, MRESULT &rc)
787{
788 QWidget *top = 0;
789
790 if (QApplicationPrivate::tryModalHelper(widget, &top))
791 return true;
792
793 int type = qmsg->msg;
794
795 bool block_event = false;
796 if ((type >= WM_MOUSEFIRST && type <= WM_MOUSELAST) ||
797 (type >= WM_EXTMOUSEFIRST && type <= WM_EXTMOUSELAST) ||
798 type == WM_VSCROLL || type == WM_HSCROLL ||
799 type == WM_U_MOUSELEAVE ||
800 type == WM_CHAR) {
801 if (type == WM_MOUSEMOVE) {
802#ifndef QT_NO_CURSOR
803 QCursor *c = qt_grab_cursor();
804 if (!c)
805 c = QApplication::overrideCursor();
806 if (c) // application cursor defined
807 WinSetPointer(HWND_DESKTOP, c->handle());
808 else
809 WinSetPointer(HWND_DESKTOP, QCursor(Qt::ArrowCursor).handle());
810#endif // QT_NO_CURSOR
811 } else if (type == WM_BUTTON1DOWN || type == type == WM_BUTTON2DOWN ||
812 type == WM_BUTTON3DOWN) {
813 if (!top->isActiveWindow()) {
814 top->activateWindow();
815 } else {
816 QApplication::beep();
817 }
818 }
819 block_event = true;
820 } else if (type == WM_CLOSE) {
821 block_event = true;
822 } else if (type == WM_SYSCOMMAND) {
823 if (!(SHORT1FROMMP(qmsg->mp1) == SC_RESTORE && widget->isMinimized()))
824 block_event = true;
825 }
826
827 return !block_event;
828}
829
830/*****************************************************************************
831 Popup widget mechanism
832
833 openPopup()
834 Adds a widget to the list of popup widgets
835 Arguments:
836 QWidget *widget The popup widget to be added
837
838 closePopup()
839 Removes a widget from the list of popup widgets
840 Arguments:
841 QWidget *widget The popup widget to be removed
842 *****************************************************************************/
843
844void QApplicationPrivate::openPopup(QWidget *popup)
845{
846 // @todo implement
847}
848
849void QApplicationPrivate::closePopup(QWidget *popup)
850{
851 // @todo implement
852}
853
854/*****************************************************************************
855 Event translation; translates PM events to Qt events
856 *****************************************************************************/
857
858// State holder for LWIN/RWIN and ALTGr keys
859// (ALTGr is also necessary since OS/2 doesn't report ALTGr as KC_ALT)
860static int qt_extraKeyState = 0;
861
862static int mouseButtonState()
863{
864 int state = 0;
865
866 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)
867 state |= Qt::LeftButton;
868 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000)
869 state |= Qt::RightButton;
870 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000)
871 state |= Qt::MidButton;
872
873 return state;
874}
875
876//
877// Auto-capturing for mouse press and mouse release
878//
879
880static void setAutoCapture(HWND h)
881{
882 if (autoCaptureWnd)
883 releaseAutoCapture();
884 autoCaptureWnd = h;
885
886 if (!mouseButtonState()) {
887 // all buttons released, we don't actually capture the mouse
888 // (see QWidget::translateMouseEvent())
889 autoCaptureReleased = true;
890 } else {
891 autoCaptureReleased = false;
892 WinSetCapture(HWND_DESKTOP, h);
893 }
894}
895
896static void releaseAutoCapture()
897{
898 if (autoCaptureWnd) {
899 if (!autoCaptureReleased) {
900 WinSetCapture(HWND_DESKTOP, NULLHANDLE);
901 autoCaptureReleased = true;
902 }
903 autoCaptureWnd = NULLHANDLE;
904 }
905}
906
907//
908// Mouse event translation
909//
910
911static ushort mouseTbl[] = {
912 WM_MOUSEMOVE, QEvent::MouseMove, 0,
913 WM_BUTTON1DOWN, QEvent::MouseButtonPress, Qt::LeftButton,
914 WM_BUTTON1UP, QEvent::MouseButtonRelease, Qt::LeftButton,
915 WM_BUTTON1DBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
916 WM_BUTTON2DOWN, QEvent::MouseButtonPress, Qt::RightButton,
917 WM_BUTTON2UP, QEvent::MouseButtonRelease, Qt::RightButton,
918 WM_BUTTON2DBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
919 WM_BUTTON3DOWN, QEvent::MouseButtonPress, Qt::MidButton,
920 WM_BUTTON3UP, QEvent::MouseButtonRelease, Qt::MidButton,
921 WM_BUTTON3DBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
922 WM_CONTEXTMENU, QEvent::ContextMenu, 0,
923 0, 0, 0
924};
925
926static int translateButtonState(USHORT s, int type, int button)
927{
928 Q_UNUSED(button);
929
930 int bst = mouseButtonState();
931
932 if (type == QEvent::ContextMenu) {
933 if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000)
934 bst |= Qt::ShiftModifier;
935 if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000)
936 bst |= Qt::AltModifier;
937 if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
938 bst |= Qt::ControlModifier;
939 } else {
940 if (s & KC_SHIFT)
941 bst |= Qt::ShiftModifier;
942 if ((s & KC_ALT))
943 bst |= Qt::AltModifier;
944 if (s & KC_CTRL)
945 bst |= Qt::ControlModifier;
946 }
947 if ((qt_extraKeyState & Qt::AltModifier))
948 bst |= Qt::AltModifier;
949 if (qt_extraKeyState & Qt::MetaModifier)
950 bst |= Qt::MetaModifier;
951
952 return bst;
953}
954
955bool QETWidget::translateMouseEvent(const QMSG &qmsg)
956{
957#if 0
958 static const char *msgNames[] = { // 11 items
959 "WM_MOUSEMOVE",
960 "WM_BUTTON1DOWN", "WM_BUTTON1UP", "WM_BUTTON1DBLCLK",
961 "WM_BUTTON2DOWN", "WM_BUTTON2UP", "WM_BUTTON2DBLCLK",
962 "WM_BUTTON3DOWN", "WM_BUTTON3UP", "WM_BUTTON3DBLCLK",
963 "WM_???"
964 };
965 int msgIdx = qmsg.msg - WM_MOUSEMOVE;
966 if (msgIdx < 0 || msgIdx > 9)
967 msgIdx = 10;
968 qDebug("%s (%04lX): [%08lX/%p:%s] %04hd,%04hd hit=%04hX fl=%04hX",
969 msgNames[msgIdx], qmsg.msg, qmsg.hwnd, this, widgetName(this),
970 SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1),
971 SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2));
972#endif
973
974 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
975 Q_ASSERT(internalWinId() != NULLHANDLE);
976
977 static QPoint pos; // window pos (y flipped)
978 static POINTL gpos = { -1, -1 }; // global pos (y flipped)
979 QEvent::Type type; // event parameters
980 int button;
981 int state;
982 int i;
983
984 // candidate for the double click event
985 static HWND dblClickCandidateWin = 0;
986
987#if !defined (QT_NO_SESSIONMANAGER)
988 if (sm_blockUserInput) //block user interaction during session management
989 return true;
990#endif
991
992 // Compress mouse move events
993 if (qmsg.msg == WM_MOUSEMOVE) {
994 QMSG mouseMsg;
995 mouseMsg.msg = WM_NULL;
996 while (WinPeekMsg(0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
997 WM_MOUSEMOVE, PM_NOREMOVE)) {
998 if (mouseMsg.mp2 != qmsg.mp2)
999 break; // leave the message in the queue because
1000 // the key state has changed
1001 // Remove the mouse move message
1002 WinPeekMsg(0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
1003 WM_MOUSEMOVE, PM_REMOVE);
1004 }
1005 // Update the passed in QMSG structure with the
1006 // most recent one.
1007 if (mouseMsg.msg != WM_NULL) {
1008 PQMSG pqmsg = (PQMSG)&qmsg;
1009 pqmsg->mp1 = mouseMsg.mp1;
1010 pqmsg->mp2 = mouseMsg.mp2;
1011 pqmsg->time = mouseMsg.time;
1012 pqmsg->ptl.x = (short)SHORT1FROMMP(mouseMsg.mp1);
1013 pqmsg->ptl.y = (short)SHORT2FROMMP(mouseMsg.mp1);
1014 WinMapWindowPoints(pqmsg->hwnd, HWND_DESKTOP, &pqmsg->ptl, 1);
1015 // flip y coordinate
1016 pqmsg->ptl.y = QApplication::desktop()->height() - (pqmsg->ptl.y + 1);
1017 }
1018 }
1019
1020 for (i = 0; mouseTbl[i] && (ULONG)mouseTbl[i] != qmsg.msg; i += 3)
1021 ;
1022 if (!mouseTbl[i])
1023 return true;
1024
1025 type = (QEvent::Type)mouseTbl[++i]; // event type
1026 button = mouseTbl[++i]; // which button
1027 state = translateButtonState(SHORT2FROMMP(qmsg.mp2), type, button); // button state
1028
1029 // It seems, that PM remembers only the WM_BUTTONxDOWN message (instead of
1030 // the WM_BUTTONxDOWN + WM_BUTTONxUP pair) to detect whether the next button
1031 // press should be converted to WM_BUTTONxDBLCLK or not. As a result, the
1032 // window gets WM_BUTTONxDBLCLK even if it didn't receive the preceeding
1033 // WM_BUTTONxUP (this happens if we issue WinSetCapture() on the first
1034 // WM_BUTTONxDOWN), which is obviously wrong and makes problems for QWorkspace
1035 // and QTitleBar system menu handlers that don't expect a double click after
1036 // they opened a popup menu. dblClickCandidateWin is reset to 0 (see a ***
1037 // remmark below) when WinSetCapture is issued that directs messages
1038 // to a window other than one received the first WM_BUTTONxDOWN,
1039 // so we can fix it here. Note that if there is more than one popup window,
1040 // WinSetCapture is issued only for the first of them, so this code doesn't
1041 // prevent MouseButtonDblClick from being delivered to a popup when another
1042 // popup gets closed on the first WM_BUTTONxDOWN (Qt/Win32 behaves in the
1043 // same way, so it's left for compatibility).
1044 if (type == QEvent::MouseButtonPress) {
1045 dblClickCandidateWin = qmsg.hwnd;
1046 } else if (type == QEvent::MouseButtonDblClick) {
1047 if (dblClickCandidateWin != qmsg.hwnd)
1048 type = QEvent::MouseButtonPress;
1049 dblClickCandidateWin = 0;
1050 }
1051
1052 const QPoint widgetPos = mapFromGlobal(QPoint(qmsg.ptl.x, qmsg.ptl.y));
1053
1054 QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos);
1055 if (alienWidget && alienWidget->internalWinId())
1056 alienWidget = 0;
1057
1058 if (type == QEvent::MouseMove) {
1059 if (!(state & Qt::MouseButtonMask))
1060 qt_button_down = 0;
1061#ifndef QT_NO_CURSOR
1062 QCursor *c = qt_grab_cursor();
1063 if (!c)
1064 c = QApplication::overrideCursor();
1065 if (c) // application cursor defined
1066 WinSetPointer(HWND_DESKTOP, c->handle());
1067 else if (!qt_button_down) {
1068 QWidget *w = alienWidget ? alienWidget : this;
1069 while (!w->isWindow() && !w->isEnabled())
1070 w = w->parentWidget();
1071 WinSetPointer(HWND_DESKTOP, w->cursor().handle());
1072 }
1073#else
1074 // pass the msg to the default proc to let it change the pointer shape
1075 WinDefWindowProc(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
1076#endif
1077
1078 HWND id = effectiveWinId();
1079 QWidget *mouseGrabber = QWidget::mouseGrabber();
1080 QWidget *activePopupWidget = qApp->activePopupWidget();
1081 if (mouseGrabber) {
1082 if (!activePopupWidget || (activePopupWidget == this && !rect().contains(widgetPos)))
1083 id = mouseGrabber->effectiveWinId();
1084 } else if (type == QEvent::NonClientAreaMouseMove) {
1085 id = 0;
1086 }
1087
1088 if (curWin != id) { // new current window
1089 // @todo
1090 // add CS_HITTEST to our window classes and handle WM_HITTEST,
1091 // otherwise disabled windows will not get mouse events?
1092 if (id == 0) {
1093 QWidget *leave = qt_last_mouse_receiver;
1094 if (!leave)
1095 leave = QWidget::find(curWin);
1096 QApplicationPrivate::dispatchEnterLeave(0, leave);
1097 qt_last_mouse_receiver = 0;
1098 curWin = 0;
1099 } else {
1100 QWidget *leave = 0;
1101 if (curWin && qt_last_mouse_receiver)
1102 leave = qt_last_mouse_receiver;
1103 else
1104 leave = QWidget::find(curWin);
1105 QWidget *enter = alienWidget ? alienWidget : this;
1106 if (mouseGrabber && activePopupWidget) {
1107 if (leave != mouseGrabber)
1108 enter = mouseGrabber;
1109 else
1110 enter = activePopupWidget == this ? this : mouseGrabber;
1111 }
1112 QApplicationPrivate::dispatchEnterLeave(enter, leave);
1113 qt_last_mouse_receiver = enter;
1114 curWin = enter ? enter->effectiveWinId() : 0;
1115 }
1116 }
1117
1118 // *** PM posts a dummy WM_MOUSEMOVE message (with the same, uncahnged
1119 // pointer coordinates) after every WinSetCapture that actually changes
1120 // the capture target. I.e., if the argument of WinSetCapture is
1121 // NULLHANDLE, a window under the mouse pointer gets this message,
1122 // otherwise the specified window gets it unless it is already under the
1123 // pointer. We use this info to check whether the window can be a double
1124 // click candidate (see above).
1125 if (qmsg.ptl.x == gpos.x && qmsg.ptl.y == gpos.y) {
1126 if (dblClickCandidateWin != qmsg.hwnd)
1127 dblClickCandidateWin = 0;
1128 return true;
1129 }
1130
1131 gpos = qmsg.ptl;
1132
1133 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1134
1135 POINTL curPos = gpos;
1136 WinMapWindowPoints(internalWinId(), HWND_DESKTOP, &gpos, 1);
1137
1138 pos.rx() = curPos.x;
1139 pos.ry() = curPos.y;
1140 pos = d_func()->mapFromWS(pos);
1141 } else {
1142 if (type == QEvent::MouseButtonPress && !isActiveWindow())
1143 setActiveWindow();
1144
1145 gpos = qmsg.ptl;
1146 pos = mapFromGlobal(QPoint(gpos.x, gpos.y));
1147
1148 // mouse button pressed
1149 if (!qt_button_down && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick)) {
1150 QWidget *tlw = window();
1151 if (QWidget *child = tlw->childAt(mapTo(tlw, pos)))
1152 qt_button_down = child;
1153 else
1154 qt_button_down = this;
1155 }
1156 }
1157
1158 // detect special button states
1159 enum { Other, SinglePressed, AllReleased } btnState = Other;
1160 int bs = state & Qt::MouseButtonMask;
1161 if ((type == QEvent::MouseButtonPress ||
1162 type == QEvent::MouseButtonDblClick) && bs == 0) {
1163 btnState = SinglePressed;
1164 } else if (type == QEvent::MouseButtonRelease && bs == button) {
1165 btnState = AllReleased;
1166 }
1167
1168 bool res = false;
1169
1170 if (qApp->d_func()->inPopupMode()) { // in popup mode
1171 if (!autoCaptureReleased && btnState == AllReleased) {
1172 // in order to give non-Qt windows the opportunity to see mouse
1173 // messages while our popups are active we need to release the
1174 // mouse capture which is absolute in OS/2. we do it directly
1175 // (not through releaseAutoCapture()) in order to keep
1176 // autoCaptureWnd nonzero to keep forwarding mouse move events
1177 // (actually sent to one of Qt widgets) to the active popup.
1178 autoCaptureReleased = true;
1179 WinSetCapture(HWND_DESKTOP, 0);
1180 } else if (autoCaptureReleased && btnState == SinglePressed) {
1181 // set the mouse capture back if a button is pressed.
1182 if ( autoCaptureWnd ) {
1183 autoCaptureReleased = false;
1184 WinSetCapture(HWND_DESKTOP, autoCaptureWnd);
1185 }
1186 }
1187
1188 replayPopupMouseEvent = false;
1189 QWidget* activePopupWidget = qApp->activePopupWidget();
1190 QWidget *target = activePopupWidget;
1191 const QPoint globalPos(gpos.x, gpos.y);
1192
1193 if (target != this) {
1194 if ((windowType() == Qt::Popup) && rect().contains(pos) && 0)
1195 target = this;
1196 else // send to last popup
1197 pos = target->mapFromGlobal(globalPos);
1198 }
1199 QWidget *popupChild = target->childAt(pos);
1200 bool releaseAfter = false;
1201 switch (type) {
1202 case QEvent::MouseButtonPress:
1203 case QEvent::MouseButtonDblClick:
1204 popupButtonFocus = popupChild;
1205 break;
1206 case QEvent::MouseButtonRelease:
1207 releaseAfter = true;
1208 break;
1209 default:
1210 break; // nothing for mouse move
1211 }
1212
1213 if (target->isEnabled()) {
1214 if (popupButtonFocus) {
1215 target = popupButtonFocus;
1216 } else if (popupChild) {
1217 // forward mouse events to the popup child. mouse move events
1218 // are only forwarded to popup children that enable mouse tracking.
1219 if (type != QEvent::MouseMove || popupChild->hasMouseTracking())
1220 target = popupChild;
1221 }
1222
1223 pos = target->mapFromGlobal(globalPos);
1224#ifndef QT_NO_CONTEXTMENU
1225 if (type == QEvent::ContextMenu) {
1226 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, state);
1227 res = QApplication::sendSpontaneousEvent(target, &e);
1228 res = res && e.isAccepted();
1229 }
1230 else
1231#endif
1232 {
1233 QMouseEvent e(type, pos, globalPos,
1234 Qt::MouseButton(button),
1235 Qt::MouseButtons(state & Qt::MouseButtonMask),
1236 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
1237 res = QApplicationPrivate::sendMouseEvent(target, &e, alienWidget, this, &qt_button_down,
1238 qt_last_mouse_receiver);
1239 res = res && e.isAccepted();
1240 }
1241 } else {
1242 // close disabled popups when a mouse button is pressed or released
1243 switch (type) {
1244 case QEvent::MouseButtonPress:
1245 case QEvent::MouseButtonDblClick:
1246 case QEvent::MouseButtonRelease:
1247 target->close();
1248 break;
1249 default:
1250 break;
1251 }
1252 }
1253
1254 if (releaseAfter) {
1255 popupButtonFocus = 0;
1256 qt_button_down = 0;
1257 }
1258
1259 if (type == QEvent::MouseButtonPress
1260 && qApp->activePopupWidget() != activePopupWidget
1261 && replayPopupMouseEvent) {
1262 // the popup dissappeared. Replay the event
1263 QWidget* w = QApplication::widgetAt(gpos.x, gpos.y);
1264 if (w && !QApplicationPrivate::isBlockedByModal(w)) {
1265 Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
1266 HWND hwndTarget = w->effectiveWinId();
1267 if (QWidget::mouseGrabber() == 0)
1268 setAutoCapture(hwndTarget);
1269 if (!w->isActiveWindow())
1270 w->activateWindow();
1271 POINTL pt = gpos;
1272 WinMapWindowPoints(HWND_DESKTOP, hwndTarget, &pt, 1);
1273 // flip y coordinate
1274 pt.y = w->height() - (pt.y + 1);
1275 WinPostMsg(hwndTarget, qmsg.msg,
1276 MPFROM2SHORT(pt.x, pt.y), qmsg.mp2);
1277 }
1278 }
1279 } else { // not popup mode
1280 if (btnState == SinglePressed && QWidget::mouseGrabber() == 0) {
1281 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1282 setAutoCapture(internalWinId());
1283 } else if (btnState == AllReleased && QWidget::mouseGrabber() == 0) {
1284 releaseAutoCapture();
1285 }
1286
1287 const QPoint globalPos(gpos.x,gpos.y);
1288 QWidget *widget = QApplicationPrivate::pickMouseReceiver(this, globalPos, pos, type,
1289 Qt::MouseButtons(bs),
1290 qt_button_down, alienWidget);
1291 if (!widget)
1292 return false; // don't send event
1293
1294#ifndef QT_NO_CONTEXTMENU
1295 if (type == QEvent::ContextMenu) {
1296 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, state);
1297 res = QApplication::sendSpontaneousEvent(widget, &e);
1298 res = res && e.isAccepted();
1299 } else
1300#endif
1301 {
1302 QMouseEvent e(type, pos, globalPos, Qt::MouseButton(button),
1303 Qt::MouseButtons(state & Qt::MouseButtonMask),
1304 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
1305
1306 res = QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
1307 qt_last_mouse_receiver);
1308 res = res && e.isAccepted();
1309 }
1310
1311 if (type != QEvent::MouseMove)
1312 pos.rx() = pos.ry() = -9999; // init for move compression
1313 }
1314
1315 return res;
1316}
1317
1318#ifndef QT_NO_WHEELEVENT
1319bool QETWidget::translateWheelEvent(const QMSG &qmsg)
1320{
1321 enum { WHEEL_DELTA = 120 };
1322
1323#ifndef QT_NO_SESSIONMANAGER
1324 if (sm_blockUserInput) // block user interaction during session management
1325 return true;
1326#endif
1327
1328 // consume duplicate wheel events sent by the AMouse driver to emulate
1329 // multiline scrolls. we need this since currently Qt (QScrollBar, for
1330 // instance) maintains the number of lines to scroll per wheel rotation
1331 // (including the special handling of CTRL and SHIFT modifiers) on its own
1332 // and doesn't have a setting to tell it to be aware of system settings
1333 // for the mouse wheel. if we had processed events as they are, we would
1334 // get a confusing behavior (too many lines scrolled etc.).
1335 {
1336 int devh = QApplication::desktop()->height();
1337 QMSG wheelMsg;
1338 while (WinPeekMsg(0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_NOREMOVE)) {
1339 // PM bug: ptl contains SHORT coordinates although fields are LONG
1340 wheelMsg.ptl.x = (short) wheelMsg.ptl.x;
1341 wheelMsg.ptl.y = (short) wheelMsg.ptl.y;
1342 // flip y coordinate
1343 wheelMsg.ptl.y = devh - (wheelMsg.ptl.y + 1);
1344 if (wheelMsg.mp1 != qmsg.mp1 ||
1345 wheelMsg.mp2 != qmsg.mp2 ||
1346 wheelMsg.ptl.x != qmsg.ptl.x ||
1347 wheelMsg.ptl.y != qmsg.ptl.y)
1348 break;
1349 WinPeekMsg(0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_REMOVE);
1350 }
1351 }
1352
1353 int delta;
1354 USHORT cmd = SHORT2FROMMP(qmsg.mp2);
1355 switch (cmd) {
1356 case SB_LINEUP:
1357 case SB_PAGEUP:
1358 delta = WHEEL_DELTA;
1359 break;
1360 case SB_LINEDOWN:
1361 case SB_PAGEDOWN:
1362 delta = -WHEEL_DELTA;
1363 break;
1364 default:
1365 return false;
1366 }
1367
1368 int state = 0;
1369 if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT ) & 0x8000)
1370 state |= Qt::ShiftModifier;
1371 if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000 ||
1372 (qt_extraKeyState & Qt::AltModifier))
1373 state |= Qt::AltModifier;
1374 if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
1375 state |= Qt::ControlModifier;
1376 if (qt_extraKeyState & Qt::MetaModifier)
1377 state |= Qt::MetaModifier;
1378
1379 Qt::Orientation orient;
1380 // Alt inverts scroll orientation (Qt/Win32 behavior)
1381 if (state & Qt::AltModifier)
1382 orient = qmsg.msg == WM_VSCROLL ? Qt::Horizontal : Qt::Vertical;
1383 else
1384 orient = qmsg.msg == WM_VSCROLL ? Qt::Vertical : Qt::Horizontal;
1385
1386 QPoint globalPos(qmsg.ptl.x, qmsg.ptl.y);
1387
1388 // if there is a widget under the mouse and it is not shadowed
1389 // by modality, we send the event to it first
1390 MRESULT rc = FALSE;
1391 QWidget* w = QApplication::widgetAt(globalPos);
1392 if (!w || !qt_try_modal(w, (QMSG*)&qmsg, rc)) {
1393 //synaptics touchpad shows its own widget at this position
1394 //so widgetAt() will fail with that HWND, try child of this widget
1395 w = this->childAt(this->mapFromGlobal(globalPos));
1396 if (!w)
1397 w = this;
1398 }
1399
1400 // send the event to the widget or its ancestors
1401 {
1402 QWidget* popup = qApp->activePopupWidget();
1403 if (popup && w->window() != popup)
1404 popup->close();
1405#ifndef QT_NO_WHEELEVENT
1406 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
1407 Qt::MouseButtons(state & Qt::MouseButtonMask),
1408 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
1409
1410 if (QApplication::sendSpontaneousEvent(w, &e))
1411#else
1412 Q_UNUSED(orient);
1413#endif //QT_NO_WHEELEVENT
1414 return true;
1415 }
1416
1417 // send the event to the widget that has the focus or its ancestors, if different
1418 if (w != qApp->focusWidget() && (w = qApp->focusWidget())) {
1419 QWidget* popup = qApp->activePopupWidget();
1420 if (popup && w->window() != popup)
1421 popup->close();
1422#ifndef QT_NO_WHEELEVENT
1423 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
1424 Qt::MouseButtons(state & Qt::MouseButtonMask),
1425 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
1426 if (QApplication::sendSpontaneousEvent(w, &e))
1427#endif //QT_NO_WHEELEVENT
1428 return true;
1429 }
1430
1431 return false;
1432}
1433#endif
1434
1435//
1436// Paint event translation
1437//
1438bool QETWidget::translatePaintEvent(const QMSG &qmsg)
1439{
1440 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
1441 Q_ASSERT(internalWinId());
1442
1443 HPS displayPS = qt_display_ps();
1444
1445 // Since we don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN bits (see
1446 // qwidget_pm.cpp), we have to validate areas that intersect with our
1447 // children and siblings, taking their clip regions into account.
1448// validateObstacles();
1449
1450 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1451
1452 HRGN hrgn = GpiCreateRegion(displayPS, 0, NULL);
1453 LONG rc = WinQueryUpdateRegion(internalWinId(), hrgn);
1454 if (rc == RGN_ERROR) { // The update bounding rect is invalid
1455 GpiDestroyRegion(displayPS, hrgn);
1456 d_func()->hd = NULLHANDLE;
1457 setAttribute(Qt::WA_PendingUpdate, false);
1458 return false;
1459 }
1460
1461 setAttribute(Qt::WA_PendingUpdate, false);
1462
1463 // @todo not sure we need it
1464// const QRegion dirtyInBackingStore(qt_dirtyRegion(this));
1465// // Make sure the invalidated region contains the region we're about to repaint.
1466// // BeginPaint will set the clip to the invalidated region and it is impossible
1467// // to enlarge it afterwards (only shrink it). Using GetDCEx is not suffient
1468// // as it may return an invalid context (especially on Windows Vista).
1469// if (!dirtyInBackingStore.isEmpty())
1470// InvalidateRgn(internalWinId(), dirtyInBackingStore.handle(), false);
1471
1472 RECTL rcl;
1473 d_func()->hd = WinBeginPaint(internalWinId(), 0, &rcl);
1474
1475 // it's possible that the update rectangle is empty
1476 if (rcl.xRight <= rcl.xLeft || rcl.yTop <= rcl.yBottom) {
1477 WinEndPaint(d_func()->hd);
1478 GpiDestroyRegion(displayPS, hrgn);
1479 d_func()->hd = NULLHANDLE;
1480 setAttribute(Qt::WA_PendingUpdate, false);
1481 return true;
1482 }
1483
1484 if (WinQueryClipRegion( internalWinId(), 0) != QCRGN_NO_CLIP_REGION) {
1485 // Correct the update region by intersecting it with the clip
1486 // region (PM doesn't do that itself). It is necessary
1487 // to have a correct QRegion in QPaintEvent.
1488 HRGN hcrgn = GpiCreateRegion(displayPS, 0, NULL);
1489 WinQueryClipRegion(internalWinId(), hcrgn);
1490 GpiCombineRegion(displayPS, hrgn, hrgn, hcrgn, CRGN_AND);
1491 GpiDestroyRegion(displayPS, hcrgn);
1492 }
1493
1494 // flip y coordinate
1495 rcl.yBottom = height() - (rcl.yBottom + 1);
1496 rcl.yTop = height() - (rcl.yTop + 1);
1497
1498 const QRect updateRect(QPoint(rcl.xLeft, rcl.yBottom),
1499 QPoint(rcl.xRight, rcl.yTop));
1500
1501 // Mapping region from system to qt (32 bit) coordinate system.
1502 // @todo use hrgn here once we implement QRegion<->HRGN relationship
1503 d_func()->syncBackingStore(updateRect.translated(data->wrect.topLeft()));
1504
1505 WinEndPaint(d_func()->hd);
1506 d_func()->hd = NULLHANDLE;
1507
1508 return true;
1509}
1510
1511//
1512// Window move and resize (configure) events
1513//
1514
1515bool QETWidget::translateConfigEvent(const QMSG &qmsg)
1516{
1517 // @todo implement
1518 return false;
1519}
1520
1521//
1522// Close window event translation.
1523//
1524// This class is a friend of QApplication because it needs to emit the
1525// lastWindowClosed() signal when the last top level widget is closed.
1526//
1527
1528bool QETWidget::translateCloseEvent(const QMSG &)
1529{
1530 return d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
1531}
1532
1533QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.