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

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

gui: Improved font handling (patch by komh):

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