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

Last change on this file was 1034, checked in by Dmitry A. Kuminov, 14 years ago

OS/2: Disable native window masking code as it is not complete.

This code is only necessary for child widgets that have native windows.
Applications using this approach are very rare (they include e.g. video
players that paint to Qt widgets on their own using native window IDs)
and they don't need masking in these widgets or their ancestors anyway.

The current implementation lacks some functionality -- in particular, it
cannot properly issue WM_VRNENABLED/WM_VRNDISABLED notifications
which breaks those video players, so that keeping it enabled makes little
to no sense.

The relevant code remains in place but guarded by the
QT_PM_NATIVEWIDGETMASK compiler macro so that it can be enabled
as needed for further experiments. See also #203 for more details.

File size: 109.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** Copyright (C) 2010 netlabs.org. OS/2 parts.
8**
9** This file is part of the QtGui module of the Qt Toolkit.
10**
11** $QT_BEGIN_LICENSE:LGPL$
12** Commercial Usage
13** Licensees holding valid Qt Commercial licenses may use this file in
14** accordance with the Qt Commercial License Agreement provided with the
15** Software or, alternatively, in accordance with the terms contained in
16** a written agreement between you and Nokia.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 2.1 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 2.1 requirements
24** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** In addition, as a special exception, Nokia gives you certain additional
27** rights. These rights are described in the Nokia Qt LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
39** Nokia at qt-info@nokia.com.
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include "qt_os2.h"
45
46#include "qdebug.h"
47
48#include "qapplication.h"
49#include "qapplication_p.h"
50
51#include "qwidget.h"
52#include "qpointer.h"
53#include "qcolormap.h"
54#include "qpixmapcache.h"
55#include "qdesktopwidget.h"
56#include "qsessionmanager.h"
57
58#include "qset.h"
59
60#include "private/qeventdispatcher_pm_p.h"
61#include "private/qbackingstore_p.h"
62
63#include "qwidget_p.h"
64#include "qkeymapper_p.h"
65#include "qcursor_p.h"
66#include "qdnd_p.h"
67
68#define WM_KBDLAYERCHANGED 0x0BD4 // defined in OS2TK45/h/pmbidi.h
69
70//#define QT_DEBUGMSGFLOW
71
72QT_BEGIN_NAMESPACE
73
74/*****************************************************************************
75 Internal variables and functions
76 *****************************************************************************/
77
78static HWND curWin = 0; // current window
79static HPS displayPS = 0; // display presentation space
80
81#if !defined (QT_NO_SESSIONMANAGER)
82
83//#define DEBUG_SESSIONMANAGER
84
85// Session management
86static bool sm_blockUserInput = false;
87static bool sm_smActive = false;
88static bool sm_cancel = false;
89static bool sm_gracefulShutdown = false;
90static bool sm_quitSkipped = false;
91
92extern QSessionManager *qt_session_manager_self; // defined in qapplication.cpp
93extern bool qt_about_to_destroy_wnd; // defined in qwidget_pm.cpp
94
95#endif
96
97static bool replayPopupMouseEvent = false; // replay handling when popups close
98
99// ignore the next release event if return from a modal widget
100static bool ignoreNextMouseReleaseEvent = false;
101
102#if defined(QT_DEBUG)
103static bool appNoGrab = false; // mouse/keyboard grabbing
104#endif
105
106static bool app_do_modal = false; // modal mode
107extern QWidgetList *qt_modal_stack;
108extern QDesktopWidget *qt_desktopWidget;
109static QPointer<QWidget> popupButtonFocus;
110static bool qt_try_modal(QWidget*, QMSG*, MRESULT&);
111
112QWidget *qt_button_down = 0; // widget got last button-down
113QPointer<QWidget> qt_last_mouse_receiver = 0;
114
115static HWND foreignActiveWnd = NULLHANDLE;
116static HWND foreignFocusWnd = NULLHANDLE;
117
118static HWND autoCaptureWnd = NULLHANDLE;
119static bool autoCaptureReleased = false;
120static void setAutoCapture(HWND); // automatic capture
121static void releaseAutoCapture();
122
123extern QCursor *qt_grab_cursor();
124
125#ifdef QT_PM_NATIVEWIDGETMASK
126extern void qt_WinQueryClipRegionOrRect(HWND hwnd, HRGN hrgn); // qwidget_pm.cpp
127#endif
128
129extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication.cpp
130
131extern QRegion qt_dirtyRegion(QWidget *); // qbackingstore.cpp
132
133MRESULT EXPENTRY QtWndProc(HWND, ULONG, MPARAM, MPARAM);
134
135class QETWidget : public QWidget // event translator widget
136{
137public:
138 QWExtra *xtra() { return d_func()->extraData(); }
139 QTLWExtra *topData() { return d_func()->topData(); }
140 QTLWExtra *maybeTopData() { return d_func()->maybeTopData(); }
141// @todo later
142// void syncBackingStore(const QRegion &rgn) { d_func()->syncBackingStore(rgn); }
143// void syncBackingStore() { d_func()->syncBackingStore(); }
144 QWidgetData *dataPtr() { return data; }
145 QWidgetPrivate *dptr() { return d_func(); }
146 QRect frameStrut() const { return d_func()->frameStrut(); }
147 HWND frameWinId() const { return d_func()->frameWinId(); }
148 QETWidget* modalBlocker() const { return (QETWidget *)d_func()->modalBlocker(); }
149 bool pmEvent(QMSG *m, MRESULT *r) { return QWidget::pmEvent(m, r); }
150// void markFrameStrutDirty() { data->fstrut_dirty = 1; }
151 bool translateMouseEvent(const QMSG &qmsg);
152 void translateNonClientMouseEvent(const QMSG &qmsg);
153#ifndef QT_NO_WHEELEVENT
154 bool translateWheelEvent(const QMSG &qmsg);
155#endif
156 bool translatePaintEvent(const QMSG &qmsg);
157 bool translateConfigEvent(const QMSG &qmsg);
158 bool translateCloseEvent(const QMSG &qmsg);
159// void repolishStyle(QStyle &style);
160// inline void showChildren(bool spontaneous) { d_func()->showChildren(spontaneous); }
161// inline void hideChildren(bool spontaneous) { d_func()->hideChildren(spontaneous); }
162// inline void validateObstacles() { d_func()->validateObstacles(); }
163// inline uint testWindowState(uint teststate){ return dataPtr()->window_state & teststate; }
164// inline void forceUpdate() {
165// QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
166// if (tlwExtra && tlwExtra->backingStore)
167// tlwExtra->backingStore->markDirty(rect(), this, true, true);
168// }
169};
170
171static QRgb qt_sysclr2qrgb(LONG sysClr)
172{
173 // QRgb has the same RGB format (0xaarrggbb) as OS/2 uses (ignoring the
174 // highest alpha byte) so we just cast the OS/2 LONG RGB value to qRgb
175 // which is an unsigned int actually.
176 return ((QRgb)WinQuerySysColor(HWND_DESKTOP, sysClr, 0)) & RGB_MASK;
177}
178
179static QFont qt_sysfont2qfont(PCSZ scope)
180{
181 // note: 10.System Proportional is de-facto the default font selected into
182 // the presentation space
183
184 static PCSZ app = "PM_SystemFonts";
185 static PCSZ def = "10.System Proportional";
186
187 ULONG keyLen = 0;
188 QFont f(QLatin1String("System Proportional"), 10);
189
190 if (PrfQueryProfileSize(HINI_USERPROFILE, app, scope, &keyLen) && keyLen) {
191 keyLen++; // reserve space for the dot
192 char *buf = new char[keyLen];
193 ULONG realLen = PrfQueryProfileString(HINI_USERPROFILE, app, scope, def,
194 buf, keyLen);
195 realLen--; // excude terminating NULL
196
197 // parse the font definition
198 int height = 0;
199 char *dot = strchr(buf, '.'), *dot2 = 0;
200 if (dot) {
201 *dot = 0;
202 height = strtoul(buf, NULL, 10);
203 dot2 = strchr(++ dot, '.');
204 if (dot2) {
205 // process simulated styles
206 buf[realLen] = '.';
207 buf[realLen+1] = 0;
208 strupr( dot2 );
209 // @todo currently, simulated bold and italic font styles are not
210 // supported by Qt/OS2 because Qt doesn't support style simulation
211 // explicitly. the code below is commented out to prevent selecting
212 // true fonts when simulated ones are actually requested.
213 // if (strstr(dot2, ".BOLD.")) f.setBold(true);
214 // if (strstr(dot2, ".ITALIC.")) f.setItalic(true);
215 if (strstr(dot2, ".UNDERSCORE.")) f.setUnderline(true);
216 if (strstr(dot2, ".UNDERLINED.")) f.setUnderline(true);
217 if (strstr(dot2, ".STRIKEOUT.")) f.setStrikeOut(true);
218 *dot2 = 0;
219 }
220 // query non-simulated styles
221 FONTMETRICS fm;
222 LONG cnt = 1; // use the first match
223 GpiQueryFonts(qt_display_ps(), QF_PUBLIC, dot, &cnt, sizeof(FONTMETRICS), &fm);
224 if (cnt) {
225 if (fm.fsSelection & FM_SEL_ITALIC) f.setItalic(true);
226 if (fm.fsType & FM_TYPE_FIXED) f.setFixedPitch(true);
227 USHORT weight = fm.usWeightClass;
228 USHORT width = fm.usWidthClass;
229 if (weight < 4) f.setWeight( QFont::Light );
230 else if (weight < 6) f.setWeight(QFont::Normal);
231 else if (weight < 7) f.setWeight(QFont::DemiBold);
232 else if (weight < 8) f.setWeight(QFont::Bold);
233 else f.setWeight(QFont::Black);
234 switch (width) {
235 case 1: f.setStretch(QFont::UltraCondensed); break;
236 case 2: f.setStretch(QFont::ExtraCondensed); break;
237 case 3: f.setStretch(QFont::Condensed); break;
238 case 4: f.setStretch(QFont::SemiCondensed); break;
239 case 5: f.setStretch(QFont::Unstretched); break;
240 case 6: f.setStretch(QFont::SemiExpanded); break;
241 case 7: f.setStretch(QFont::Expanded); break;
242 case 8: f.setStretch(QFont::ExtraExpanded); break;
243 case 9: f.setStretch(QFont::UltraExpanded); break;
244 default: f.setStretch(QFont::Unstretched); break;
245 }
246 f.setFamily(QString::fromLocal8Bit(fm.szFamilyname));
247 f.setPointSize(height);
248 }
249 }
250 delete[] buf;
251 }
252 return f;
253}
254
255static void qt_set_pm_resources()
256{
257 QFont menuFont = qt_sysfont2qfont("Menus");
258 QFont iconFont = qt_sysfont2qfont("IconText");
259 QFont titleFont = qt_sysfont2qfont("WindowTitles");
260
261 QApplication::setFont(menuFont, "QMenu");
262 QApplication::setFont(menuFont, "QMenuBar");
263 QApplication::setFont(titleFont, "Q3TitleBar");
264 QApplication::setFont(titleFont, "QWorkspaceTitleBar");
265 QApplication::setFont(iconFont, "QAbstractItemView");
266 QApplication::setFont(iconFont, "QDockWidgetTitle");
267
268 // let QPallette calculate all colors automatically based on the
269 // base PM window background color -- to be on the safe side in case if we
270 // don't set some role explicitly below (like QPalette::AlternateBase)
271 QPalette pal = QPalette(QColor(qt_sysclr2qrgb(SYSCLR_DIALOGBACKGROUND)));
272
273 pal.setColor(QPalette::WindowText,
274 QColor(qt_sysclr2qrgb(SYSCLR_WINDOWTEXT)));
275 pal.setColor(QPalette::Window,
276 QColor(qt_sysclr2qrgb(SYSCLR_DIALOGBACKGROUND)));
277 pal.setColor(QPalette::ButtonText,
278 QColor(qt_sysclr2qrgb(SYSCLR_MENUTEXT)));
279 pal.setColor(QPalette::Button,
280 QColor(qt_sysclr2qrgb(SYSCLR_BUTTONMIDDLE)));
281 pal.setColor(QPalette::Light,
282 QColor(qt_sysclr2qrgb(SYSCLR_BUTTONLIGHT)));
283 pal.setColor(QPalette::Dark,
284 QColor(qt_sysclr2qrgb(SYSCLR_BUTTONDARK)));
285 pal.setColor(QPalette::Midlight,
286 QColor((pal.light().color().red() + pal.button().color().red()) / 2,
287 (pal.light().color().green() + pal.button().color().green()) / 2,
288 (pal.light().color().blue() + pal.button().color().blue()) / 2));
289 pal.setColor(QPalette::Mid,
290 QColor((pal.dark().color().red() + pal.button().color().red()) / 2,
291 (pal.dark().color().green() + pal.button().color().green()) / 2,
292 (pal.dark().color().blue() + pal.button().color().blue()) / 2));
293 pal.setColor(QPalette::Shadow, // note: SYSCLR_SHADOW often = SYSCLR_BUTTONDARK
294 QColor(qt_sysclr2qrgb(SYSCLR_BUTTONDEFAULT)));
295 pal.setColor(QPalette::Text,
296 QColor(qt_sysclr2qrgb(SYSCLR_WINDOWTEXT)));
297 pal.setColor(QPalette::Base,
298 QColor(qt_sysclr2qrgb(SYSCLR_ENTRYFIELD)));
299 pal.setColor(QPalette::BrightText,
300 QColor(qt_sysclr2qrgb(SYSCLR_BUTTONLIGHT)));
301 pal.setColor(QPalette::Highlight,
302 QColor(qt_sysclr2qrgb(SYSCLR_HILITEBACKGROUND)));
303 pal.setColor(QPalette::HighlightedText,
304 QColor(qt_sysclr2qrgb(SYSCLR_HILITEFOREGROUND)));
305 // these colors are not present in the PM system palette
306 pal.setColor(QPalette::Link, Qt::blue);
307 pal.setColor(QPalette::LinkVisited, Qt::magenta);
308
309 // disabled colors
310 // note: it should be SYSCLR_MENUDISABLEDTEXT but many styles use etched
311 // appearance for disabled elements (in combination with QPalette::Light)
312 // which gives weakly readable text. Make it somewhat darker.
313 pal.setColor(QPalette::Disabled, QPalette::WindowText,
314 QColor(qt_sysclr2qrgb(SYSCLR_BUTTONDARK)));
315 pal.setColor(QPalette::Disabled, QPalette::ButtonText,
316 QColor(qt_sysclr2qrgb(SYSCLR_BUTTONDARK)));
317 pal.setColor(QPalette::Disabled, QPalette::Text,
318 QColor(qt_sysclr2qrgb(SYSCLR_BUTTONDARK)));
319
320 QApplicationPrivate::setSystemPalette(pal);
321
322 // special palete: menus
323 QPalette spal = pal;
324 spal.setColor(QPalette::Window,
325 QColor(qt_sysclr2qrgb(SYSCLR_MENU)));
326 spal.setColor(QPalette::WindowText,
327 QColor(qt_sysclr2qrgb(SYSCLR_MENUTEXT)));
328 spal.setColor(QPalette::Highlight,
329 QColor(qt_sysclr2qrgb( SYSCLR_MENUHILITEBGND)));
330 spal.setColor(QPalette::HighlightedText,
331 QColor(qt_sysclr2qrgb(SYSCLR_MENUHILITE)));
332
333 QApplication::setPalette(spal, "QMenu");
334 QApplication::setPalette(spal, "QMenuBar");
335
336 // special palete: static widget text
337 spal = pal;
338 QColor staticTextCol(qt_sysclr2qrgb( SYSCLR_WINDOWSTATICTEXT));
339 spal.setColor(QPalette::WindowText, staticTextCol);
340 spal.setColor(QPalette::Text, staticTextCol);
341
342 QApplication::setPalette(spal, "QLabel");
343 QApplication::setPalette(spal, "QGroupBox");
344};
345
346/*****************************************************************************
347 qt_init() - initializes Qt for PM
348 *****************************************************************************/
349
350void qt_init(QApplicationPrivate *priv, int)
351{
352 int argc = priv->argc;
353 char **argv = priv->argv;
354 int i, j;
355
356 // Get command line params
357
358 j = argc ? 1 : 0;
359 for (i=1; i<argc; i++) {
360 if (argv[i] && *argv[i] != '-') {
361 argv[j++] = argv[i];
362 continue;
363 }
364#if defined(QT_DEBUG)
365 if (qstrcmp(argv[i], "-nograb") == 0)
366 appNoGrab = !appNoGrab;
367 else
368#endif // QT_DEBUG
369 argv[j++] = argv[i];
370 }
371 if(j < priv->argc) {
372 priv->argv[j] = 0;
373 priv->argc = j;
374 }
375
376 displayPS = WinGetScreenPS(HWND_DESKTOP);
377
378 // initialize key mapper
379 QKeyMapper::changeKeyboard();
380
381 QColormap::initialize();
382 QFont::initialize();
383#ifndef QT_NO_CURSOR
384 QCursorData::initialize();
385#endif
386 qApp->setObjectName(priv->appName());
387
388 // @todo search for QTPM_USE_WINDOWFONT in Qt3 for OS/2 sources for a
389 // discussion on whether to use PM_Fonts/DefaultFont or WindowText as the
390 // default one. So far, the latter is used.
391 QApplicationPrivate::setSystemFont(qt_sysfont2qfont("WindowText"));
392
393 // QFont::locale_init(); ### Uncomment when it does something on OS/2
394
395 if (QApplication::desktopSettingsAware())
396 qt_set_pm_resources();
397}
398
399/*****************************************************************************
400 qt_cleanup() - cleans up when the application is finished
401 *****************************************************************************/
402
403void qt_cleanup()
404{
405 QPixmapCache::clear();
406
407#ifndef QT_NO_CURSOR
408 QCursorData::cleanup();
409#endif
410 QFont::cleanup();
411 QColormap::cleanup();
412
413 WinReleasePS(displayPS);
414 displayPS = 0;
415
416#ifdef QT_LOG_BLITSPEED
417 extern unsigned long long qt_total_blit_ms;
418 extern unsigned long long qt_total_blit_pixels;
419 printf("*** qt_total_blit_ms : %llu\n"
420 "*** qt_total_blit_pixels : %llu\n"
421 "*** average speed, px/ms : %llu\n",
422 qt_total_blit_ms, qt_total_blit_pixels,
423 qt_total_blit_pixels / qt_total_blit_ms);
424#endif
425}
426
427/*****************************************************************************
428 Platform specific global and internal functions
429 *****************************************************************************/
430
431Q_GUI_EXPORT HPS qt_display_ps()
432{
433 Q_ASSERT(qApp);
434 if (!qApp)
435 return NULLHANDLE;
436 return displayPS;
437}
438
439Q_GUI_EXPORT int qt_display_width()
440{
441 // display resolution is constant for any given bootup
442 static LONG displayWidth = 0;
443 if (displayWidth == 0)
444 displayWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
445 return displayWidth;
446}
447
448Q_GUI_EXPORT int qt_display_height()
449{
450 // display resolution is constant for any given bootup
451 static LONG displayHeight = 0;
452 if (displayHeight == 0)
453 displayHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
454 return displayHeight;
455}
456
457/*!
458 Returns a QWidget pointer or 0 if there is no widget corresponding to the
459 given HWND. As opposed to QWidget::find(), correctly handles WC_FRAME
460 windows created for top level widgets.
461 */
462QWidget *qt_widget_from_hwnd(HWND hwnd)
463{
464 char buf[10];
465 if (WinQueryClassName(hwnd, sizeof(buf), buf)) {
466 if (!strcmp(buf, "#1")) // WC_FRAME
467 hwnd = WinWindowFromID(hwnd, FID_CLIENT);
468 return QWidget::find(hwnd);
469 }
470 return 0;
471}
472
473// application no-grab option
474bool qt_nograb()
475{
476#if defined(QT_DEBUG)
477 return appNoGrab;
478#else
479 return false;
480#endif
481}
482
483/*****************************************************************************
484 Safe configuration (move,resize,setGeometry) mechanism to avoid
485 recursion when processing messages.
486 *****************************************************************************/
487
488struct QPMConfigRequest {
489 WId id; // widget to be configured
490 int req; // 0=move, 1=resize, 2=setGeo
491 int x, y, w, h; // request parameters
492};
493
494Q_GLOBAL_STATIC(QList<QPMConfigRequest*>, configRequests);
495
496void qPMRequestConfig(WId id, int req, int x, int y, int w, int h)
497{
498 QPMConfigRequest *r = new QPMConfigRequest;
499 r->id = id;
500 r->req = req;
501 r->x = x;
502 r->y = y;
503 r->w = w;
504 r->h = h;
505 configRequests()->append(r);
506}
507
508/*****************************************************************************
509 GUI event dispatcher
510 *****************************************************************************/
511
512class QGuiEventDispatcherPM : public QEventDispatcherPM
513{
514public:
515 QGuiEventDispatcherPM(QObject *parent = 0);
516 bool processEvents(QEventLoop::ProcessEventsFlags flags);
517};
518
519QGuiEventDispatcherPM::QGuiEventDispatcherPM(QObject *parent)
520 : QEventDispatcherPM(parent)
521{
522 // pre-create the message queue early as we'll need it anyway in GUI mode
523 createMsgQueue();
524}
525
526bool QGuiEventDispatcherPM::processEvents(QEventLoop::ProcessEventsFlags flags)
527{
528 if (!QEventDispatcherPM::processEvents(flags))
529 return false;
530
531 QPMConfigRequest *r;
532 for (;;) {
533 if (configRequests()->isEmpty())
534 break;
535 r = configRequests()->takeLast();
536 QWidget *w = QWidget::find(r->id);
537 QRect rect(r->x, r->y, r->w, r->h);
538 int req = r->req;
539 delete r;
540
541 if (w) { // widget exists
542 if (w->testAttribute(Qt::WA_WState_ConfigPending))
543 break; // biting our tail
544 if (req == 0)
545 w->move(rect.topLeft());
546 else if (req == 1)
547 w->resize(rect.size());
548 else
549 w->setGeometry(rect);
550 }
551 }
552
553 return true;
554}
555
556void QApplicationPrivate::createEventDispatcher()
557{
558 Q_Q(QApplication);
559 if (q->type() != QApplication::Tty)
560 eventDispatcher = new QGuiEventDispatcherPM(q);
561 else
562 eventDispatcher = new QEventDispatcherPM(q);
563}
564
565/*****************************************************************************
566 Platform specific QApplication members
567 *****************************************************************************/
568
569void QApplicationPrivate::initializeWidgetPaletteHash()
570{
571}
572
573QString QApplicationPrivate::appName() const
574{
575 return QCoreApplicationPrivate::appName();
576}
577
578void QApplication::setCursorFlashTime(int msecs)
579{
580 WinSetSysValue(HWND_DESKTOP, SV_CURSORRATE, msecs / 2);
581 QApplicationPrivate::cursor_flash_time = msecs;
582}
583
584int QApplication::cursorFlashTime()
585{
586 int blink = (int)WinQuerySysValue(HWND_DESKTOP, SV_CURSORRATE);
587 if (!blink)
588 return QApplicationPrivate::cursor_flash_time;
589 if (blink > 0)
590 return 2 * blink;
591 return 0;
592}
593
594void QApplication::setDoubleClickInterval(int ms)
595{
596 WinSetSysValue(HWND_DESKTOP, SV_DBLCLKTIME, ms);
597 QApplicationPrivate::mouse_double_click_time = ms;
598}
599
600int QApplication::doubleClickInterval()
601{
602 int ms = (int) WinQuerySysValue(HWND_DESKTOP, SV_DBLCLKTIME);
603 if (ms != 0)
604 return ms;
605 return QApplicationPrivate::mouse_double_click_time;
606}
607
608void QApplication::setKeyboardInputInterval(int ms)
609{
610 QApplicationPrivate::keyboard_input_time = ms;
611}
612
613int QApplication::keyboardInputInterval()
614{
615 // FIXME: get from the system
616 return QApplicationPrivate::keyboard_input_time;
617}
618
619#ifndef QT_NO_WHEELEVENT
620void QApplication::setWheelScrollLines(int n)
621{
622 QApplicationPrivate::wheel_scroll_lines = n;
623}
624
625int QApplication::wheelScrollLines()
626{
627 return QApplicationPrivate::wheel_scroll_lines;
628}
629#endif //QT_NO_WHEELEVENT
630
631void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
632{
633 // @todo implement
634}
635
636bool QApplication::isEffectEnabled(Qt::UIEffect effect)
637{
638 // @todo implement
639 return false;
640}
641
642void QApplication::beep()
643{
644 WinAlarm(HWND_DESKTOP, WA_WARNING);
645}
646
647void QApplication::alert(QWidget *widget, int duration)
648{
649 // @todo implement
650}
651
652/*****************************************************************************
653 QApplication cursor stack
654 *****************************************************************************/
655
656#ifndef QT_NO_CURSOR
657
658void QApplication::setOverrideCursor(const QCursor &cursor)
659{
660 qApp->d_func()->cursor_list.prepend(cursor);
661 WinSetPointer(HWND_DESKTOP, qApp->d_func()->cursor_list.first().handle());
662}
663
664void QApplication::restoreOverrideCursor()
665{
666 if (qApp->d_func()->cursor_list.isEmpty())
667 return;
668 qApp->d_func()->cursor_list.removeFirst();
669
670 if (!qApp->d_func()->cursor_list.isEmpty()) {
671 WinSetPointer(HWND_DESKTOP, qApp->d_func()->cursor_list.first().handle());
672 } else {
673 QWidget *w = QWidget::find(curWin);
674 if (w)
675 WinSetPointer(HWND_DESKTOP, w->cursor().handle());
676 else
677 WinSetPointer(HWND_DESKTOP, QCursor(Qt::ArrowCursor).handle());
678 }
679}
680
681/*
682 Internal function called from QWidget::setCursor()
683
684 force is true if this function is called from dispatchEnterLeave, it means
685 that the mouse is actually directly under this widget.
686*/
687void qt_pm_set_cursor(QWidget *w, bool force)
688{
689 static QPointer<QWidget> lastUnderMouse = 0;
690 if (force) {
691 lastUnderMouse = w;
692 } else if (w->testAttribute(Qt::WA_WState_Created) && lastUnderMouse
693 && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) {
694 w = lastUnderMouse;
695 }
696
697 if (!curWin && w && w->internalWinId())
698 return;
699 QWidget* cW = w && !w->internalWinId() ? w : QWidget::find(curWin);
700 if (!cW || cW->window() != w->window() ||
701 !cW->isVisible() || !cW->underMouse() || QApplication::overrideCursor())
702 return;
703
704 WinSetPointer(HWND_DESKTOP, cW->cursor().handle());
705}
706
707#endif // QT_NO_CURSOR
708
709/*****************************************************************************
710 Routines to find a Qt widget from a screen position
711 *****************************************************************************/
712
713QWidget *QApplication::topLevelAt(const QPoint &pos)
714{
715 // flip y coordinate
716 int y = qt_display_height() - (pos.y() + 1);
717 POINTL ptl = { pos.x(), y };
718 HWND hwnd = WinWindowFromPoint(HWND_DESKTOP, &ptl, FALSE);
719 if (hwnd == NULLHANDLE)
720 return 0;
721
722 QWidget *w = qt_widget_from_hwnd(hwnd);
723 return w ? w->window() : 0;
724}
725
726/*****************************************************************************
727 Main event loop
728 *****************************************************************************/
729
730// sent to hwnd that has been entered to by a mouse pointer.
731// FID_CLIENT also receives enter messages of its WC_FRAME.
732// mp1 = hwnd that is entered, mp2 = hwnd that is left
733#define WM_U_MOUSEENTER 0x41E
734// sent to hwnd that has been left by a mouse pointer.
735// FID_CLIENT also receives leave messages of its WC_FRAME.
736// mp1 = hwnd that is left, mp2 = hwnd that is entered
737#define WM_U_MOUSELEAVE 0x41F
738
739// some undocumented system values
740#define SV_WORKAREA_YTOP 51
741#define SV_WORKAREA_YBOTTOM 52
742#define SV_WORKAREA_XRIGHT 53
743#define SV_WORKAREA_XLEFT 54
744
745/*!
746 \internal
747 \since 4.1
748
749 If \a gotFocus is true, \a widget will become the active window.
750 Otherwise the active window is reset to 0.
751*/
752void QApplication::pmFocus(QWidget *widget, bool gotFocus)
753{
754 if (gotFocus) {
755 setActiveWindow(widget);
756 if (QApplicationPrivate::active_window
757 && (QApplicationPrivate::active_window->windowType() == Qt::Dialog)) {
758 // raise the entire application, not just the dialog
759 QWidget* mw = QApplicationPrivate::active_window;
760 while(mw->parentWidget() && (mw->windowType() == Qt::Dialog))
761 mw = mw->parentWidget()->window();
762 if (mw->testAttribute(Qt::WA_WState_Created) && mw != QApplicationPrivate::active_window)
763 WinSetWindowPos(mw->d_func()->frameWinId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
764 }
765 } else {
766 setActiveWindow(0);
767 }
768}
769
770// QMSG wrapper that translates message coordinates from PM to Qt
771struct QtQmsg : public QMSG
772{
773 QtQmsg(HWND aHwnd, ULONG aMsg, MPARAM aMp1, MPARAM aMp2)
774 {
775 hwnd = aHwnd;
776 msg = aMsg;
777 mp1 = aMp1;
778 mp2 = aMp2;
779 time = WinQueryMsgTime(0);
780
781 isTranslatableMouseEvent =
782 (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
783 (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST);
784
785 if (isTranslatableMouseEvent || msg == WM_CONTEXTMENU) {
786 ptl.x = (short)SHORT1FROMMP(mp1);
787 ptl.y = (short)SHORT2FROMMP(mp1);
788 WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptl, 1);
789 } else {
790 WinQueryMsgPos(0, &ptl);
791 }
792 // flip y coordinate
793 ptl.y = qt_display_height() - (ptl.y + 1);
794 }
795
796 bool isTranslatableMouseEvent;
797};
798
799// QtWndProc() receives all messages from the main event loop
800
801MRESULT EXPENTRY QtWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
802{
803 do {
804 if (!qApp) // unstable app state
805 break;
806#if 0
807 // make sure we show widgets (e.g. scrollbars) when the user resizes
808 if (qApp->loopLevel())
809 qApp->sendPostedEvents(0, QEvent::ShowWindowRequest);
810#endif
811
812 MRESULT rc = (MRESULT) FALSE;
813 QETWidget *widget = 0;
814
815 QtQmsg qmsg(hwnd, msg, mp1, mp2);
816
817#if defined(QT_DEBUGMSGFLOW)
818 if (qmsg.msg != WM_QUERYICON)
819 qDebug() << "*** [W]" << qmsg;
820#endif
821
822 // send through app filter
823 if (qApp->filterEvent(&qmsg, reinterpret_cast<long *>(&rc)))
824 return rc;
825
826 switch(msg) {
827
828#if !defined(QT_NO_SESSIONMANAGER)
829 case WM_SAVEAPPLICATION: {
830#if defined(DEBUG_SESSIONMANAGER)
831 qDebug("WM_SAVEAPPLICATION: sm_gracefulShutdown %d, "
832 "qt_about_to_destroy_wnd %d, (mp1 %p, mp2 %p)",
833 sm_gracefulShutdown, qt_about_to_destroy_wnd, mp1, mp2);
834#endif
835 // PM seems to post this message to all top-level windows on system
836 // shutdown, so react only to the first one. Also, this message is
837 // always sent by WinDestroyWindow(), where it must be also ignored.
838 if (!qt_about_to_destroy_wnd && !sm_smActive &&
839 !sm_gracefulShutdown) {
840 sm_smActive = true;
841 sm_gracefulShutdown = true;
842 sm_blockUserInput = true; // prevent user-interaction outside interaction windows
843 sm_cancel = false;
844 sm_quitSkipped = false;
845 if (qt_session_manager_self)
846 qApp->commitData(*qt_session_manager_self);
847 sm_smActive = false; // session management has been finished
848 if (sm_cancel) {
849#if defined(DEBUG_SESSIONMANAGER)
850 qDebug("WM_SAVEAPPLICATION: sm_cancel %d", sm_cancel);
851#endif
852 // @todo propagate the patch that does the below to XWP
853 // and enable the code when it appears upstream (see #100)
854#if 0
855 // Here we try to cancel the Extended XWorkplace shutdown.
856 // If it's XWorkplace who sent us WM_SAVEAPPLICATION, then
857 // it probably passed us non-NULL parameters so that
858 // mp1 = its window handle and mp2 = WM_COMMAND code to
859 // cancel the shutdown procedure.
860 HWND shutdownHwnd = HWNDFROMMP(mp1);
861 if (WinIsWindow(0, shutdownHwnd)) {
862 WinPostMsg(shutdownHwnd, WM_COMMAND, mp2, 0);
863 // Ensure we will get WM_QUIT anyway, even if XWP was
864 // not that fast to post it yet (we need it to correctly
865 // finish the graceful shutdown procedure)
866 sm_quitSkipped = true;
867 }
868#endif
869 }
870 // repost WM_QUIT to ourselves because we might have ignored
871 // it in qt_app_canQuit(), so will not get one anymore
872 if (sm_quitSkipped)
873 WinPostMsg(hwnd, WM_QUIT, 0, 0);
874 }
875 // PMREF recommends to pass it to WinDefWindowProc()
876 return WinDefWindowProc(hwnd, msg, mp1, mp2);
877 }
878#endif
879
880 case WM_SYSVALUECHANGED: {
881 // This message is sent to all top-level widgets, handle only once
882 QWidgetList list = QApplication::topLevelWidgets();
883 bool firstWidget = list.first()->winId() == hwnd;
884 if (!firstWidget)
885 break;
886 LONG from = (LONG) mp1;
887 LONG to = (LONG) mp2;
888 #define MY_IS_SV(sv) (from >= (sv) && to <= (sv))
889 if (MY_IS_SV(SV_WORKAREA_XLEFT) || MY_IS_SV(SV_WORKAREA_XRIGHT) ||
890 MY_IS_SV(SV_WORKAREA_YBOTTOM) || MY_IS_SV(SV_WORKAREA_YTOP)) {
891 // send a special invalid resize event to QDesktopWidget
892 QApplication::sendEvent(qt_desktopWidget, 0);
893 // @todo enumerate all top-level widgets and
894 // remaximize those that are maximized
895 } else {
896 /// @todo call qt_set_pm_resources() in the way it is
897 // done in WM_SYSCOLORCHANGE for relevant SV_ values.
898 }
899 #undef MY_IS_SV
900 break;
901 }
902
903 case WM_SYSCOLORCHANGE: {
904 // This message is sent to all top-level widgets, handle only once
905 QWidgetList list = QApplication::topLevelWidgets();
906 bool firstWidget = list.first()->winId() == hwnd;
907 if (!firstWidget)
908 break;
909 if (qApp->type() == QApplication::Tty)
910 break;
911 if (QApplication::desktopSettingsAware())
912 qt_set_pm_resources();
913 break;
914 }
915
916 case WM_BUTTON1DOWN:
917 case WM_BUTTON2DOWN:
918 case WM_BUTTON3DOWN:
919 if (ignoreNextMouseReleaseEvent)
920 ignoreNextMouseReleaseEvent = false;
921 break;
922 case WM_BUTTON1UP:
923 case WM_BUTTON2UP:
924 case WM_BUTTON3UP:
925 if (ignoreNextMouseReleaseEvent) {
926 ignoreNextMouseReleaseEvent = false;
927 if (qt_button_down && qt_button_down->internalWinId() == autoCaptureWnd) {
928 releaseAutoCapture();
929 qt_button_down = 0;
930 }
931 return (MRESULT)TRUE;
932 }
933 break;
934
935 default:
936 break;
937 }
938
939 if (!widget)
940 widget = (QETWidget*)QWidget::find(hwnd);
941 if (!widget) // don't know this widget
942 break;
943
944 if (app_do_modal) { // modal event handling
945 if (!qt_try_modal(widget, &qmsg, rc))
946 return rc;
947 }
948
949 if (widget->xtra()) { // send through widget filter list
950 foreach(QWidget::PmEventFilter *filter, widget->xtra()->pmEventFilters) {
951 if (filter->pmEventFilter(&qmsg, &rc))
952 return rc;
953 }
954 }
955
956 if (widget->pmEvent(&qmsg, &rc)) // send through widget filter
957 return rc;
958
959 if (qmsg.isTranslatableMouseEvent) {
960 if (qApp->activePopupWidget() != 0) { // in popup mode
961 QWidget *w = QApplication::widgetAt(qmsg.ptl.x, qmsg.ptl.y);
962 if (w)
963 widget = (QETWidget*)w;
964 }
965 if (widget->translateMouseEvent(qmsg)) // mouse event
966 return (MRESULT)TRUE;
967#ifndef QT_NO_WHEELEVENT
968 } else if (msg == WM_VSCROLL || msg == WM_HSCROLL) {
969 if (widget->translateWheelEvent(qmsg))
970 return (MRESULT)TRUE;
971#endif
972#ifndef QT_NO_DRAGANDDROP
973 } else if (msg >= WM_DRAGFIRST && msg <= WM_DRAGLAST) {
974 return QDragManager::self()->dispatchDragAndDrop(widget, qmsg);
975#endif
976 } else {
977 switch(msg) {
978
979 case WM_TRANSLATEACCEL: {
980 if (widget->isWindow()) {
981 rc = WinDefWindowProc(hwnd, msg, mp1, mp2);
982 if (rc) {
983 QMSG &qmsg = *(QMSG*)mp1;
984 if (qmsg.msg == WM_SYSCOMMAND &&
985 WinWindowFromID(widget->internalFrameWinId(),
986 FID_SYSMENU)) {
987 switch (SHORT1FROMMP(qmsg.mp1)) {
988 case SC_CLOSE:
989 case SC_TASKMANAGER:
990 return (MRESULT)TRUE;
991 default:
992 break;
993 }
994 }
995 }
996 }
997 // return FALSE in all other cases to let Qt process keystrokes
998 // that are in the system-wide frame accelerator table.
999 return FALSE;
1000 }
1001
1002 case WM_CHAR: { // keyboard event
1003 if (!(CHARMSG(&qmsg.msg)->fs & KC_KEYUP))
1004 qt_keymapper_private()->updateKeyMap(qmsg);
1005
1006 QWidget *g = QWidget::keyboardGrabber();
1007 if (g)
1008 widget = (QETWidget*)g;
1009 else if (QApplication::activePopupWidget())
1010 widget = (QETWidget*)QApplication::activePopupWidget()->focusWidget()
1011 ? (QETWidget*)QApplication::activePopupWidget()->focusWidget()
1012 : (QETWidget*)QApplication::activePopupWidget();
1013 else if (qApp->focusWidget())
1014 widget = (QETWidget*)QApplication::focusWidget();
1015 else if (widget->internalWinId() == WinQueryFocus(HWND_DESKTOP)) {
1016 // We faked the message to go to exactly that widget.
1017 widget = (QETWidget*)widget->window();
1018 }
1019 if (widget->isEnabled()) {
1020 bool result =
1021#if !defined (QT_NO_SESSIONMANAGER)
1022 sm_blockUserInput ? true :
1023#endif
1024 qt_keymapper_private()->translateKeyEvent(widget, qmsg, g != 0);
1025 if (result)
1026 return (MRESULT)TRUE;
1027 }
1028 break;
1029 }
1030
1031 case WM_KBDLAYERCHANGED: { // Keyboard layout change
1032 QKeyMapper::changeKeyboard();
1033 break;
1034 }
1035
1036 case WM_QUERYCONVERTPOS: { // IME input box position request
1037 // @todo the proper detection of the caret position in the
1038 // current widget requires implementing QInputContext. For now,
1039 // just send the IME box to the lower left corner of the
1040 // top-level window
1041 PRECTL pcp = (PRECTL)mp1;
1042 memset(pcp, 0xFF, sizeof(RECTL));
1043 pcp->xLeft = 0;
1044 pcp->yBottom = 0;
1045 return (MRESULT)QCP_CONVERT;
1046 }
1047
1048 case WM_PAINT: { // paint event
1049 if (widget->translatePaintEvent(qmsg))
1050 return (MRESULT)TRUE;
1051 break;
1052 }
1053
1054 case WM_ERASEBACKGROUND: { // erase window background
1055 // flush WM_PAINT messages here to update window contents
1056 // instantly while tracking the resize frame (normally these
1057 // messages are delivered after the user has stopped resizing
1058 // for some time). this slows down resizing slightly but gives a
1059 // better look (no invalid window contents can be seen during
1060 // resize). the alternative could be to erase the background only,
1061 // but we need to do it for every non-toplevel window, which can
1062 // also be time-consuming (WM_ERASEBACKGROUND is sent to WC_FRAME
1063 // clients only, so we would have to do all calculations ourselves).
1064 WinUpdateWindow(widget->effectiveWinId());
1065 return FALSE;
1066 }
1067
1068 case WM_CALCVALIDRECTS: {
1069 // we must always return this value here to cause PM to reposition
1070 // our children accordingly (othwerwise we would have to do it
1071 // ourselves to keep them top-left aligned).
1072 return (MRESULT)(CVR_ALIGNLEFT | CVR_ALIGNTOP);
1073 }
1074
1075 case WM_SIZE: { // resize window
1076 if (widget->translateConfigEvent(qmsg))
1077 return (MRESULT)TRUE;
1078 break;
1079 }
1080
1081 case WM_ACTIVATE: {
1082 qApp->pmFocus(widget, SHORT1FROMMP(mp1));
1083 break;
1084 }
1085
1086 case WM_FOCUSCHANGE: {
1087 HWND hwnd = (HWND)mp1;
1088 bool focus = SHORT1FROMMP(mp2);
1089 if (!focus) {
1090 if (!QWidget::find(hwnd) && !QDragManager::self()->isInOwnDrag()) {
1091 // we gave up focus to another application, unset Qt
1092 // focus (exclude the situation when we've started the
1093 // drag in which case the PM focus goes to the drag
1094 // bitmap but the Qt focus should stay with us)
1095 if (QApplication::activePopupWidget()) {
1096 foreignFocusWnd = hwnd;
1097 // Another application was activated while our popups are open,
1098 // then close all popups. In case some popup refuses to close,
1099 // we give up after 1024 attempts (to avoid an infinite loop).
1100 int maxiter = 1024;
1101 QWidget *popup;
1102 while ((popup=QApplication::activePopupWidget()) && maxiter--)
1103 popup->close();
1104 }
1105 // non-Qt ownees of our WC_FRAME window (such as
1106 // FID_SYSMENU) should not cause the focus to be lost.
1107 if (WinQueryWindow(hwnd, QW_OWNER) ==
1108 ((QETWidget*)widget->window())->frameWinId())
1109 break;
1110 if (!widget->isWindow())
1111 qApp->pmFocus(widget, focus);
1112 }
1113 }
1114 break;
1115 }
1116
1117 case WM_SHOW: {
1118 // @todo there is some more processing in Qt4, see
1119 // WM_SHOWWINDOW in qapplication_win.cpp
1120 if (!SHORT1FROMMP(mp1) && autoCaptureWnd == widget->internalWinId())
1121 releaseAutoCapture();
1122 break;
1123 }
1124
1125 case WM_CLOSE: { // close window
1126 widget->translateCloseEvent(qmsg);
1127 return (MRESULT)TRUE;
1128 }
1129
1130 case WM_DESTROY: { // destroy window
1131 if (hwnd == curWin) {
1132 QWidget *enter = QWidget::mouseGrabber();
1133 if (enter == widget)
1134 enter = 0;
1135 QApplicationPrivate::dispatchEnterLeave(enter, widget);
1136 curWin = enter ? enter->effectiveWinId() : 0;
1137 qt_last_mouse_receiver = enter;
1138 }
1139 if (widget == popupButtonFocus)
1140 popupButtonFocus = 0;
1141 break;
1142 }
1143
1144#ifndef QT_NO_CONTEXTMENU
1145 case WM_CONTEXTMENU: {
1146 if (SHORT2FROMMP(mp2)) {
1147 // keyboard event
1148 QWidget *fw = qApp->focusWidget();
1149 if (fw && fw->isEnabled()) {
1150 QContextMenuEvent e(QContextMenuEvent::Keyboard,
1151 QPoint(5, 5),
1152 fw->mapToGlobal(QPoint(5, 5)), 0);
1153 if (qt_sendSpontaneousEvent(fw, &e))
1154 return (MRESULT)TRUE;
1155 }
1156 } else {
1157 // mouse event
1158 if (widget->translateMouseEvent(qmsg))
1159 return (MRESULT)TRUE;
1160 }
1161 break;
1162 }
1163#endif
1164
1165 case WM_U_MOUSELEAVE: {
1166 // mp1 = hwndFrom, mp2 = hwndTo
1167 if (hwnd != (HWND)mp1) {
1168 // this must be a LEAVE message from one of the frame
1169 // controls forwarded by WC_FRAME to FID_CLIENT; ignore it
1170 // as it's doesn't actually belong to the given hwnd
1171 break;
1172 }
1173 // We receive a mouse leave for curWin, meaning the mouse was
1174 // moved outside our widgets (in any other case curWin will be
1175 // already set to a different value in response to WM_MOUSEMOVE
1176 // in translateMouseEvent())
1177 if (widget->internalWinId() == curWin) {
1178 bool dispatch = !widget->underMouse();
1179 // hasMouse is updated when dispatching enter/leave,
1180 // so test if it is actually up-to-date
1181 if (!dispatch) {
1182 QRect geom = widget->geometry();
1183 if (widget->parentWidget() && !widget->isWindow()) {
1184 QPoint gp = widget->parentWidget()->mapToGlobal(widget->pos());
1185 geom.setX(gp.x());
1186 geom.setY(gp.y());
1187 }
1188 QPoint cpos = QCursor::pos();
1189 dispatch = !geom.contains(cpos);
1190 if ( !dispatch && !QWidget::mouseGrabber()) {
1191 QWidget *hittest = QApplication::widgetAt(cpos);
1192 dispatch = !hittest || hittest->internalWinId() != curWin;
1193 }
1194 if (!dispatch) {
1195#ifdef QT_PM_NATIVEWIDGETMASK
1196 HPS hps = qt_display_ps();
1197 HRGN hrgn = GpiCreateRegion(hps, 0, NULL);
1198 qt_WinQueryClipRegionOrRect(hwnd, hrgn);
1199 QPoint lcpos = widget->mapFromGlobal(cpos);
1200 // flip y coordinate
1201 POINTL pt = { lcpos.x(), widget->height() - (lcpos.y() + 1) };
1202 dispatch = !GpiPtInRegion(hps, hrgn, &pt);
1203 GpiDestroyRegion(hps, hrgn);
1204#else
1205 QPoint lcpos = widget->mapFromGlobal(cpos);
1206 QRect rect(0, 0, widget->width(), widget->height());
1207 dispatch = !rect.contains(lcpos);
1208#endif
1209 }
1210 }
1211 if (dispatch) {
1212 if (qt_last_mouse_receiver && !qt_last_mouse_receiver->internalWinId())
1213 QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
1214 else
1215 QApplicationPrivate::dispatchEnterLeave(0, QWidget::find((WId)curWin));
1216 curWin = 0;
1217 qt_last_mouse_receiver = 0;
1218 }
1219 }
1220 break;
1221 }
1222
1223 case WM_MINMAXFRAME: {
1224 PSWP pswp = (PSWP)mp1;
1225
1226 bool window_state_change = false;
1227 Qt::WindowStates oldstate = Qt::WindowStates(widget->dataPtr()->window_state);
1228
1229 if (pswp->fl & SWP_MINIMIZE) {
1230 window_state_change = true;
1231 widget->dataPtr()->window_state |= Qt::WindowMinimized;
1232 if (widget->isVisible()) {
1233 QHideEvent e;
1234 qt_sendSpontaneousEvent(widget, &e);
1235 widget->dptr()->hideChildren(true);
1236 const QString title = widget->windowIconText();
1237 if (!title.isEmpty())
1238 widget->dptr()->setWindowTitle_helper(title);
1239 }
1240 } else if (pswp->fl & (SWP_MAXIMIZE | SWP_RESTORE)) {
1241 window_state_change = true;
1242 if (pswp->fl & SWP_MAXIMIZE) {
1243 widget->topData()->normalGeometry = widget->geometry();
1244 widget->dataPtr()->window_state |= Qt::WindowMaximized;
1245 }
1246 else if (!widget->isMinimized()) {
1247 widget->dataPtr()->window_state &= ~Qt::WindowMaximized;
1248 }
1249
1250 if (widget->isMinimized()) {
1251 widget->dataPtr()->window_state &= ~Qt::WindowMinimized;
1252 widget->dptr()->showChildren(true);
1253 QShowEvent e;
1254 qt_sendSpontaneousEvent(widget, &e);
1255 const QString title = widget->windowTitle();
1256 if (!title.isEmpty())
1257 widget->dptr()->setWindowTitle_helper(title);
1258 }
1259 }
1260
1261 if (window_state_change) {
1262 QWindowStateChangeEvent e(oldstate);
1263 qt_sendSpontaneousEvent(widget, &e);
1264 }
1265
1266 break;
1267 }
1268
1269 default:
1270 break;
1271 }
1272 }
1273
1274 } while(0);
1275
1276 return WinDefWindowProc(hwnd, msg, mp1, mp2);
1277}
1278
1279static void qt_pull_blocked_widgets(QETWidget *widget)
1280{
1281 QWidgetList list = QApplication::topLevelWidgets();
1282 foreach (QWidget *w, list) {
1283 QETWidget *ew = (QETWidget *)w;
1284 QETWidget *above = (QETWidget*)ew->modalBlocker();
1285 if (above == widget) {
1286 WinSetWindowPos(ew->frameWinId(), widget->frameWinId(),
1287 0, 0, 0, 0, SWP_ZORDER);
1288 qt_pull_blocked_widgets(ew);
1289 }
1290 }
1291}
1292
1293PFNWP QtOldFrameProc = 0;
1294
1295MRESULT EXPENTRY QtFrameProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1296{
1297 static bool pullingBlockedWigets = false;
1298
1299 do {
1300 if (!qApp) // unstable app state
1301 break;
1302#if 0
1303 // make sure we show widgets (e.g. scrollbars) when the user resizes
1304 if (qApp->loopLevel())
1305 qApp->sendPostedEvents(0, QEvent::ShowWindowRequest);
1306#endif
1307
1308 MRESULT rc = (MRESULT) FALSE;
1309
1310 HWND hwndC = WinWindowFromID(hwnd, FID_CLIENT);
1311 QETWidget *widget = (QETWidget*)QWidget::find(hwndC);
1312 if (!widget) // don't know this widget
1313 break;
1314
1315 Q_ASSERT(widget->isWindow());
1316
1317 QtQmsg qmsg(hwnd, msg, mp1, mp2);
1318
1319#if defined(QT_DEBUGMSGFLOW)
1320 if (qmsg.msg != WM_QUERYICON)
1321 qDebug() << "*** [F]" << qmsg;
1322#endif
1323
1324 if (qmsg.isTranslatableMouseEvent)
1325 widget->translateNonClientMouseEvent(qmsg);
1326
1327 switch(msg) {
1328
1329 case WM_MOVE: { // move window
1330 // note that we handle it nere instead of having CS_MOVENOTIFY
1331 // on the client and handling in QtWndProc because we don't want
1332 // client inside frame window move messages that would appear during
1333 // minimize/maximize otherwise
1334 if (widget->translateConfigEvent(qmsg))
1335 return (MRESULT)TRUE;
1336 break;
1337 }
1338
1339 case WM_ADJUSTWINDOWPOS: {
1340 // If PM tries to activate a modally blocked window, pass activation
1341 // over to the top modal window instead of letting it activate the
1342 // blocked one
1343 PSWP pswp =(PSWP)qmsg.mp1;
1344 if (app_do_modal &&
1345 ((pswp->fl & SWP_ACTIVATE) || (pswp->fl & SWP_ZORDER))) {
1346 QETWidget *above = (QETWidget *)widget->modalBlocker();
1347 if (above) {
1348 if (pswp->fl & SWP_ACTIVATE) {
1349 // find the blocker that isn't blocked itself and
1350 // delegate activation to it (WM_WINDOWPOSCHANGED will
1351 // care about the rest)
1352 while (above->modalBlocker())
1353 above = above->modalBlocker();
1354 WinSetWindowPos(above->frameWinId(), HWND_TOP, 0, 0, 0, 0,
1355 SWP_ACTIVATE | SWP_ZORDER);
1356 pswp->fl &= ~SWP_ACTIVATE;
1357 }
1358 if (pswp->fl & SWP_ZORDER) {
1359 // forbid changing the Z-order of the blocked widget
1360 // (except when it is moved right under its blocker)
1361 if (pswp->hwndInsertBehind != above->frameWinId())
1362 pswp->fl &= ~SWP_ZORDER;
1363 }
1364 }
1365 }
1366 break;
1367 }
1368
1369 case WM_WINDOWPOSCHANGED: {
1370 PSWP pswp =(PSWP)qmsg.mp1;
1371 // make sure blocked widgets stay behind the blocker on Z-order change
1372 if (app_do_modal && (pswp->fl & SWP_ZORDER) && !pullingBlockedWigets) {
1373 // protect against various kinds of recursion (e.g. when the
1374 // blocked widgets are PM owners of the blocker in which case PM
1375 // manages pulling on its own and will put us in a loop)
1376 pullingBlockedWigets = true;
1377 qt_pull_blocked_widgets(widget);
1378 pullingBlockedWigets = false;
1379 }
1380 break;
1381 }
1382
1383 case WM_QUERYTRACKINFO: {
1384 QWExtra *x = widget->xtra();
1385 if (x) {
1386 rc = QtOldFrameProc(hwnd, msg, mp1, mp2);
1387 PTRACKINFO pti = (PTRACKINFO) mp2;
1388 int minw = 0, minh = 0;
1389 int maxw = QWIDGETSIZE_MAX, maxh = QWIDGETSIZE_MAX;
1390 QRect fs = widget->frameStrut();
1391 if (x->minw > 0)
1392 minw = x->minw + fs.left() + fs.right();
1393 if (x->minh > 0)
1394 minh = x->minh + fs.top() + fs.bottom();
1395 if (x->maxw < QWIDGETSIZE_MAX)
1396 maxw = x->maxw > x->minw ? x->maxw + fs.left() + fs.right() : minw;
1397 if (x->maxh < QWIDGETSIZE_MAX)
1398 maxh = x->maxh > x->minh ? x->maxh + fs.top() + fs.bottom() : minh;
1399 // obey system recommended minimum size (to emulate Qt/Win32)
1400 pti->ptlMinTrackSize.x = qMax<LONG>(minw, pti->ptlMinTrackSize.x);
1401 pti->ptlMinTrackSize.y = qMax<LONG>(minh, pti->ptlMinTrackSize.y);
1402 // we assume that PM doesn't restrict the maximum size by default
1403 // and use it as an absolute maximum (values above it will cause
1404 // PM to disable window sizing and moving for some reason)
1405 pti->ptlMaxTrackSize.x = qMin<LONG>(maxw, pti->ptlMaxTrackSize.x);
1406 pti->ptlMaxTrackSize.y = qMin<LONG>(maxh, pti->ptlMaxTrackSize.y);
1407 return rc;
1408 }
1409 break;
1410 }
1411
1412 case WM_TRACKFRAME: {
1413 if (QApplication::activePopupWidget()) {
1414 // Another application was activated while our popups are open,
1415 // then close all popups. In case some popup refuses to close,
1416 // we give up after 1024 attempts (to avoid an infinite loop).
1417 int maxiter = 1024;
1418 QWidget *popup;
1419 while ((popup=QApplication::activePopupWidget()) && maxiter--)
1420 popup->close();
1421 }
1422 break;
1423 }
1424
1425 default:
1426 break;
1427 }
1428 } while(0);
1429
1430 return QtOldFrameProc(hwnd, msg, mp1, mp2);
1431}
1432
1433PFNWP QtOldFrameCtlProcs[FID_HORZSCROLL - FID_SYSMENU + 1] = { 0 };
1434
1435MRESULT EXPENTRY QtFrameCtlProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1436{
1437 // sanity: this procedure is only for standard frame controls
1438 ULONG id = (ULONG)WinQueryWindowUShort(hwnd, QWS_ID);
1439 Q_ASSERT(id >= FID_SYSMENU && id <= FID_HORZSCROLL);
1440 Q_ASSERT(QtOldFrameCtlProcs[id - FID_SYSMENU]);
1441 if (id < FID_SYSMENU || id > FID_HORZSCROLL ||
1442 !QtOldFrameCtlProcs[id - FID_SYSMENU])
1443 return FALSE;
1444
1445 do {
1446 if (!qApp) // unstable app state
1447 break;
1448
1449 HWND hwndF = WinQueryWindow(hwnd, QW_PARENT);
1450 HWND hwndC = WinWindowFromID(hwndF, FID_CLIENT);
1451 QETWidget *widget = (QETWidget*)QWidget::find(hwndC);
1452 if (!widget) // don't know this widget
1453 break;
1454
1455 Q_ASSERT(widget->isWindow());
1456
1457 QtQmsg qmsg(hwnd, msg, mp1, mp2);
1458
1459#if defined(QT_DEBUGMSGFLOW)
1460 if (qmsg.msg != WM_QUERYICON)
1461 qDebug() << "*** [FC]" << qmsg;
1462#endif
1463
1464 if (qmsg.isTranslatableMouseEvent)
1465 widget->translateNonClientMouseEvent(qmsg);
1466
1467 } while(0);
1468
1469 // call the original window procedure of this frame control
1470 return QtOldFrameCtlProcs[id - FID_SYSMENU](hwnd, msg, mp1, mp2);
1471}
1472
1473/*****************************************************************************
1474 Modal widgets; We have implemented our own modal widget mechanism
1475 to get total control.
1476 A modal widget without a parent becomes application-modal.
1477 A modal widget with a parent becomes modal to its parent and grandparents..
1478
1479 QApplicationPrivate::enterModal()
1480 Enters modal state
1481 Arguments:
1482 QWidget *widget A modal widget
1483
1484 QApplicationPrivate::leaveModal()
1485 Leaves modal state for a widget
1486 Arguments:
1487 QWidget *widget A modal widget
1488 *****************************************************************************/
1489
1490bool QApplicationPrivate::modalState()
1491{
1492 return app_do_modal;
1493}
1494
1495void QApplicationPrivate::enterModal_sys(QWidget *widget)
1496{
1497 if (!qt_modal_stack)
1498 qt_modal_stack = new QWidgetList;
1499
1500 releaseAutoCapture();
1501 QWidget *leave = qt_last_mouse_receiver;
1502 if (!leave)
1503 leave = QWidget::find(curWin);
1504 QApplicationPrivate::dispatchEnterLeave(0, leave);
1505 qt_modal_stack->insert(0, widget);
1506 app_do_modal = true;
1507 curWin = 0;
1508 qt_last_mouse_receiver = 0;
1509 ignoreNextMouseReleaseEvent = false;
1510
1511 // go through all top-level widgets and disable those that should be blocked
1512 // by the modality (this will effectively disable frame controls and make
1513 // it impossible to manipulate the window state, position and size, even
1514 // programmatically, e.g. from the Window List)
1515 QWidgetList list = QApplication::topLevelWidgets();
1516 foreach (QWidget *w, list) {
1517 if (w != widget && QApplicationPrivate::isBlockedByModal(w)) {
1518 if (!w->d_func()->modalBlocker()) {
1519 WinEnableWindow(w->d_func()->frameWinId(), FALSE);
1520 // also remember the blocker widget so that the blocked one can
1521 // pass activation attempts to it (note that the blocker is not
1522 // necessarily modal itself, it's just the window right above
1523 // the one being blocked, we will use this to restore z-order of
1524 // of blocked widgets in qt_pull_blocked_widgets())
1525 QWidget *widgetAbove = 0;
1526 HWND above = w->d_func()->frameWinId();
1527 while (!widgetAbove) {
1528 above = WinQueryWindow(above, QW_PREV);
1529 if (!above)
1530 break;
1531 widgetAbove = qt_widget_from_hwnd(above);
1532 }
1533 if (!widgetAbove)
1534 widgetAbove = widget;
1535 w->d_func()->setModalBlocker(widgetAbove);
1536 }
1537 }
1538 }
1539}
1540
1541void QApplicationPrivate::leaveModal_sys(QWidget *widget)
1542{
1543 if (qt_modal_stack) {
1544 if (qt_modal_stack->removeAll(widget)) {
1545 if (qt_modal_stack->isEmpty()) {
1546 delete qt_modal_stack;
1547 qt_modal_stack = 0;
1548 QPoint p(QCursor::pos());
1549 app_do_modal = false; // necessary, we may get recursively into qt_try_modal below
1550 QWidget* w = QApplication::widgetAt(p.x(), p.y());
1551 QWidget *leave = qt_last_mouse_receiver;
1552 if (!leave)
1553 leave = QWidget::find(curWin);
1554 if (QWidget *grabber = QWidget::mouseGrabber()) {
1555 w = grabber;
1556 if (leave == w)
1557 leave = 0;
1558 }
1559 QApplicationPrivate::dispatchEnterLeave(w, leave); // send synthetic enter event
1560 curWin = w ? w->effectiveWinId() : 0;
1561 qt_last_mouse_receiver = w;
1562 }
1563 }
1564 ignoreNextMouseReleaseEvent = true;
1565
1566 // go through all top-level widgets and re-enable those that are not
1567 // blocked any more
1568 QWidgetList list = QApplication::topLevelWidgets();
1569 foreach(QWidget *w, list) {
1570 if (w != widget && !QApplicationPrivate::isBlockedByModal(w)) {
1571 if (w->d_func()->modalBlocker()) {
1572 w->d_func()->setModalBlocker(0);
1573 WinEnableWindow(w->d_func()->frameWinId(), TRUE);
1574 }
1575 }
1576 }
1577 }
1578 app_do_modal = qt_modal_stack != 0;
1579}
1580
1581bool qt_try_modal(QWidget *widget, QMSG *qmsg, MRESULT &rc)
1582{
1583 QWidget *top = 0;
1584
1585 if (QApplicationPrivate::tryModalHelper(widget, &top))
1586 return true;
1587
1588 int type = qmsg->msg;
1589
1590 bool block_event = false;
1591 if ((type >= WM_MOUSEFIRST && type <= WM_MOUSELAST) ||
1592 (type >= WM_EXTMOUSEFIRST && type <= WM_EXTMOUSELAST) ||
1593 type == WM_VSCROLL || type == WM_HSCROLL ||
1594 type == WM_U_MOUSELEAVE ||
1595 type == WM_CHAR) {
1596 if (type == WM_MOUSEMOVE) {
1597#ifndef QT_NO_CURSOR
1598 QCursor *c = qt_grab_cursor();
1599 if (!c)
1600 c = QApplication::overrideCursor();
1601 if (c) // application cursor defined
1602 WinSetPointer(HWND_DESKTOP, c->handle());
1603 else
1604 WinSetPointer(HWND_DESKTOP, QCursor(Qt::ArrowCursor).handle());
1605#endif // QT_NO_CURSOR
1606 } else if (type == WM_BUTTON1DOWN || type == WM_BUTTON2DOWN ||
1607 type == WM_BUTTON3DOWN) {
1608 if (!top->isActiveWindow()) {
1609 top->activateWindow();
1610 } else {
1611 QApplication::beep();
1612 }
1613 }
1614 block_event = true;
1615 } else if (type == WM_CLOSE) {
1616 block_event = true;
1617 } else if (type == WM_SYSCOMMAND) {
1618 if (!(SHORT1FROMMP(qmsg->mp1) == SC_RESTORE && widget->isMinimized()))
1619 block_event = true;
1620 }
1621
1622 return !block_event;
1623}
1624
1625/*****************************************************************************
1626 Popup widget mechanism
1627
1628 openPopup()
1629 Adds a widget to the list of popup widgets
1630 Arguments:
1631 QWidget *widget The popup widget to be added
1632
1633 closePopup()
1634 Removes a widget from the list of popup widgets
1635 Arguments:
1636 QWidget *widget The popup widget to be removed
1637 *****************************************************************************/
1638
1639void QApplicationPrivate::openPopup(QWidget *popup)
1640{
1641 if (!QApplicationPrivate::popupWidgets)
1642 QApplicationPrivate::popupWidgets = new QWidgetList;
1643 QApplicationPrivate::popupWidgets->append(popup);
1644 if (!popup->isEnabled())
1645 return;
1646
1647 if (QApplicationPrivate::popupWidgets->count() == 1) {
1648 if (!qt_nograb()) {
1649 Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
1650 setAutoCapture(popup->d_func()->frameWinId()); // grab mouse/keyboard
1651 }
1652 if (!qt_widget_from_hwnd(WinQueryActiveWindow(HWND_DESKTOP))) {
1653 // the popup is opened while another application is active. Steal
1654 // the focus (to receive keyboard input and to make sure we get
1655 // WM_FOCUSCHANGE when clicked outside) but not the active state.
1656 ULONG flags = FC_NOSETACTIVE | FC_NOLOSEACTIVE;
1657 WinFocusChange(HWND_DESKTOP, popup->d_func()->frameWinId(), flags);
1658 foreignActiveWnd = WinQueryActiveWindow(HWND_DESKTOP);
1659 }
1660 }
1661
1662 // Popups are not focus-handled by the window system (the first
1663 // popup grabbed the keyboard), so we have to do that manually: A
1664 // new popup gets the focus
1665 if (popup->focusWidget()) {
1666 popup->focusWidget()->setFocus(Qt::PopupFocusReason);
1667 } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
1668 if (QWidget *fw = q_func()->focusWidget()) {
1669 QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
1670 q_func()->sendEvent(fw, &e);
1671 }
1672 }
1673}
1674
1675void QApplicationPrivate::closePopup(QWidget *popup)
1676{
1677 if (!QApplicationPrivate::popupWidgets)
1678 return;
1679 QApplicationPrivate::popupWidgets->removeAll(popup);
1680 POINTL curPos;
1681 WinQueryPointerPos(HWND_DESKTOP, &curPos);
1682 // flip y coordinate
1683 curPos.y = qt_display_height() - (curPos.y + 1);
1684
1685 if (QApplicationPrivate::popupWidgets->isEmpty()) {
1686 // this was the last popup
1687 if (foreignActiveWnd != NULLHANDLE && foreignFocusWnd != NULLHANDLE) {
1688 // we stole focus from another application so PM won't send it
1689 // WM_ACTIVATE(FALSE). Our duty is to do it for PM.
1690 HWND parent, desktop = WinQueryDesktopWindow(0, NULLHANDLE);
1691 // find the top-level window of the window actually getting focus
1692 while ((parent = WinQueryWindow(foreignFocusWnd, QW_PARENT)) != desktop)
1693 foreignFocusWnd = parent;
1694 // send deactivation to the old active window if it differs
1695 if (foreignFocusWnd != foreignActiveWnd)
1696 WinSendMsg(foreignActiveWnd, WM_ACTIVATE, (MPARAM)FALSE, (MPARAM)foreignActiveWnd);
1697 }
1698 foreignActiveWnd = NULLHANDLE;
1699 foreignFocusWnd = NULLHANDLE;
1700
1701 delete QApplicationPrivate::popupWidgets;
1702 QApplicationPrivate::popupWidgets = 0;
1703 replayPopupMouseEvent = (!popup->geometry().contains(QPoint(curPos.x, curPos.y))
1704 && !popup->testAttribute(Qt::WA_NoMouseReplay));
1705 if (!popup->isEnabled())
1706 return;
1707 if (!qt_nograb()) // grabbing not disabled
1708 releaseAutoCapture();
1709 QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
1710 : q_func()->focusWidget();
1711 if (fw) {
1712 if (fw != q_func()->focusWidget()) {
1713 fw->setFocus(Qt::PopupFocusReason);
1714 } else {
1715 QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
1716 q_func()->sendEvent(fw, &e);
1717 }
1718 }
1719 } else {
1720 // Popups are not focus-handled by the window system (the
1721 // first popup grabbed the keyboard), so we have to do that
1722 // manually: A popup was closed, so the previous popup gets
1723 // the focus.
1724 QWidget* aw = QApplicationPrivate::popupWidgets->last();
1725 if (QApplicationPrivate::popupWidgets->count() == 1) {
1726 Q_ASSERT(aw->testAttribute(Qt::WA_WState_Created));
1727 setAutoCapture(aw->internalWinId());
1728 }
1729 if (QWidget *fw = aw->focusWidget())
1730 fw->setFocus(Qt::PopupFocusReason);
1731 }
1732}
1733
1734/*****************************************************************************
1735 Event translation; translates PM events to Qt events
1736 *****************************************************************************/
1737
1738static int mouseButtonState()
1739{
1740 int state = 0;
1741
1742 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)
1743 state |= Qt::LeftButton;
1744 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000)
1745 state |= Qt::RightButton;
1746 if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000)
1747 state |= Qt::MidButton;
1748
1749 return state;
1750}
1751
1752//
1753// Auto-capturing for mouse press and mouse release
1754//
1755
1756static void setAutoCapture(HWND h)
1757{
1758 if (autoCaptureWnd)
1759 releaseAutoCapture();
1760 autoCaptureWnd = h;
1761
1762 if (!mouseButtonState()) {
1763 // all buttons released, we don't actually capture the mouse
1764 // (see QWidget::translateMouseEvent())
1765 autoCaptureReleased = true;
1766 } else {
1767 autoCaptureReleased = false;
1768 WinSetCapture(HWND_DESKTOP, h);
1769 }
1770}
1771
1772static void releaseAutoCapture()
1773{
1774 if (autoCaptureWnd) {
1775 if (!autoCaptureReleased) {
1776 WinSetCapture(HWND_DESKTOP, NULLHANDLE);
1777 autoCaptureReleased = true;
1778 }
1779 autoCaptureWnd = NULLHANDLE;
1780 }
1781}
1782
1783//
1784// Mouse event translation
1785//
1786
1787static const ushort mouseTbl[] = {
1788 WM_MOUSEMOVE, QEvent::MouseMove, 0,
1789 WM_BUTTON1DOWN, QEvent::MouseButtonPress, Qt::LeftButton,
1790 WM_BUTTON1UP, QEvent::MouseButtonRelease, Qt::LeftButton,
1791 WM_BUTTON1DBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
1792 WM_BUTTON2DOWN, QEvent::MouseButtonPress, Qt::RightButton,
1793 WM_BUTTON2UP, QEvent::MouseButtonRelease, Qt::RightButton,
1794 WM_BUTTON2DBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
1795 WM_BUTTON3DOWN, QEvent::MouseButtonPress, Qt::MidButton,
1796 WM_BUTTON3UP, QEvent::MouseButtonRelease, Qt::MidButton,
1797 WM_BUTTON3DBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
1798 WM_CONTEXTMENU, QEvent::ContextMenu, 0,
1799 0, 0, 0
1800};
1801
1802static const ushort mouseTblNC[] = {
1803 WM_MOUSEMOVE, QEvent::NonClientAreaMouseMove, 0,
1804 WM_BUTTON1DOWN, QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton,
1805 WM_BUTTON1UP, QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton,
1806 WM_BUTTON1DBLCLK, QEvent::NonClientAreaMouseButtonDblClick, Qt::LeftButton,
1807 WM_BUTTON2DOWN, QEvent::NonClientAreaMouseButtonPress, Qt::RightButton,
1808 WM_BUTTON2UP, QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton,
1809 WM_BUTTON2DBLCLK, QEvent::NonClientAreaMouseButtonDblClick, Qt::RightButton,
1810 WM_BUTTON3DOWN, QEvent::NonClientAreaMouseButtonPress, Qt::MidButton,
1811 WM_BUTTON3UP, QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton,
1812 WM_BUTTON3DBLCLK, QEvent::NonClientAreaMouseButtonDblClick, Qt::MidButton,
1813 0, 0, 0
1814};
1815
1816static int translateButtonState(USHORT s, int type, int button)
1817{
1818 Q_UNUSED(button);
1819
1820 int bst = mouseButtonState();
1821
1822 if (type == QEvent::ContextMenu) {
1823 if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000)
1824 bst |= Qt::ShiftModifier;
1825 if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000)
1826 bst |= Qt::AltModifier;
1827 if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
1828 bst |= Qt::ControlModifier;
1829 } else {
1830 if (s & KC_SHIFT)
1831 bst |= Qt::ShiftModifier;
1832 if ((s & KC_ALT))
1833 bst |= Qt::AltModifier;
1834 if (s & KC_CTRL)
1835 bst |= Qt::ControlModifier;
1836 }
1837 if (qt_keymapper_private()->extraKeyState & Qt::AltModifier)
1838 bst |= Qt::AltModifier;
1839 if (qt_keymapper_private()->extraKeyState & Qt::MetaModifier)
1840 bst |= Qt::MetaModifier;
1841
1842 return bst;
1843}
1844
1845bool QETWidget::translateMouseEvent(const QMSG &qmsg)
1846{
1847 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
1848 Q_ASSERT(internalWinId() != NULLHANDLE);
1849
1850 static QPoint pos; // window pos (y flipped)
1851 static POINTL gpos = { -1, -1 }; // global pos (y flipped)
1852 QEvent::Type type; // event parameters
1853 int button;
1854 int state;
1855 int i;
1856
1857 // candidate for the double click event
1858 static HWND dblClickCandidateWin = 0;
1859
1860#if !defined (QT_NO_SESSIONMANAGER)
1861 if (sm_blockUserInput) //block user interaction during session management
1862 return true;
1863#endif
1864
1865 for (i = 0; mouseTbl[i] && (ULONG)mouseTbl[i] != qmsg.msg; i += 3)
1866 ;
1867 if (!mouseTbl[i])
1868 return true;
1869
1870 type = (QEvent::Type)mouseTbl[++i]; // event type
1871 button = mouseTbl[++i]; // which button
1872 state = translateButtonState(SHORT2FROMMP(qmsg.mp2), type, button); // button state
1873
1874 // It seems, that PM remembers only the WM_BUTTONxDOWN message (instead of
1875 // the WM_BUTTONxDOWN + WM_BUTTONxUP pair) to detect whether the next button
1876 // press should be converted to WM_BUTTONxDBLCLK or not. As a result, the
1877 // window gets WM_BUTTONxDBLCLK even if it didn't receive the preceeding
1878 // WM_BUTTONxUP (this happens if we issue WinSetCapture() on the first
1879 // WM_BUTTONxDOWN), which is obviously wrong and makes problems for QWorkspace
1880 // and QTitleBar system menu handlers that don't expect a double click after
1881 // they opened a popup menu. dblClickCandidateWin is reset to 0 (see a ***
1882 // remmark below) when WinSetCapture is issued that directs messages
1883 // to a window other than one received the first WM_BUTTONxDOWN,
1884 // so we can fix it here. Note that if there is more than one popup window,
1885 // WinSetCapture is issued only for the first of them, so this code doesn't
1886 // prevent MouseButtonDblClick from being delivered to a popup when another
1887 // popup gets closed on the first WM_BUTTONxDOWN (Qt/Win32 behaves in the
1888 // same way, so it's left for compatibility).
1889 if (type == QEvent::MouseButtonPress) {
1890 dblClickCandidateWin = qmsg.hwnd;
1891 } else if (type == QEvent::MouseButtonDblClick) {
1892 if (dblClickCandidateWin != qmsg.hwnd)
1893 type = QEvent::MouseButtonPress;
1894 dblClickCandidateWin = 0;
1895 }
1896
1897 const QPoint widgetPos = mapFromGlobal(QPoint(qmsg.ptl.x, qmsg.ptl.y));
1898
1899 QWidget *alienWidget = !internalWinId() ? this : QApplication::widgetAt(qmsg.ptl.x, qmsg.ptl.y);
1900 if (alienWidget && alienWidget->internalWinId())
1901 alienWidget = 0;
1902
1903 if (type == QEvent::MouseMove) {
1904 if (!(state & Qt::MouseButtonMask))
1905 qt_button_down = 0;
1906#ifndef QT_NO_CURSOR
1907 QCursor *c = qt_grab_cursor();
1908 if (!c)
1909 c = QApplication::overrideCursor();
1910 if (c) // application cursor defined
1911 WinSetPointer(HWND_DESKTOP, c->handle());
1912 else if (!qt_button_down) {
1913 QWidget *w = alienWidget ? alienWidget : this;
1914 while (!w->isWindow() && !w->isEnabled())
1915 w = w->parentWidget();
1916 WinSetPointer(HWND_DESKTOP, w->cursor().handle());
1917 }
1918#else
1919 // pass the msg to the default proc to let it change the pointer shape
1920 WinDefWindowProc(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
1921#endif
1922
1923 HWND id = effectiveWinId();
1924 QWidget *mouseGrabber = QWidget::mouseGrabber();
1925 QWidget *activePopupWidget = qApp->activePopupWidget();
1926 if (mouseGrabber) {
1927 if (!activePopupWidget || (activePopupWidget == this && !rect().contains(widgetPos)))
1928 id = mouseGrabber->effectiveWinId();
1929 } else if (type == QEvent::NonClientAreaMouseMove) {
1930 id = 0;
1931 }
1932
1933 if (curWin != id) { // new current window
1934 // @todo
1935 // add CS_HITTEST to our window classes and handle WM_HITTEST,
1936 // otherwise disabled windows will not get mouse events?
1937 if (id == 0) {
1938 QWidget *leave = qt_last_mouse_receiver;
1939 if (!leave)
1940 leave = QWidget::find(curWin);
1941 QApplicationPrivate::dispatchEnterLeave(0, leave);
1942 qt_last_mouse_receiver = 0;
1943 curWin = 0;
1944 } else {
1945 QWidget *leave = 0;
1946 if (curWin && qt_last_mouse_receiver)
1947 leave = qt_last_mouse_receiver;
1948 else
1949 leave = QWidget::find(curWin);
1950 QWidget *enter = alienWidget ? alienWidget : this;
1951 if (mouseGrabber && activePopupWidget) {
1952 if (leave != mouseGrabber)
1953 enter = mouseGrabber;
1954 else
1955 enter = activePopupWidget == this ? this : mouseGrabber;
1956 }
1957 QApplicationPrivate::dispatchEnterLeave(enter, leave);
1958 qt_last_mouse_receiver = enter;
1959 curWin = id;
1960 }
1961 }
1962
1963 // *** PM posts a dummy WM_MOUSEMOVE message (with the same, uncahnged
1964 // pointer coordinates) after every WinSetCapture that actually changes
1965 // the capture target. I.e., if the argument of WinSetCapture is
1966 // NULLHANDLE, a window under the mouse pointer gets this message,
1967 // otherwise the specified window gets it unless it is already under the
1968 // pointer. We use this info to check whether the window can be a double
1969 // click candidate (see above).
1970 if (qmsg.ptl.x == gpos.x && qmsg.ptl.y == gpos.y) {
1971 if (dblClickCandidateWin != qmsg.hwnd)
1972 dblClickCandidateWin = 0;
1973 return true;
1974 }
1975
1976 gpos = qmsg.ptl;
1977 pos = widgetPos;
1978
1979 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1980 } else {
1981 if (type == QEvent::MouseButtonPress && !isActiveWindow())
1982 activateWindow();
1983
1984 gpos = qmsg.ptl;
1985 pos = widgetPos;
1986
1987 // mouse button pressed
1988 if (!qt_button_down && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick)) {
1989 QWidget *tlw = window();
1990 if (QWidget *child = tlw->childAt(mapTo(tlw, pos)))
1991 qt_button_down = child;
1992 else
1993 qt_button_down = this;
1994 }
1995 }
1996
1997 // detect special button states
1998 enum { Other, SinglePressed, AllReleased } btnState = Other;
1999 int bs = state & Qt::MouseButtonMask;
2000 if ((type == QEvent::MouseButtonPress ||
2001 type == QEvent::MouseButtonDblClick) && bs == button) {
2002 btnState = SinglePressed;
2003 } else if (type == QEvent::MouseButtonRelease && bs == 0) {
2004 btnState = AllReleased;
2005 }
2006
2007 bool res = false;
2008
2009 if (qApp->d_func()->inPopupMode()) { // in popup mode
2010 if (!autoCaptureReleased && btnState == AllReleased) {
2011 // in order to give non-Qt windows the opportunity to see mouse
2012 // messages while our popups are active we need to release the
2013 // mouse capture which is absolute in OS/2. We do it directly
2014 // (not through releaseAutoCapture()) in order to keep
2015 // autoCaptureWnd nonzero so that mouse move events (actually sent
2016 // to one of Qt widgets) are forwarded to the active popup.
2017 autoCaptureReleased = true;
2018 WinSetCapture(HWND_DESKTOP, 0);
2019 } else if (autoCaptureReleased && btnState == SinglePressed) {
2020 // set the mouse capture back if a button is pressed.
2021 if ( autoCaptureWnd ) {
2022 autoCaptureReleased = false;
2023 WinSetCapture(HWND_DESKTOP, autoCaptureWnd);
2024 }
2025 }
2026
2027 replayPopupMouseEvent = false;
2028 QWidget* activePopupWidget = qApp->activePopupWidget();
2029 QWidget *target = activePopupWidget;
2030 const QPoint globalPos(gpos.x, gpos.y);
2031
2032 if (target != this) {
2033 if ((windowType() == Qt::Popup) && rect().contains(pos) && 0)
2034 target = this;
2035 else // send to last popup
2036 pos = target->mapFromGlobal(globalPos);
2037 }
2038 QWidget *popupChild = target->childAt(pos);
2039 bool releaseAfter = false;
2040 switch (type) {
2041 case QEvent::MouseButtonPress:
2042 case QEvent::MouseButtonDblClick:
2043 popupButtonFocus = popupChild;
2044 break;
2045 case QEvent::MouseButtonRelease:
2046 releaseAfter = true;
2047 break;
2048 default:
2049 break; // nothing for mouse move
2050 }
2051
2052 if (target->isEnabled()) {
2053 if (popupButtonFocus) {
2054 target = popupButtonFocus;
2055 } else if (popupChild) {
2056 // forward mouse events to the popup child. mouse move events
2057 // are only forwarded to popup children that enable mouse tracking.
2058 if (type != QEvent::MouseMove || popupChild->hasMouseTracking())
2059 target = popupChild;
2060 }
2061
2062 pos = target->mapFromGlobal(globalPos);
2063#ifndef QT_NO_CONTEXTMENU
2064 if (type == QEvent::ContextMenu) {
2065 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos,
2066 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
2067 res = QApplication::sendSpontaneousEvent(target, &e);
2068 res = res && e.isAccepted();
2069 }
2070 else
2071#endif
2072 {
2073 QMouseEvent e(type, pos, globalPos,
2074 Qt::MouseButton(button),
2075 Qt::MouseButtons(state & Qt::MouseButtonMask),
2076 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
2077 res = QApplicationPrivate::sendMouseEvent(target, &e, alienWidget, this, &qt_button_down,
2078 qt_last_mouse_receiver);
2079 res = res && e.isAccepted();
2080 }
2081 } else {
2082 // close disabled popups when a mouse button is pressed or released
2083 switch (type) {
2084 case QEvent::MouseButtonPress:
2085 case QEvent::MouseButtonDblClick:
2086 case QEvent::MouseButtonRelease:
2087 target->close();
2088 break;
2089 default:
2090 break;
2091 }
2092 }
2093
2094 if (releaseAfter) {
2095 popupButtonFocus = 0;
2096 qt_button_down = 0;
2097 }
2098
2099 if (type == QEvent::MouseButtonPress
2100 && qApp->activePopupWidget() != activePopupWidget
2101 && replayPopupMouseEvent) {
2102 // the popup dissappeared. Replay the event
2103 QWidget* w = QApplication::widgetAt(gpos.x, gpos.y);
2104 if (w && !QApplicationPrivate::isBlockedByModal(w)) {
2105 Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
2106 HWND hwndTarget = w->effectiveWinId();
2107 if (QWidget::mouseGrabber() == 0)
2108 setAutoCapture(hwndTarget);
2109 if (!w->isActiveWindow())
2110 w->activateWindow();
2111 POINTL ptl = gpos;
2112 // flip y coordinate
2113 ptl.y = qt_display_height() - (ptl.y + 1);
2114 WinMapWindowPoints(HWND_DESKTOP, hwndTarget, &ptl, 1);
2115 WinPostMsg(hwndTarget, qmsg.msg,
2116 MPFROM2SHORT(ptl.x, ptl.y), qmsg.mp2);
2117 }
2118 }
2119 } else { // not popup mode
2120 if (btnState == SinglePressed && QWidget::mouseGrabber() == 0) {
2121 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
2122 setAutoCapture(internalWinId());
2123 } else if (btnState == AllReleased && QWidget::mouseGrabber() == 0) {
2124 releaseAutoCapture();
2125 }
2126
2127 const QPoint globalPos(gpos.x,gpos.y);
2128 QWidget *widget = QApplicationPrivate::pickMouseReceiver(this, globalPos, pos, type,
2129 Qt::MouseButtons(bs),
2130 qt_button_down, alienWidget);
2131 if (!widget)
2132 return false; // don't send event
2133
2134#ifndef QT_NO_CONTEXTMENU
2135 if (type == QEvent::ContextMenu) {
2136 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos,
2137 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
2138 res = QApplication::sendSpontaneousEvent(widget, &e);
2139 res = res && e.isAccepted();
2140 } else
2141#endif
2142 {
2143 QMouseEvent e(type, pos, globalPos, Qt::MouseButton(button),
2144 Qt::MouseButtons(state & Qt::MouseButtonMask),
2145 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
2146
2147 res = QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
2148 qt_last_mouse_receiver);
2149 res = res && e.isAccepted();
2150 }
2151 }
2152
2153 return res;
2154}
2155
2156void QETWidget::translateNonClientMouseEvent(const QMSG &qmsg)
2157{
2158 // this is a greatly simplified version of translateMouseEvent() that
2159 // only sends informational non-client area mouse messages to the top-level
2160 // widget
2161
2162 Q_ASSERT(isWindow());
2163 Q_ASSERT(internalWinId() != NULLHANDLE);
2164
2165#if !defined (QT_NO_SESSIONMANAGER)
2166 if (sm_blockUserInput) //block user interaction during session management
2167 return;
2168#endif
2169
2170 if (qApp->d_func()->inPopupMode()) {
2171 // don't report non-client area events in popup mode
2172 // (for compatibility with Windows)
2173 return;
2174 }
2175
2176 int i;
2177 for (i = 0; mouseTblNC[i] && (ULONG)mouseTblNC[i] != qmsg.msg; i += 3)
2178 ;
2179 if (!mouseTblNC[i])
2180 return;
2181
2182 QEvent::Type type = (QEvent::Type)mouseTblNC[++i]; // event type
2183 int button = mouseTblNC[++i]; // which button
2184 int state = translateButtonState(SHORT2FROMMP(qmsg.mp2), type, button); // button state
2185
2186 const QPoint globalPos(QPoint(qmsg.ptl.x, qmsg.ptl.y));
2187 const QPoint widgetPos = mapFromGlobal(globalPos);
2188
2189 QMouseEvent e(type, widgetPos, globalPos, Qt::MouseButton(button),
2190 Qt::MouseButtons(state & Qt::MouseButtonMask),
2191 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
2192
2193 QApplication::sendSpontaneousEvent(this, &e);
2194}
2195
2196#ifndef QT_NO_WHEELEVENT
2197bool QETWidget::translateWheelEvent(const QMSG &qmsg)
2198{
2199 enum { WHEEL_DELTA = 120 };
2200
2201#ifndef QT_NO_SESSIONMANAGER
2202 if (sm_blockUserInput) // block user interaction during session management
2203 return true;
2204#endif
2205
2206 // consume duplicate wheel events sent by the AMouse driver to emulate
2207 // multiline scrolls. we need this since currently Qt (QScrollBar, for
2208 // instance) maintains the number of lines to scroll per wheel rotation
2209 // (including the special handling of CTRL and SHIFT modifiers) on its own
2210 // and doesn't have a setting to tell it to be aware of system settings
2211 // for the mouse wheel. if we had processed events as they are, we would
2212 // get a confusing behavior (too many lines scrolled etc.).
2213 {
2214 int devh = qt_display_height();
2215 QMSG wheelMsg;
2216 while (WinPeekMsg(0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_NOREMOVE)) {
2217 // PM bug: ptl contains SHORT coordinates although fields are LONG
2218 wheelMsg.ptl.x = (short) wheelMsg.ptl.x;
2219 wheelMsg.ptl.y = (short) wheelMsg.ptl.y;
2220 // flip y coordinate
2221 wheelMsg.ptl.y = devh - (wheelMsg.ptl.y + 1);
2222 if (wheelMsg.mp1 != qmsg.mp1 ||
2223 wheelMsg.mp2 != qmsg.mp2 ||
2224 wheelMsg.ptl.x != qmsg.ptl.x ||
2225 wheelMsg.ptl.y != qmsg.ptl.y)
2226 break;
2227 WinPeekMsg(0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_REMOVE);
2228 }
2229 }
2230
2231 int delta;
2232 USHORT cmd = SHORT2FROMMP(qmsg.mp2);
2233 switch (cmd) {
2234 case SB_LINEUP:
2235 case SB_PAGEUP:
2236 delta = WHEEL_DELTA;
2237 break;
2238 case SB_LINEDOWN:
2239 case SB_PAGEDOWN:
2240 delta = -WHEEL_DELTA;
2241 break;
2242 default:
2243 return false;
2244 }
2245
2246 int state = 0;
2247 if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT ) & 0x8000)
2248 state |= Qt::ShiftModifier;
2249 if ((WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000) ||
2250 (qt_keymapper_private()->extraKeyState & Qt::AltModifier))
2251 state |= Qt::AltModifier;
2252 if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
2253 state |= Qt::ControlModifier;
2254 if (qt_keymapper_private()->extraKeyState & Qt::MetaModifier)
2255 state |= Qt::MetaModifier;
2256
2257 Qt::Orientation orient;
2258 // Alt inverts scroll orientation (Qt/Win32 behavior)
2259 if (state & Qt::AltModifier)
2260 orient = qmsg.msg == WM_VSCROLL ? Qt::Horizontal : Qt::Vertical;
2261 else
2262 orient = qmsg.msg == WM_VSCROLL ? Qt::Vertical : Qt::Horizontal;
2263
2264 QPoint globalPos(qmsg.ptl.x, qmsg.ptl.y);
2265
2266 // if there is a widget under the mouse and it is not shadowed
2267 // by modality, we send the event to it first
2268 MRESULT rc = FALSE;
2269 QWidget* w = QApplication::widgetAt(globalPos);
2270 if (!w || !qt_try_modal(w, (QMSG*)&qmsg, rc)) {
2271 //synaptics touchpad shows its own widget at this position
2272 //so widgetAt() will fail with that HWND, try child of this widget
2273 w = this->childAt(this->mapFromGlobal(globalPos));
2274 if (!w)
2275 w = this;
2276 }
2277
2278 // send the event to the widget or its ancestors
2279 {
2280 QWidget* popup = qApp->activePopupWidget();
2281 if (popup && w->window() != popup)
2282 popup->close();
2283#ifndef QT_NO_WHEELEVENT
2284 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
2285 Qt::MouseButtons(state & Qt::MouseButtonMask),
2286 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
2287
2288 if (QApplication::sendSpontaneousEvent(w, &e))
2289#else
2290 Q_UNUSED(orient);
2291#endif //QT_NO_WHEELEVENT
2292 return true;
2293 }
2294
2295 // send the event to the widget that has the focus or its ancestors, if different
2296 if (w != qApp->focusWidget() && (w = qApp->focusWidget())) {
2297 QWidget* popup = qApp->activePopupWidget();
2298 if (popup && w->window() != popup)
2299 popup->close();
2300#ifndef QT_NO_WHEELEVENT
2301 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
2302 Qt::MouseButtons(state & Qt::MouseButtonMask),
2303 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
2304 if (QApplication::sendSpontaneousEvent(w, &e))
2305#endif //QT_NO_WHEELEVENT
2306 return true;
2307 }
2308
2309 return false;
2310}
2311#endif
2312
2313/*!
2314 \internal
2315 In DnD, the mouse release event never appears, so the
2316 mouse button state machine must be manually reset.
2317*/
2318void qt_pmMouseButtonUp()
2319{
2320 // release any stored mouse capture
2321 qt_button_down = 0;
2322 autoCaptureReleased = true;
2323 releaseAutoCapture();
2324}
2325
2326//
2327// Paint event translation
2328//
2329bool QETWidget::translatePaintEvent(const QMSG &qmsg)
2330{
2331 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
2332 Q_ASSERT(internalWinId());
2333
2334 HPS displayPS = qt_display_ps();
2335
2336#ifdef QT_PM_NATIVEWIDGETMASK
2337 // Since we don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN bits (see
2338 // qwidget_pm.cpp), we have to validate areas that intersect with our
2339 // children and siblings, taking their clip regions into account.
2340 d_func()->validateObstacles();
2341#endif
2342
2343 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
2344
2345 HRGN hrgn = GpiCreateRegion(displayPS, 0, NULL);
2346 LONG rc = WinQueryUpdateRegion(internalWinId(), hrgn);
2347 if (rc == RGN_ERROR) { // The update bounding rect is invalid
2348 GpiDestroyRegion(displayPS, hrgn);
2349 setAttribute(Qt::WA_PendingUpdate, false);
2350 return false;
2351 }
2352
2353 setAttribute(Qt::WA_PendingUpdate, false);
2354
2355 const QRegion dirtyInBackingStore(qt_dirtyRegion(this));
2356 // Make sure the invalidated region contains the region we're about to repaint.
2357 // BeginPaint will set the clip to the invalidated region and it is impossible
2358 // to enlarge it afterwards (only shrink it).
2359 if (!dirtyInBackingStore.isEmpty())
2360 WinInvalidateRegion(internalWinId(), dirtyInBackingStore.handle(height()), FALSE);
2361
2362 RECTL rcl;
2363 d_func()->hd = WinBeginPaint(internalWinId(), 0, &rcl);
2364
2365#if defined(QT_DEBUGMSGFLOW)
2366 qDebug() << "PAINT BEGIN:" << rcl << "hps" << qDebugFmtHex(d_func()->hd);
2367#endif
2368
2369 // it's possible that the update rectangle is empty
2370 if (rcl.xRight <= rcl.xLeft || rcl.yTop <= rcl.yBottom) {
2371 WinEndPaint(d_func()->hd);
2372 d_func()->hd = NULLHANDLE;
2373 GpiDestroyRegion(displayPS, hrgn);
2374 setAttribute(Qt::WA_PendingUpdate, false);
2375 return true;
2376 }
2377
2378 // flip y coordinate
2379 // note: right top point is exlusive in rcl
2380 QRect updRect(QPoint(rcl.xLeft, height() - rcl.yTop),
2381 QPoint(rcl.xRight - 1, height() - (rcl.yBottom + 1)));
2382
2383 // Mapping region from system to qt (32 bit) coordinate system.
2384 updRect.translate(data->wrect.topLeft());
2385#if defined(QT_DEBUGMSGFLOW)
2386 qDebug() << "PAINT updRect:" << updRect;
2387#endif
2388
2389 // @todo use hrgn here converted to QRegion?
2390 d_func()->syncBackingStore(updRect);
2391
2392 WinEndPaint(d_func()->hd);
2393 d_func()->hd = NULLHANDLE;
2394
2395#if defined(QT_DEBUGMSGFLOW)
2396 qDebug() << "PAINT END";
2397#endif
2398
2399 return true;
2400}
2401
2402//
2403// Window move and resize (configure) events
2404//
2405
2406bool QETWidget::translateConfigEvent(const QMSG &qmsg)
2407{
2408 if (!testAttribute(Qt::WA_WState_Created)) // in QWidget::create()
2409 return true;
2410 if (testAttribute(Qt::WA_WState_ConfigPending))
2411 return true;
2412 if (testAttribute(Qt::WA_DontShowOnScreen))
2413 return true;
2414
2415 // @todo there are other isWindow() checks below (same in Windows code).
2416 // Either they or this return statement are leftovers. The assertion may
2417 // tell the truth.
2418 Q_ASSERT(isWindow());
2419 if (!isWindow())
2420 return true;
2421
2422 // When the window is minimized, PM moves it to -32000,-32000 and resizes
2423 // to 48x50. We don't want these useless actions to be seen by Qt.
2424 if (isMinimized())
2425 return true;
2426
2427 setAttribute(Qt::WA_WState_ConfigPending); // set config flag
2428
2429 HWND fId = NULLHANDLE;
2430 ULONG fStyle = 0;
2431 if (isWindow()) {
2432 fId = d_func()->frameWinId();
2433 fStyle = WinQueryWindowULong(fId, QWL_STYLE);
2434 }
2435
2436 // Note: due to the vertical coordinate space flip in PM, WM_SIZE events may
2437 // also mean moving the widget in Qt coordinates
2438
2439 if (qmsg.msg == WM_MOVE || qmsg.msg == WM_SIZE) { // move event
2440 QPoint oldPos = data->crect.topLeft();
2441 SWP swp;
2442 if (isWindow()) {
2443 WinQueryWindowPos(fId, &swp);
2444 // flip y coordinate
2445 swp.y = qt_display_height() - (swp.y + swp.cy);
2446 QTLWExtra *top = d_func()->topData();
2447 swp.x += top->frameStrut.left();
2448 swp.y += top->frameStrut.top();
2449 } else {
2450 WinQueryWindowPos(internalWinId(), &swp);
2451 // flip y coordinate
2452 swp.y = parentWidget()->height() - (swp.y + swp.cy);
2453 }
2454 QPoint newCPos(swp.x, swp.y);
2455 if (newCPos != oldPos) {
2456 data->crect.moveTopLeft(newCPos);
2457 if (isVisible()) {
2458 QMoveEvent e(newCPos, oldPos); // cpos (client position)
2459 QApplication::sendSpontaneousEvent(this, &e);
2460 } else {
2461 QMoveEvent *e = new QMoveEvent(newCPos, oldPos);
2462 QApplication::postEvent(this, e);
2463 }
2464 }
2465 }
2466 if (qmsg.msg == WM_SIZE) { // resize event
2467 QSize oldSize = data->crect.size();
2468 QSize newSize = QSize(SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2));
2469 data->crect.setSize(newSize);
2470 if (isWindow()) { // update title/icon text
2471 d_func()->createTLExtra();
2472 QString title;
2473 if ((fStyle & WS_MINIMIZED))
2474 title = windowIconText();
2475 if (title.isEmpty())
2476 title = windowTitle();
2477 if (!title.isEmpty())
2478 d_func()->setWindowTitle_helper(title);
2479 }
2480 if (oldSize != newSize) {
2481 // Spontaneous (external to Qt) WM_SIZE messages should occur only
2482 // on top-level widgets. If we get them for a non top-level widget,
2483 // the result will most likely be incorrect because widget masks will
2484 // not be properly processed (i.e. in the way it is done in
2485 // QWidget::setGeometry_sys() when the geometry is changed from
2486 // within Qt). So far, I see no need to support this (who will ever
2487 // need to move a non top-level window of a foreign process?).
2488 Q_ASSERT(isWindow());
2489 if (isVisible()) {
2490 QTLWExtra *tlwExtra = d_func()->maybeTopData();
2491 static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
2492 const bool hasStaticContents = tlwExtra && tlwExtra->backingStore
2493 && tlwExtra->backingStore->hasStaticContents();
2494 // If we have a backing store with static contents, we have to disable the top-level
2495 // resize optimization in order to get invalidated regions for resized widgets.
2496 // The optimization discards all invalidateBuffer() calls since we're going to
2497 // repaint everything anyways, but that's not the case with static contents.
2498 if (!slowResize && tlwExtra && !hasStaticContents)
2499 tlwExtra->inTopLevelResize = true;
2500 QResizeEvent e(newSize, oldSize);
2501 QApplication::sendSpontaneousEvent(this, &e);
2502 if (d_func()->paintOnScreen()) {
2503 QRegion updateRegion(rect());
2504 if (testAttribute(Qt::WA_StaticContents))
2505 updateRegion -= QRect(0, 0, oldSize.width(), oldSize.height());
2506 // syncBackingStore() should have already flushed the widget
2507 // contents to the screen, so no need to redraw the exposed
2508 // areas in WM_PAINT once more
2509 d_func()->syncBackingStore(updateRegion);
2510 WinValidateRegion(internalWinId(),
2511 updateRegion.handle(newSize.height()), FALSE);
2512 } else {
2513 d_func()->syncBackingStore();
2514 // see above
2515 RECTL rcl = { 0, 0, newSize.width(), newSize.height() };
2516 WinValidateRect(internalWinId(), &rcl, FALSE);
2517 }
2518 if (!slowResize && tlwExtra)
2519 tlwExtra->inTopLevelResize = false;
2520 } else {
2521 QResizeEvent *e = new QResizeEvent(newSize, oldSize);
2522 QApplication::postEvent(this, e);
2523 }
2524 }
2525 }
2526 setAttribute(Qt::WA_WState_ConfigPending, false); // clear config flag
2527 return true;
2528}
2529
2530//
2531// Close window event translation.
2532//
2533// This class is a friend of QApplication because it needs to emit the
2534// lastWindowClosed() signal when the last top level widget is closed.
2535//
2536
2537bool QETWidget::translateCloseEvent(const QMSG &)
2538{
2539 return d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
2540}
2541
2542void QApplicationPrivate::initializeMultitouch_sys()
2543{
2544}
2545
2546void QApplicationPrivate::cleanupMultitouch_sys()
2547{
2548}
2549
2550/*****************************************************************************
2551 PM session management
2552 *****************************************************************************/
2553
2554#if !defined(QT_NO_SESSIONMANAGER)
2555
2556bool QApplicationPrivate::canQuit()
2557{
2558#if defined (DEBUG_SESSIONMANAGER)
2559 qDebug("QApplicationPrivate::canQuit: sm_smActive %d,"
2560 "qt_about_to_destroy_wnd %d, sm_gracefulShutdown %d, sm_cancel %d",
2561 sm_smActive, qt_about_to_destroy_wnd,
2562 sm_gracefulShutdown, sm_cancel);
2563#endif
2564
2565 bool quit = false;
2566
2567 // We can get multiple WM_QUIT messages while the "session termination
2568 // procedure" (i.e. the QApplication::commitData() call) is still in
2569 // progress. Ignore them.
2570 if (!sm_smActive) {
2571 if (sm_gracefulShutdown) {
2572 // this is WM_QUIT after WM_SAVEAPPLICATION (either posted by the OS
2573 // or by ourselves), confirm the quit depending on what the user wants
2574 sm_quitSkipped = false;
2575 quit = !sm_cancel;
2576 if (sm_cancel) {
2577 // the shutdown has been canceled, reset the flag to let the
2578 // graceful shutdown happen again later
2579 sm_gracefulShutdown = false;
2580 }
2581 } else {
2582 // sm_gracefulShutdown is false, so allowsInteraction() and friends
2583 // will return FALSE during commitData() (assuming that WM_QUIT w/o
2584 // WM_SAVEAPPLICATION is an emergency termination)
2585 sm_smActive = true;
2586 sm_blockUserInput = true; // prevent user-interaction outside interaction windows
2587 sm_cancel = false;
2588 if (qt_session_manager_self)
2589 qApp->commitData(*qt_session_manager_self);
2590 sm_smActive = false;
2591 quit = true; // ignore sm_cancel
2592 }
2593 } else {
2594 // if this is a WM_QUIT received during WM_SAVEAPPLICATION handling,
2595 // remember we've skipped (refused) it
2596 if (sm_gracefulShutdown)
2597 sm_quitSkipped = true;
2598 }
2599
2600#if defined (DEBUG_SESSIONMANAGER)
2601 qDebug("QApplicationPrivate::canQuit: returns %d", quit);
2602#endif
2603
2604 return quit;
2605}
2606
2607bool QSessionManager::allowsInteraction()
2608{
2609 // Allow interation only when the system is being normally shutdown
2610 // and informs us using WM_SAVEAPPLICATION. When we receive WM_QUIT directly
2611 // (so sm_gracefulShutdown is false), interaction is disallowed.
2612 if (sm_smActive && sm_gracefulShutdown) {
2613 sm_blockUserInput = false;
2614 return true;
2615 }
2616
2617 return false;
2618}
2619
2620bool QSessionManager::allowsErrorInteraction()
2621{
2622 // Allow interation only when the system is being normally shutdown
2623 // and informs us using WM_SAVEAPPLICATION. When we receive WM_QUIT directly
2624 // (so sm_gracefulShutdown is false), interaction is disallowed.
2625 if (sm_smActive && sm_gracefulShutdown) {
2626 sm_blockUserInput = false;
2627 return true;
2628 }
2629
2630 return false;
2631}
2632
2633void QSessionManager::release()
2634{
2635 if (sm_smActive && sm_gracefulShutdown)
2636 sm_blockUserInput = true;
2637}
2638
2639void QSessionManager::cancel()
2640{
2641 if (sm_smActive && sm_gracefulShutdown)
2642 sm_cancel = true;
2643}
2644
2645#endif // QT_NO_SESSIONMANAGER
2646
2647/*****************************************************************************
2648 PM struct/message debug helpers
2649 *****************************************************************************/
2650
2651Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QDebugHWND &d)
2652{
2653 QETWidget *w = (QETWidget *)qt_widget_from_hwnd(d.hwnd);
2654 debug << qDebugFmtHex(d.hwnd) << w;
2655 if (w && w->internalWinId() != w->frameWinId()) {
2656 if (w->internalWinId() == d.hwnd) {
2657 debug.nospace() << "(frame " << qDebugFmtHex(w->frameWinId()) << ")";
2658 debug.space();
2659 } else if (w->frameWinId() == d.hwnd) {
2660 debug.nospace() << "(client " << qDebugFmtHex(w->internalWinId()) << ")";
2661 debug.space();
2662 }
2663 }
2664 return debug;
2665}
2666
2667Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QDebugHRGN &d)
2668{
2669 RGNRECT ctl;
2670 ctl.ircStart = 1;
2671 ctl.crc = 0;
2672 ctl.crcReturned = 0;
2673 ctl.ulDirection = RECTDIR_LFRT_BOTTOP;
2674 GpiQueryRegionRects(qt_display_ps(), d.hrgn, NULL, &ctl, NULL);
2675 ctl.crc = ctl.crcReturned;
2676 int rclcnt = ctl.crcReturned;
2677 PRECTL rcls = new RECTL[rclcnt];
2678 GpiQueryRegionRects(qt_display_ps(), d.hrgn, NULL, &ctl, rcls);
2679 PRECTL rcl = rcls;
2680 debug.nospace() << "HRGN{";
2681 for (int i = 0; i < rclcnt; i++, rcl++)
2682 debug.nospace() << " " << *rcl;
2683 delete [] rcls;
2684 debug.nospace() << "}";
2685 return debug.space();
2686}
2687
2688Q_GUI_EXPORT QDebug operator<<(QDebug debug, const RECTL &rcl)
2689{
2690 debug.nospace() << "RECTL(" << rcl.xLeft << "," << rcl.yBottom
2691 << " " << rcl.xRight << "," << rcl.yTop << ")";
2692 return debug.space();
2693}
2694
2695#define myDefFlagEx(var,fl,varstr,flstr) if (var & fl) { \
2696 if (!varstr.isEmpty()) varstr += "|"; varstr += flstr; \
2697} else do {} while(0)
2698
2699#define myDefFlag(var,fl,varstr) myDefFlagEx(var,fl,varstr,#fl)
2700#define myDefFlagCut(var,fl,varstr,pos) myDefFlagEx(var,fl,varstr,#fl + pos)
2701
2702Q_GUI_EXPORT QDebug operator<<(QDebug debug, const SWP &swp)
2703{
2704 QByteArray fl;
2705 myDefFlagEx(swp.fl, SWP_SIZE, fl, "SIZE");
2706 myDefFlagEx(swp.fl, SWP_MOVE, fl, "MOVE");
2707 myDefFlagEx(swp.fl, SWP_ZORDER, fl, "ZORD");
2708 myDefFlagEx(swp.fl, SWP_SHOW, fl, "SHOW");
2709 myDefFlagEx(swp.fl, SWP_HIDE, fl, "HIDE");
2710 myDefFlagEx(swp.fl, SWP_NOREDRAW, fl, "NORDR");
2711 myDefFlagEx(swp.fl, SWP_NOADJUST, fl, "NOADJ");
2712 myDefFlagEx(swp.fl, SWP_ACTIVATE, fl, "ACT");
2713 myDefFlagEx(swp.fl, SWP_DEACTIVATE, fl, "DEACT");
2714 myDefFlagEx(swp.fl, SWP_EXTSTATECHANGE, fl, "EXTST");
2715 myDefFlagEx(swp.fl, SWP_MINIMIZE, fl, "MIN");
2716 myDefFlagEx(swp.fl, SWP_MAXIMIZE, fl, "MAX");
2717 myDefFlagEx(swp.fl, SWP_RESTORE, fl, "REST");
2718 myDefFlagEx(swp.fl, SWP_FOCUSACTIVATE, fl, "FCSACT");
2719 myDefFlagEx(swp.fl, SWP_FOCUSDEACTIVATE, fl, "FCSDEACT");
2720 myDefFlagEx(swp.fl, SWP_NOAUTOCLOSE, fl, "NOACLOSE");
2721
2722 debug.nospace() << "SWP(" << swp.x << "," << swp.y
2723 << " " << swp.cx << "x" << swp.cy << " "
2724 << qDebugFmtHex(swp.hwndInsertBehind) << " "
2725 << fl.constData() << ")";
2726 return debug.space();
2727}
2728
2729Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QMSG &qmsg)
2730{
2731 #define myCaseBegin(a) case a: { \
2732 debug << #a": hwnd" << qDebugHWND(qmsg.hwnd);
2733 #define myCaseEnd() }
2734
2735 bool isMouse = false;
2736
2737 switch (qmsg.msg) {
2738
2739#if 1
2740 myCaseBegin(WM_MOUSEMOVE)
2741 isMouse = true; break;
2742 myCaseEnd()
2743 myCaseBegin(WM_BUTTON1DOWN)
2744 isMouse = true; break;
2745 myCaseEnd()
2746 myCaseBegin(WM_BUTTON1UP)
2747 isMouse = true; break;
2748 myCaseEnd()
2749 myCaseBegin(WM_BUTTON1DBLCLK)
2750 isMouse = true; break;
2751 myCaseEnd()
2752 myCaseBegin(WM_BUTTON2DOWN)
2753 isMouse = true; break;
2754 myCaseEnd()
2755 myCaseBegin(WM_BUTTON2UP)
2756 isMouse = true; break;
2757 myCaseEnd()
2758 myCaseBegin(WM_BUTTON2DBLCLK)
2759 isMouse = true; break;
2760 myCaseEnd()
2761 myCaseBegin(WM_BUTTON3DOWN)
2762 isMouse = true; break;
2763 myCaseEnd()
2764 myCaseBegin(WM_BUTTON3UP)
2765 isMouse = true; break;
2766 myCaseEnd()
2767 myCaseBegin(WM_BUTTON3DBLCLK)
2768 isMouse = true; break;
2769 myCaseEnd()
2770#endif
2771
2772 myCaseBegin(WM_CHAR)
2773 USHORT fl = SHORT1FROMMP(qmsg.mp1);
2774 UCHAR repeat = CHAR3FROMMP(qmsg.mp1);
2775 UCHAR scan = CHAR4FROMMP(qmsg.mp1);
2776 USHORT ch = SHORT1FROMMP(qmsg.mp2);
2777 USHORT vk = SHORT2FROMMP(qmsg.mp2);
2778 QByteArray flstr;
2779 myDefFlagEx(fl, KC_CHAR, flstr, "CHAR");
2780 myDefFlagEx(fl, KC_VIRTUALKEY, flstr, "VIRT");
2781 myDefFlagEx(fl, KC_SCANCODE, flstr, "SCAN");
2782 myDefFlagEx(fl, KC_SHIFT, flstr, "SHIFT");
2783 myDefFlagEx(fl, KC_CTRL, flstr, "CTRL");
2784 myDefFlagEx(fl, KC_ALT, flstr, "ALT");
2785 myDefFlagEx(fl, KC_KEYUP, flstr, "UP");
2786 myDefFlagEx(fl, KC_PREVDOWN, flstr, "PREVDWN");
2787 myDefFlagEx(fl, KC_LONEKEY, flstr, "LONE");
2788 myDefFlagEx(fl, KC_DEADKEY, flstr, "DEAD");
2789 myDefFlagEx(fl, KC_COMPOSITE, flstr, "COMP");
2790 myDefFlagEx(fl, KC_INVALIDCOMP, flstr, "INVCMP");
2791 myDefFlagEx(fl, KC_TOGGLE, flstr, "TGGL");
2792 myDefFlagEx(fl, KC_INVALIDCHAR, flstr, "INVCHR");
2793
2794 debug << "rep" << qDebugFmt("%02d", repeat)
2795 << "scan" << qDebugFmtHex(scan) << "ch" << qDebugFmtHex(ch)
2796 << ((ch > 32 && ch < 254) ? QString::fromLocal8Bit((char *)&ch, 1) :
2797 QString(QLatin1String(" ")))
2798 << "vk" << qDebugFmtHex(vk);
2799 debug.nospace() << "KC(" << qDebugFmtHex(fl) << ","
2800 << flstr.constData() << ")";
2801 debug.space();
2802 break;
2803 myCaseEnd()
2804
2805 myCaseBegin(WM_KBDLAYERCHANGED)
2806 debug << "mp1" << qmsg.mp1 << "mp2" << qmsg.mp2;
2807 break;
2808 myCaseEnd()
2809
2810 myCaseBegin(WM_PAINT)
2811 debug << "mp1" << qmsg.mp1 << "mp2" << qmsg.mp2;
2812 break;
2813 myCaseEnd()
2814
2815 myCaseBegin(WM_SIZE)
2816 SWP swp;
2817 WinQueryWindowPos(qmsg.hwnd, &swp);
2818 debug << "old " << SHORT1FROMMP(qmsg.mp1) << SHORT2FROMMP(qmsg.mp1)
2819 << "new " << SHORT1FROMMP(qmsg.mp2) << SHORT2FROMMP(qmsg.mp2)
2820 << swp;
2821 HWND p = WinQueryWindow(qmsg.hwnd, QW_PARENT);
2822 if (p != NULLHANDLE && p != WinQueryDesktopWindow(0, 0)) {
2823 WinQueryWindowPos(p, &swp);
2824 debug << "parent" << swp;
2825 }
2826 break;
2827 myCaseEnd()
2828
2829 myCaseBegin(WM_MOVE)
2830 SWP swp;
2831 WinQueryWindowPos(qmsg.hwnd, &swp);
2832 debug << swp;
2833 HWND p = WinQueryWindow(qmsg.hwnd, QW_PARENT);
2834 if (p != NULLHANDLE && p != WinQueryDesktopWindow(0, 0)) {
2835 WinQueryWindowPos(p, &swp);
2836 debug << "parent" << swp;
2837 }
2838 break;
2839 myCaseEnd()
2840
2841 myCaseBegin(WM_ADJUSTWINDOWPOS)
2842 debug << *((PSWP) qmsg.mp1);
2843 debug.space();
2844 break;
2845 myCaseEnd()
2846
2847 myCaseBegin(WM_WINDOWPOSCHANGED)
2848 debug << *((PSWP) qmsg.mp1);
2849 ULONG awp = LONGFROMMP(qmsg.mp2);
2850 QByteArray awpstr;
2851 myDefFlagEx(awp, AWP_MINIMIZED, awpstr, "MIN");
2852 myDefFlagEx(awp, AWP_MAXIMIZED, awpstr, "MAX");
2853 myDefFlagEx(awp, AWP_RESTORED, awpstr, "REST");
2854 myDefFlagEx(awp, AWP_ACTIVATE, awpstr, "ACT");
2855 myDefFlagEx(awp, AWP_DEACTIVATE, awpstr, "DEACT");
2856 debug.nospace() << "AWP(" << awpstr.constData() << ")";
2857 debug.space();
2858 break;
2859 myCaseEnd()
2860
2861 myCaseBegin(WM_MINMAXFRAME)
2862 debug << *((PSWP) qmsg.mp1);
2863 break;
2864 myCaseEnd()
2865
2866 myCaseBegin(WM_ACTIVATE)
2867 bool active = SHORT1FROMMP(qmsg.mp1);
2868 HWND hwnd = (HWND)qmsg.mp2;
2869 debug.nospace() << "Active(" << (active ? "TRUE)" : "FALSE)");
2870 debug.space() << "hwndActive" << qDebugHWND(hwnd);
2871 break;
2872 myCaseEnd()
2873
2874 myCaseBegin(WM_SETFOCUS)
2875 HWND hwnd = (HWND)qmsg.mp1;
2876 bool focus = SHORT1FROMMP(qmsg.mp2);
2877 debug.nospace() << "Focus(" << (focus ? "TRUE) " : "FALSE)");
2878 debug.space() << "hwndFocus" << qDebugHWND(hwnd);
2879 break;
2880 myCaseEnd()
2881
2882 myCaseBegin(WM_FOCUSCHANGE)
2883 HWND hwnd = (HWND)qmsg.mp1;
2884 bool focus = SHORT1FROMMP(qmsg.mp2);
2885 bool fl = SHORT2FROMMP(qmsg.mp2);
2886 QByteArray flstr;
2887 myDefFlagEx(fl, FC_NOSETFOCUS, flstr, "NOSETFCS");
2888 myDefFlagEx(fl, FC_NOLOSEFOCUS, flstr, "NOLOSEFCS");
2889 myDefFlagEx(fl, FC_NOSETACTIVE, flstr, "NOSETACT");
2890 myDefFlagEx(fl, FC_NOLOSEACTIVE, flstr, "NOLOSEACT");
2891 myDefFlagEx(fl, FC_NOSETSELECTION, flstr, "NOSETSEL");
2892 myDefFlagEx(fl, FC_NOLOSESELECTION, flstr, "NOSETSEL");
2893 debug.nospace() << "Focus(" << (focus ? "TRUE) " : "FALSE)");
2894 debug.space() << "hwndFocus" << qDebugHWND(hwnd);
2895 debug.nospace() << "FC(" << flstr.constData() << ")";
2896 debug.space();
2897 break;
2898 myCaseEnd()
2899
2900 myCaseBegin(WM_VRNDISABLED)
2901 break;
2902 myCaseEnd()
2903 myCaseBegin(WM_VRNENABLED)
2904 break;
2905 myCaseEnd()
2906
2907 myCaseBegin(WM_SHOW)
2908 break;
2909 myCaseEnd()
2910
2911 myCaseBegin(WM_HITTEST)
2912 PPOINTS pt = (PPOINTS)&qmsg.mp1;
2913 debug.nospace() << "Point(" << pt->x << "," << pt->y << ")";
2914 debug.space();
2915 break;
2916 myCaseEnd()
2917
2918 default:
2919 debug.nospace() << "WM_" << qDebugFmtHex(qmsg.msg) << ":";
2920 debug.space() << qDebugHWND(qmsg.hwnd);
2921 debug << "mp1" << qmsg.mp1 << "mp2" << qmsg.mp2;
2922 break;
2923 }
2924
2925 if (isMouse) {
2926 SHORT x = SHORT1FROMMP(qmsg.mp1);
2927 SHORT y = SHORT2FROMMP(qmsg.mp1);
2928 USHORT hit = SHORT1FROMMP(qmsg.mp2);
2929 bool fl = SHORT2FROMMP(qmsg.mp2);
2930 QByteArray hitstr;
2931 myDefFlagEx(hit, HT_NORMAL, hitstr, "NORMAL");
2932 myDefFlagEx(hit, HT_TRANSPARENT, hitstr, "TRANSPARENT");
2933 myDefFlagEx(hit, HT_DISCARD, hitstr, "DISCARD");
2934 myDefFlagEx(hit, HT_ERROR, hitstr, "ERROR");
2935 QByteArray flstr;
2936 myDefFlagEx(fl, KC_CHAR, flstr, "CHAR");
2937 myDefFlagEx(fl, KC_VIRTUALKEY, flstr, "VIRT");
2938 myDefFlagEx(fl, KC_SCANCODE, flstr, "SCAN");
2939 myDefFlagEx(fl, KC_SHIFT, flstr, "SHIFT");
2940 myDefFlagEx(fl, KC_CTRL, flstr, "CTRL");
2941 myDefFlagEx(fl, KC_ALT, flstr, "ALT");
2942 myDefFlagEx(fl, KC_KEYUP, flstr, "UP");
2943 myDefFlagEx(fl, KC_PREVDOWN, flstr, "PREVDWN");
2944 myDefFlagEx(fl, KC_LONEKEY, flstr, "LONE");
2945 myDefFlagEx(fl, KC_DEADKEY, flstr, "DEAD");
2946 myDefFlagEx(fl, KC_COMPOSITE, flstr, "COMP");
2947 myDefFlagEx(fl, KC_INVALIDCOMP, flstr, "INVCMP");
2948 myDefFlagEx(fl, KC_TOGGLE, flstr, "TGGL");
2949 myDefFlagEx(fl, KC_INVALIDCHAR, flstr, "INVCHR");
2950 myDefFlagEx(fl, KC_NONE, flstr, "NONE");
2951 debug << "x" << x << "y" << y;
2952 debug.nospace() << "HT(" << hitstr.constData() << ")";
2953 debug.space();
2954 debug.nospace() << "KC(" << qDebugFmtHex(fl) << ","
2955 << flstr.constData() << ")";
2956 debug.space();
2957 }
2958
2959 return debug;
2960
2961 #undef myCaseEnd
2962 #undef myCaseBegin
2963}
2964
2965#undef myDefFlagCut
2966#undef myDefFlag
2967#undef myDefFlagEx
2968
2969QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.