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

Last change on this file since 109 was 109, checked in by dmik, 19 years ago

Widgets: Fixed: QPopupMenu::exec() did not return before the mouse press event that caused the popup menu closure was delivered as QWidget::keyPressEvent(); as a result, QPushButton::popupPressed() didn't execute setDown( FALSE ) before opening a new popup menu.

  • Property svn:keywords set to Id
File size: 124.2 KB
Line 
1/****************************************************************************
2** $Id: qapplication_pm.cpp 109 2006-07-30 12:33:26Z dmik $
3**
4** Implementation of OS/2 startup routines and event handling
5**
6** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 netlabs.org. Further OS/2 Development.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38// GCC headers do not define this when INCL_BASE is defined,
39// but we need it for IOCTL_KEYBOARD etc. constants
40#ifndef INCL_DOSDEVIOCTL
41#define INCL_DOSDEVIOCTL
42#endif
43
44#include "qapplication.h"
45#include "private/qapplication_p.h"
46#include "qwidget.h"
47#include "qwidgetlist.h"
48#include "qwidgetintdict.h"
49#include "qobjectlist.h"
50#include "qpainter.h"
51#include "qpixmapcache.h"
52#include "qdatetime.h"
53#include "qsessionmanager.h"
54#include "qmime.h"
55#include "qguardedptr.h"
56#include "qclipboard.h"
57#include "qthread.h"
58#include "qwhatsthis.h" // ######## dependency
59#include "qthread.h"
60#include "qlibrary.h"
61#include "qt_os2.h"
62#include "qcursor.h"
63#include "private/qinternal_p.h"
64#include "private/qcriticalsection_p.h"
65/// @todo (dmik) remove?
66//#include "private/qinputcontext_p.h"
67#include "qstyle.h"
68#include "qmetaobject.h"
69
70#include <limits.h>
71#include <string.h>
72#include <ctype.h>
73#include <stdlib.h>
74
75extern void qt_ensure_pm();
76
77/// @todo (dmik) how we can use buttons 4 and 5 on OS/2?
78//// support for xbuttons
79//#ifndef WM_XBUTTONDOWN
80//#define WM_XBUTTONDOWN 0x020B
81//#define WM_XBUTTONUP 0x020C
82//#define WM_XBUTTONDBLCLK 0x020D
83//#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam))
84//#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
85//#define XBUTTON1 0x0001
86//#define XBUTTON2 0x0002
87//#define MK_XBUTTON1 0x0020
88//#define MK_XBUTTON2 0x0040
89//#endif
90
91/// @todo (dmik) hmm, extended keys under OS/2?
92//// support for multi-media-keys on ME/2000/XP
93//#ifndef WM_APPCOMMAND
94//#define WM_APPCOMMAND 0x0319
95//
96//#define FAPPCOMMAND_MOUSE 0x8000
97//#define FAPPCOMMAND_KEY 0
98//#define FAPPCOMMAND_OEM 0x1000
99//#define FAPPCOMMAND_MASK 0xF000
100//#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
101//#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK))
102//#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM
103//#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam))
104//#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam)
105//
106//#define APPCOMMAND_BROWSER_BACKWARD 1
107//#define APPCOMMAND_BROWSER_FORWARD 2
108//#define APPCOMMAND_BROWSER_REFRESH 3
109//#define APPCOMMAND_BROWSER_STOP 4
110//#define APPCOMMAND_BROWSER_SEARCH 5
111//#define APPCOMMAND_BROWSER_FAVORITES 6
112//#define APPCOMMAND_BROWSER_HOME 7
113//#define APPCOMMAND_VOLUME_MUTE 8
114//#define APPCOMMAND_VOLUME_DOWN 9
115//#define APPCOMMAND_VOLUME_UP 10
116//#define APPCOMMAND_MEDIA_NEXTTRACK 11
117//#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12
118//#define APPCOMMAND_MEDIA_STOP 13
119//#define APPCOMMAND_MEDIA_PLAY_PAUSE 14
120//#define APPCOMMAND_LAUNCH_MAIL 15
121//#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16
122//#define APPCOMMAND_LAUNCH_APP1 17
123//#define APPCOMMAND_LAUNCH_APP2 18
124//#define APPCOMMAND_BASS_DOWN 19
125//#define APPCOMMAND_BASS_BOOST 20
126//#define APPCOMMAND_BASS_UP 21
127//#define APPCOMMAND_TREBLE_DOWN 22
128//#define APPCOMMAND_TREBLE_UP 23
129//#endif
130
131extern void qt_dispatchEnterLeave( QWidget*, QWidget* ); // qapplication.cpp
132
133extern void qt_erase_background(
134 HPS hps, int x, int y, int w, int h,
135 const QColor &bg_color,
136 const QPixmap *bg_pixmap, int off_x, int off_y, int devh
137);
138
139/*
140 Internal functions.
141*/
142
143Q_EXPORT
144void qt_draw_tiled_pixmap( HPS, int, int, int, int,
145 const QPixmap *, int, int, int );
146
147QRgb qt_sysclr2qrgb( LONG sysClr )
148{
149 // QRgb has the same RGB format (0xaarrggbb) as OS/2 uses (ignoring the
150 // highest alpha byte) so we just cast OS/2 LONG RGB value to qRgb
151 // which is an unsigned int actually.
152 return ((QRgb) WinQuerySysColor( HWND_DESKTOP, sysClr, 0 )) & RGB_MASK;
153}
154
155QFont qt_sysfont2qfont( const PSZ scope ) {
156 static const PSZ app = "PM_SystemFonts";
157 static const PSZ def = "8.Helv";
158 ULONG keyLen = 0;
159 QFont f( "Helv", 8 );
160
161 if ( PrfQueryProfileSize( HINI_USERPROFILE, app, scope, &keyLen ) && keyLen ) {
162 keyLen ++; // reserve space for a dot
163 char *buf = new char [keyLen];
164 ULONG realLen =
165 PrfQueryProfileString( HINI_USERPROFILE, app, scope, def, buf, keyLen );
166 realLen --; // excude zero terminator
167
168 // parse the font definition
169 int height = 0;
170 char *dot = strchr( buf, '.' ), *dot2 = 0;
171 if ( dot ) {
172 *dot = 0;
173 height = strtoul( buf, NULL, 10 );
174 dot2 = strchr( ++ dot, '.' );
175 if ( dot2 ) {
176 // process simulated styles
177 buf[realLen] = '.';
178 buf[realLen+1] = 0;
179 strupr( dot2 );
180/// @todo (dmik) currently, simulated bold and italic font styles are not
181// supported by Qt/OS2 because Qt doesn't support style simulation
182// explicitly. the code below is commented out to prevent selecting
183// true fonts when simulated ones are actually requested.
184// if ( strstr( dot2, ".BOLD." ) ) f.setBold( TRUE );
185// if ( strstr( dot2, ".ITALIC.") ) f.setItalic( TRUE );
186 if ( strstr( dot2, ".UNDERSCORE.") ) f.setUnderline( TRUE );
187 if ( strstr( dot2, ".UNDERLINED.") ) f.setUnderline( TRUE );
188 if ( strstr( dot2, ".STRIKEOUT.") ) f.setStrikeOut( TRUE );
189 *dot2 = 0;
190 }
191 // query non-simulated styles
192 FONTMETRICS fm;
193 LONG cnt = 1; // use the first match
194 GpiQueryFonts(
195 qt_display_ps(), QF_PUBLIC, dot, &cnt, sizeof(FONTMETRICS), &fm );
196 if ( cnt ) {
197 // the code below is mostly from QFontDatabasePrivate::reload()
198 if ( fm.fsSelection & FM_SEL_ITALIC ) f.setItalic( TRUE );
199 if ( fm.fsType & FM_TYPE_FIXED ) f.setFixedPitch( TRUE );
200 USHORT weight = fm.usWeightClass;
201 USHORT width = fm.usWidthClass;
202 if ( weight < 4 ) f.setWeight( QFont::Light );
203 else if ( weight < 6 ) f.setWeight( QFont::Normal );
204 else if ( weight < 7 ) f.setWeight( QFont::DemiBold );
205 else if ( weight < 8 ) f.setWeight( QFont::Bold );
206 else f.setWeight( QFont::Black );
207 switch ( width ) {
208 case 1: f.setStretch( QFont::UltraCondensed ); break;
209 case 2: f.setStretch( QFont::ExtraCondensed ); break;
210 case 3: f.setStretch( QFont::Condensed ); break;
211 case 4: f.setStretch( QFont::SemiCondensed ); break;
212 case 5: f.setStretch( QFont::Unstretched ); break;
213 case 6: f.setStretch( QFont::SemiExpanded ); break;
214 case 7: f.setStretch( QFont::Expanded ); break;
215 case 8: f.setStretch( QFont::ExtraExpanded ); break;
216 case 9: f.setStretch( QFont::UltraExpanded ); break;
217 default: f.setStretch( QFont::Unstretched ); break;
218 }
219 f.setFamily( fm.szFamilyname );
220 f.setPointSize( height );
221 }
222 }
223 delete[] buf;
224 }
225 return f;
226}
227
228/*****************************************************************************
229 Internal variables and functions
230 *****************************************************************************/
231
232static HWND curWin = 0; // current window
233static HPS displayPS = 0; // display presentation space
234
235#if !defined (QT_NO_SESSIONMANAGER)
236
237// Session management
238static bool sm_blockUserInput = FALSE;
239static bool sm_smActive = FALSE;
240extern QSessionManager* qt_session_manager_self;
241static bool sm_cancel = FALSE;
242static bool sm_gracefulShutdown = FALSE;
243static bool sm_quitSkipped = FALSE;
244bool qt_about_to_destroy_wnd = FALSE;
245
246//#define DEBUG_SESSIONMANAGER
247
248#endif
249
250static bool replayPopupMouseEvent = FALSE; // replay handling when popups close
251
252static bool ignoreNextMouseReleaseEvent = FALSE; // ignore the next release event if
253 // return from a modal widget
254#if defined(QT_DEBUG)
255static bool appNoGrab = FALSE; // mouse/keyboard grabbing
256#endif
257
258static bool app_do_modal = FALSE; // modal mode
259extern QWidgetList *qt_modal_stack;
260extern QDesktopWidget *qt_desktopWidget;
261static QWidget *popupButtonFocus = 0;
262static bool popupCloseDownMode = FALSE;
263static bool qt_try_modal( QWidget *, QMSG *, int& ret );
264
265QWidget *qt_button_down = 0; // widget got last button-down
266
267extern bool qt_tryAccelEvent( QWidget*, QKeyEvent* ); // def in qaccel.cpp
268
269static HWND autoCaptureWnd = 0;
270static bool autoCaptureReleased = FALSE;
271static void setAutoCapture( HWND ); // automatic capture
272static void releaseAutoCapture();
273
274//@@TODO (dmik):
275// do we really need this filter stuff or qApp->pmEventFilter()
276// is enough?
277typedef int (*QPMEventFilter) (QMSG*);
278static QPMEventFilter qt_pm_event_filter = 0;
279
280Q_EXPORT QPMEventFilter qt_set_pm_event_filter( QPMEventFilter filter )
281{
282 QPMEventFilter old_filter = qt_pm_event_filter;
283 qt_pm_event_filter = filter;
284 return old_filter;
285}
286
287typedef bool (*QPMEventFilterEx) (QMSG*,MRESULT&);
288static QPMEventFilterEx qt_pm_event_filter_ex = 0;
289
290Q_EXPORT QPMEventFilterEx qt_set_pm_event_filter_ex( QPMEventFilterEx filter )
291{
292 QPMEventFilterEx old = qt_pm_event_filter_ex;
293 qt_pm_event_filter_ex = filter;
294 return old;
295}
296
297bool qt_pmEventFilter( QMSG* msg, MRESULT &result )
298{
299 result = NULL;
300 if ( qt_pm_event_filter && qt_pm_event_filter( msg ) )
301 return TRUE;
302 if ( qt_pm_event_filter_ex && qt_pm_event_filter_ex( msg, result ) )
303 return TRUE;
304 return qApp->pmEventFilter( msg );
305}
306
307static void unregWinClasses();
308
309extern QCursor *qt_grab_cursor();
310
311extern "C" MRESULT EXPENTRY QtWndProc( HWND, ULONG, MPARAM, MPARAM );
312
313class QETWidget : public QWidget // event translator widget
314{
315public:
316 void setWFlags( WFlags f ) { QWidget::setWFlags(f); }
317 void clearWFlags( WFlags f ) { QWidget::clearWFlags(f); }
318 void setWState( WState f ) { QWidget::setWState(f); }
319 void clearWState( WState f ) { QWidget::clearWState(f); }
320 QWExtra *xtra() { return QWidget::extraData(); }
321 QTLWExtra *top() { return QWidget::topData(); }
322 bool pmEvent( QMSG *m ) { return QWidget::pmEvent(m); }
323#if defined(Q_CC_GNU)
324 void markFrameStrutDirty() { fstrut_dirty = 1; }
325#else
326 void markFrameStrutDirty() { QWidget::fstrut_dirty = 1; }
327#endif
328 void updateFrameStrut() { QWidget::updateFrameStrut(); }
329 bool translateMouseEvent( const QMSG &qmsg );
330 bool translateKeyEvent( const QMSG &qmsg, bool grab );
331#ifndef QT_NO_WHEELEVENT
332 bool translateWheelEvent( const QMSG &qmsg );
333#endif
334 bool sendKeyEvent( QEvent::Type type, int code, int ascii,
335 int state, bool grab, const QString& text,
336 bool autor = FALSE );
337 bool translatePaintEvent( const QMSG &qmsg );
338 bool translateConfigEvent( const QMSG &qmsg );
339 bool translateCloseEvent( const QMSG &qmsg );
340//@@TODO (dmik): later
341// void repolishStyle( QStyle &style ) { styleChange( style ); }
342//@@TODO (dmik): it seems we don't need this
343// void reparentWorkaround();
344 void showChildren(bool spontaneous) { QWidget::showChildren(spontaneous); }
345 void hideChildren(bool spontaneous) { QWidget::hideChildren(spontaneous); }
346};
347
348//@@TODO (dmik): it seems we don't need this
349//void QETWidget::reparentWorkaround()
350//{
351// ((QWidgetIntDict*)QWidget::wmapper())->remove((long)winid);
352// clearWState(WState_Created | WState_Visible | WState_ForceHide);
353// winid = 0;
354// QRect geom = geometry();
355// create(0, FALSE, FALSE);
356// setGeometry(geom);
357// QWidget *p = parentWidget();
358// while (p) {
359// if (!p->isVisible())
360// return;
361// p = p->parentWidget();
362// }
363// show();
364//}
365
366
367static bool qt_show_system_menu( QWidget* tlw )
368{
369 HWND fId = tlw->winFId();
370 HWND sysMenu = WinWindowFromID( fId, FID_SYSMENU );
371 if ( !sysMenu )
372 return FALSE; // no menu for this window
373 WinPostMsg( sysMenu, MM_STARTMENUMODE, MPFROM2SHORT(TRUE, FALSE), 0 );
374 return TRUE;
375}
376
377// Palette handling
378extern QPalette *qt_std_pal;
379extern void qt_create_std_palette();
380
381static void qt_set_pm_resources()
382{
383 // Do the font settings
384
385 QFont windowFont = qt_sysfont2qfont( "WindowText" );
386 QFont menuFont = qt_sysfont2qfont( "Menus" );
387 QFont iconFont = qt_sysfont2qfont( "IconText" );
388 QFont titleFont = qt_sysfont2qfont( "WindowTitles" );
389
390 QApplication::setFont( windowFont, TRUE );
391 QApplication::setFont( menuFont, TRUE, "QPopupMenu" );
392 QApplication::setFont( menuFont, TRUE, "QMenuBar" );
393 QApplication::setFont( iconFont, TRUE, "QTipLabel" );
394 QApplication::setFont( iconFont, TRUE, "QStatusBar" );
395 QApplication::setFont( titleFont, TRUE, "QTitleBar" );
396 QApplication::setFont( titleFont, TRUE, "QDockWindowTitleBar" );
397
398 if ( qt_std_pal && *qt_std_pal != QApplication::palette() )
399 return;
400
401 // Do the color settings
402
403 // active colors
404 QColorGroup acg;
405 acg.setColor( QColorGroup::Foreground,
406 QColor( qt_sysclr2qrgb( SYSCLR_WINDOWTEXT ) ) );
407 acg.setColor( QColorGroup::Background,
408 QColor( qt_sysclr2qrgb( SYSCLR_DIALOGBACKGROUND ) ) );
409 acg.setColor( QColorGroup::ButtonText,
410 QColor( qt_sysclr2qrgb( SYSCLR_MENUTEXT ) ) );
411 acg.setColor( QColorGroup::Button,
412 QColor( qt_sysclr2qrgb( SYSCLR_BUTTONMIDDLE ) ) );
413 acg.setColor( QColorGroup::Light,
414 QColor( qt_sysclr2qrgb( SYSCLR_BUTTONLIGHT ) ) );
415 acg.setColor( QColorGroup::Dark,
416 QColor( qt_sysclr2qrgb( SYSCLR_BUTTONDARK ) ) );
417 acg.setColor( QColorGroup::Midlight,
418 QColor( (acg.light().red() + acg.button().red()) / 2,
419 (acg.light().green() + acg.button().green()) / 2,
420 (acg.light().blue() + acg.button().blue()) / 2 ) );
421 acg.setColor( QColorGroup::Mid,
422 QColor( (acg.dark().red() + acg.button().red()) / 2,
423 (acg.dark().green() + acg.button().green()) / 2,
424 (acg.dark().blue() + acg.button().blue()) / 2 ) );
425 acg.setColor( QColorGroup::Text,
426 QColor( qt_sysclr2qrgb( SYSCLR_MENUTEXT ) ) );
427 acg.setColor( QColorGroup::Base,
428 QColor( qt_sysclr2qrgb( SYSCLR_ENTRYFIELD ) ) );
429 acg.setColor( QColorGroup::BrightText,
430 QColor( qt_sysclr2qrgb( SYSCLR_BUTTONLIGHT ) ) );
431 acg.setColor( QColorGroup::Shadow,
432 Qt::black );
433 acg.setColor( QColorGroup::Highlight,
434 QColor( qt_sysclr2qrgb( SYSCLR_HILITEBACKGROUND ) ) );
435 acg.setColor( QColorGroup::HighlightedText,
436 QColor( qt_sysclr2qrgb( SYSCLR_HILITEFOREGROUND ) ) );
437
438 // these colors are not present in the PM system palette
439 acg.setColor( QColorGroup::Link, Qt::blue );
440 acg.setColor( QColorGroup::LinkVisited, Qt::magenta );
441
442 // disabled colors
443 QColorGroup dcg = acg;
444 dcg.setColor( QColorGroup::Foreground,
445 QColor( qt_sysclr2qrgb( SYSCLR_MENUDISABLEDTEXT ) ) );
446 dcg.setColor( QColorGroup::Text,
447 QColor( qt_sysclr2qrgb( SYSCLR_MENUDISABLEDTEXT ) ) );
448
449 // inactive colors are currently the same as active
450 QColorGroup icg = acg;
451
452 QPalette pal( acg, dcg, icg );
453 QApplication::setPalette( pal, TRUE );
454 *qt_std_pal = pal;
455
456 // a special palette for menus
457 acg.setColor( QColorGroup::Highlight,
458 QColor( qt_sysclr2qrgb( SYSCLR_MENUHILITEBGND ) ) );
459 acg.setColor( QColorGroup::HighlightedText,
460 QColor( qt_sysclr2qrgb( SYSCLR_MENUHILITE ) ) );
461 QApplication::setPalette( QPalette( acg, dcg, icg ), TRUE, "QPopupMenu");
462 QApplication::setPalette( QPalette( acg, dcg, icg ), TRUE, "QMenuBar");
463}
464
465/*****************************************************************************
466 qt_init() - initializes Qt for OS/2
467 *****************************************************************************/
468
469// need to get default font?
470extern bool qt_app_has_font;
471
472void qt_init( int *argcptr, char **argv, QApplication::Type )
473{
474
475#if defined(QT_DEBUG)
476 int argc = *argcptr;
477 int i, j;
478
479 // Get command line params
480
481 j = argc ? 1 : 0;
482 for ( i=1; i<argc; i++ ) {
483 if ( argv[i] && *argv[i] != '-' ) {
484 argv[j++] = argv[i];
485 continue;
486 }
487 QCString arg = argv[i];
488 if ( arg == "-nograb" )
489 appNoGrab = !appNoGrab;
490 else
491 argv[j++] = argv[i];
492 }
493 *argcptr = j;
494#else
495 Q_UNUSED( argcptr );
496 Q_UNUSED( argv );
497#endif // QT_DEBUG
498
499 // No message boxes but important ones
500//@@TODO (dmik): configuring error popups per process is not usual practice
501// in OS/2 (since global AUTOFAIL/SUPPRESSPOPUPS control this). remove it?
502 DosError( FERR_DISABLEHARDERR | FERR_ENABLEEXCEPTION );
503
504 // Ensure we are in PM mode
505 qt_ensure_pm();
506 // Force creation of the main event loop to make it possible to
507 // create windows before the application invikes exec()
508 QApplication::eventLoop();
509
510
511//@@TODO (dmik): do we need appInst anywhere? if yes, make it obtaining its
512// value using the return value of qt_ensure_pm() since it also uses PIB.
513// if ( appInst == 0 ) {
514// PPIB ppib;
515// DosGetInfoBlocks( NULL, &ppib );
516// appInst = ppib->pib_hmte;
517// }
518
519 // Misc. initialization
520 QPMMime::initialize();
521 QColor::initialize();
522 QFont::initialize();
523 QCursor::initialize();
524 QPainter::initialize();
525#if defined(QT_THREAD_SUPPORT)
526 QThread::initialize();
527#endif
528 qApp->setName( qAppName() );
529
530 // default font
531 if ( !qt_app_has_font )
532 QApplication::setFont( QFont( "Helv", 8 ) );
533
534 // QFont::locale_init(); ### Uncomment when it does something on OS/2
535
536 if ( !qt_std_pal )
537 qt_create_std_palette();
538
539 if ( QApplication::desktopSettingsAware() )
540 qt_set_pm_resources();
541
542//@@TODO (dmik): remove?
543// QInputContext::init();
544}
545
546/*****************************************************************************
547 qt_cleanup() - cleans up when the application is finished
548 *****************************************************************************/
549
550void qt_cleanup()
551{
552 unregWinClasses();
553 QPixmapCache::clear();
554 QPainter::cleanup();
555 QCursor::cleanup();
556 QFont::cleanup();
557 QColor::cleanup();
558 QSharedDoubleBuffer::cleanup();
559#if defined(QT_THREAD_SUPPORT)
560 QThread::cleanup();
561#endif
562 if ( displayPS ) {
563 WinReleasePS( displayPS );
564 displayPS = 0;
565 }
566
567//@@TODO (dmik): remove?
568// QInputContext::shutdown();
569}
570
571
572/*****************************************************************************
573 Platform specific global and internal functions
574 *****************************************************************************/
575
576Q_EXPORT const char *qAppFileName() // get application file name
577{
578 static char appFileName[CCHMAXPATH] = "\0";
579 if ( !appFileName[0] ) {
580 PPIB ppib;
581 DosGetInfoBlocks( NULL, &ppib );
582 DosQueryModuleName( ppib->pib_hmte, sizeof(appFileName), appFileName );
583 }
584 return appFileName;
585}
586
587Q_EXPORT const char *qAppName() // get application name
588{
589 static char appName[CCHMAXPATH] = "\0";
590 if ( !appName[0] ) {
591 const char *p = strrchr( qAppFileName(), '\\' ); // skip path
592 if ( p )
593 memcpy( appName, p+1, qstrlen(p) );
594 int l = qstrlen( appName );
595 if ( (l > 4) && !qstricmp( appName + l - 4, ".exe" ) )
596 appName[l-4] = '\0'; // drop .exe extension
597 }
598 return appName;
599}
600
601Q_EXPORT HPS qt_display_ps() // get display PS
602{
603 if ( !displayPS )
604 displayPS = WinGetScreenPS( HWND_DESKTOP );
605 return displayPS;
606}
607
608bool qt_nograb() // application no-grab option
609{
610#if defined(QT_DEBUG)
611 return appNoGrab;
612#else
613 return FALSE;
614#endif
615}
616
617
618static QAsciiDict<int> *winclassNames = 0;
619
620const QString qt_reg_winclass( int flags ) // register window class
621{
622 if ( flags & Qt::WType_Desktop )
623 return QString();
624
625 if ( !winclassNames ) {
626 winclassNames = new QAsciiDict<int>;
627 Q_CHECK_PTR( winclassNames );
628 }
629
630 ULONG style = 0;
631 QString cname;
632 if ( flags & Qt::WType_TopLevel ) {
633 if ( flags & Qt::WType_Popup ) {
634 cname = "QPopup";
635 } else {
636 // this class is for frame window clients when WC_FRAME is used.
637 cname = "QClient";
638 style |= CS_MOVENOTIFY;
639 }
640 } else {
641 cname = "QWidget";
642 }
643
644 if ( winclassNames->find(cname.latin1()) ) // already registered
645 return cname;
646
647 // QT_EXTRAWINDATASIZE is defined in qwindowdefs_pm.h.
648 WinRegisterClass( 0, cname.latin1(), QtWndProc, style, QT_EXTRAWINDATASIZE );
649
650 winclassNames->insert( cname.latin1(), (int*)1 );
651 return cname;
652}
653
654static void unregWinClasses()
655{
656 if ( !winclassNames )
657 return;
658 // there is no need to unregister private window classes -- it is done
659 // automatically upon process termination.
660 delete winclassNames;
661 winclassNames = 0;
662}
663
664
665/*****************************************************************************
666 Platform specific QApplication members
667 *****************************************************************************/
668
669void QApplication::setMainWidget( QWidget *mainWidget )
670{
671 main_widget = mainWidget;
672}
673
674//@@TODO (dmik): later (os/2 version?)
675//Qt::WindowsVersion QApplication::winVersion()
676//{
677// return qt_winver;
678//}
679
680#ifndef QT_NO_CURSOR
681
682/*****************************************************************************
683 QApplication cursor stack
684 *****************************************************************************/
685
686typedef QPtrList<QCursor> QCursorList;
687
688static QCursorList *cursorStack = 0;
689
690void QApplication::setOverrideCursor( const QCursor &cursor, bool replace )
691{
692 if ( !cursorStack ) {
693 cursorStack = new QCursorList;
694 Q_CHECK_PTR( cursorStack );
695 cursorStack->setAutoDelete( TRUE );
696 }
697 app_cursor = new QCursor( cursor );
698 Q_CHECK_PTR( app_cursor );
699 if ( replace )
700 cursorStack->removeLast();
701 cursorStack->append( app_cursor );
702 WinSetPointer( HWND_DESKTOP, app_cursor->handle() );
703}
704
705void QApplication::restoreOverrideCursor()
706{
707 if ( !cursorStack ) // no cursor stack
708 return;
709 cursorStack->removeLast();
710 app_cursor = cursorStack->last();
711 if ( app_cursor ) {
712 WinSetPointer( HWND_DESKTOP, app_cursor->handle() );
713 } else {
714 delete cursorStack;
715 cursorStack = 0;
716 QWidget *w = QWidget::find( curWin );
717 if ( w )
718 WinSetPointer( HWND_DESKTOP, w->cursor().handle() );
719 else
720 WinSetPointer( HWND_DESKTOP, arrowCursor.handle() );
721 }
722}
723
724#endif
725
726/*
727 Internal function called from QWidget::setCursor()
728*/
729
730void qt_set_cursor( QWidget *w, const QCursor& /* c */)
731{
732 if ( !curWin )
733 return;
734 QWidget* cW = QWidget::find( curWin );
735 if ( !cW || cW->topLevelWidget() != w->topLevelWidget() ||
736 !cW->isVisible() || !cW->hasMouse() || cursorStack )
737 return;
738
739 WinSetPointer( HWND_DESKTOP, cW->cursor().handle() );
740}
741
742
743void QApplication::setGlobalMouseTracking( bool enable )
744{
745 bool tellAllWidgets;
746 if ( enable ) {
747 tellAllWidgets = (++app_tracking == 1);
748 } else {
749 tellAllWidgets = (--app_tracking == 0);
750 }
751 if ( tellAllWidgets ) {
752 QWidgetIntDictIt it( *((QWidgetIntDict*)QWidget::mapper) );
753 register QWidget *w;
754 while ( (w=it.current()) ) {
755 if ( app_tracking > 0 ) { // switch on
756 if ( !w->testWState(WState_MouseTracking) ) {
757 w->setMouseTracking( TRUE );
758 }
759 } else { // switch off
760 if ( w->testWState(WState_MouseTracking) ) {
761 w->setMouseTracking( FALSE );
762 }
763 }
764 ++it;
765 }
766 }
767}
768
769
770/*****************************************************************************
771 Routines to find a Qt widget from a screen position
772 *****************************************************************************/
773
774static QWidget *findChildWidget( const QWidget *p, const QPoint &pos )
775{
776 if ( p->children() ) {
777 QWidget *w;
778 QObjectListIt it( *p->children() );
779 it.toLast();
780 while ( it.current() ) {
781 if ( it.current()->isWidgetType() ) {
782 w = (QWidget*)it.current();
783 if ( w->isVisible() && w->geometry().contains(pos) ) {
784 QWidget *c = findChildWidget( w, w->mapFromParent(pos) );
785 return c ? c : w;
786 }
787 }
788 --it;
789 }
790 }
791 return 0;
792}
793
794QWidget *QApplication::widgetAt( int x, int y, bool child )
795{
796 // flip y coordinate
797 y = desktop()->height() - (y + 1);
798 POINTL ptl = { x, y };
799 HWND win = WinWindowFromPoint( HWND_DESKTOP, &ptl, child );
800 if ( !win )
801 return 0;
802
803 QWidget *w = QWidget::find( win );
804 if( !w && !child )
805 return 0;
806//@@TODO (dmik): can it ever happen that a child window is a not Qt window
807// but its (grand) parent is?
808 while (
809 !w && (win = WinQueryWindow( win, QW_PARENT )) != desktop()->winId()
810 ) {
811 w = QWidget::find( win );
812 }
813 return w;
814}
815
816void QApplication::beep()
817{
818 WinAlarm( HWND_DESKTOP, WA_WARNING );
819}
820
821/*****************************************************************************
822 OS/2-specific drawing used here
823 *****************************************************************************/
824
825static void drawTile( HPS hps, int x, int y, int w, int h,
826 const QPixmap *pixmap, int xOffset, int yOffset, int devh )
827{
828 int yPos, xPos, drawH, drawW, yOff, xOff;
829 yPos = y;
830 yOff = yOffset;
831 while( yPos < y + h ) {
832 drawH = pixmap->height() - yOff; // Cropping first row
833 if ( yPos + drawH > y + h ) // Cropping last row
834 drawH = y + h - yPos;
835 xPos = x;
836 xOff = xOffset;
837 while( xPos < x + w ) {
838 drawW = pixmap->width() - xOff; // Cropping first column
839 if ( xPos + drawW > x + w ) // Cropping last column
840 drawW = x + w - xPos;
841//@@TODO (dmik): optimize: flip y only once and change loops accodringly
842 // flip y coordinates
843 POINTL ptls[] = {
844 { xPos, yPos }, { xPos + drawW, drawH },
845 { xOff, pixmap->height() - (yOff + drawH) }
846 };
847 if ( devh ) ptls[0].y = devh - (ptls[0].y + drawH);
848 ptls[1].y += ptls[0].y;
849 GpiBitBlt( hps, pixmap->handle(), 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
850 xPos += drawW;
851 xOff = 0;
852 }
853 yPos += drawH;
854 yOff = 0;
855 }
856}
857
858//@@TODO (dmik): implement as fill pattern?
859// masks and transforms are not used here.
860Q_EXPORT
861void qt_fill_tile( QPixmap *tile, const QPixmap &pixmap )
862{
863 copyBlt( tile, 0, 0, &pixmap, 0, 0, -1, -1);
864 int x = pixmap.width();
865 while ( x < tile->width() ) {
866 copyBlt( tile, x, 0, tile, 0, 0, x, pixmap.height() );
867 x *= 2;
868 }
869 int y = pixmap.height();
870 while ( y < tile->height() ) {
871 copyBlt( tile, 0, y, tile, 0, 0, tile->width(), y );
872 y *= 2;
873 }
874}
875
876//@@TODO (dmik): implement as fill pattern?
877// masks and transforms are not used here.
878Q_EXPORT
879void qt_draw_tiled_pixmap( HPS hps, int x, int y, int w, int h,
880 const QPixmap *bg_pixmap,
881 int off_x, int off_y, int devh )
882{
883 QPixmap *tile = 0;
884 QPixmap *pm;
885 int sw = bg_pixmap->width(), sh = bg_pixmap->height();
886 if ( sw*sh < 8192 && sw*sh < 16*w*h ) {
887 int tw = sw, th = sh;
888 while ( tw*th < 32678 && tw < w/2 )
889 tw *= 2;
890 while ( tw*th < 32678 && th < h/2 )
891 th *= 2;
892 tile = new QPixmap( tw, th, bg_pixmap->depth(),
893 QPixmap::NormalOptim );
894 qt_fill_tile( tile, *bg_pixmap );
895 pm = tile;
896 } else {
897 pm = (QPixmap*)bg_pixmap;
898 }
899 drawTile( hps, x, y, w, h, pm, off_x, off_y, devh );
900 if ( tile )
901 delete tile;
902}
903
904
905
906/*****************************************************************************
907 Main event loop
908 *****************************************************************************/
909
910extern uint qGlobalPostedEventsCount();
911
912#ifndef QT_NO_DRAGANDDROP
913extern MRESULT qt_dispatchDragAndDrop( QWidget *, const QMSG & ); // qdnd_pm.cpp
914#endif
915
916/*!
917 The message procedure calls this function for every message
918 received. Reimplement this function if you want to process window
919 messages \e msg that are not processed by Qt. If you don't want
920 the event to be processed by Qt, then return TRUE; otherwise
921 return FALSE.
922*/
923bool QApplication::pmEventFilter( QMSG * /*msg*/ ) // OS/2 PM event filter
924{
925 return FALSE;
926}
927
928/*!
929 If \a gotFocus is TRUE, \a widget will become the active window.
930 Otherwise the active window is reset to NULL.
931*/
932void QApplication::pmFocus( QWidget *widget, bool gotFocus )
933{
934 if ( gotFocus ) {
935 setActiveWindow( widget );
936 if ( active_window && active_window->testWFlags( WType_Dialog ) ) {
937 // raise the entire application, not just the dialog
938 QWidget* mw = active_window;
939 while( mw->parentWidget() && mw->testWFlags( WType_Dialog) )
940 mw = mw->parentWidget()->topLevelWidget();
941 if ( mw != active_window )
942 WinSetWindowPos( mw->winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
943 }
944 } else {
945 setActiveWindow( 0 );
946 }
947}
948
949//
950// QtWndProc() receives all messages from the main event loop
951//
952
953// some undocumented messages (they have the WM_U_ prefix for clarity)
954//@@TODO (dmik): are they all available in Warp3?
955enum {
956 // sent to hwnd that has been entered to by a mouse pointer.
957 // FID_CLIENT also receives enter messages of its WC_FRAME.
958 // mp1 = hwnd that is entered, mp2 = hwnd that is left
959 WM_U_MOUSEENTER = 0x41E,
960 // sent to hwnd that has been left by a mouse pointer.
961 // FID_CLIENT also receives leave messages of its WC_FRAME.
962 // mp1 = hwnd that is left, mp2 = hwnd that is entered
963 WM_U_MOUSELEAVE = 0x41F,
964};
965
966static bool inLoop = FALSE;
967
968#define RETURN(x) { inLoop = FALSE; return (MRESULT) (x); }
969
970inline bool qt_sendSpontaneousEvent( QObject *receiver, QEvent *event )
971{
972 return QApplication::sendSpontaneousEvent( receiver, event );
973}
974
975extern "C" MRESULT EXPENTRY QtWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
976{
977 // message handling indicators: if result is true at the end of message
978 // processing, no default window proc is called but rc is returned.
979 bool result = TRUE;
980 MRESULT rc = (MRESULT) 0;
981
982 QEvent::Type evt_type = QEvent::None;
983 QETWidget *widget = 0;
984 bool isMouseEvent = FALSE;
985
986 if ( !qApp ) // unstable app state
987 goto do_default;
988
989 // make sure we show widgets (e.g. scrollbars) when the user resizes
990 if ( inLoop && qApp->loopLevel() )
991 qApp->sendPostedEvents( 0, QEvent::ShowWindowRequest );
992
993 inLoop = TRUE;
994
995 isMouseEvent =
996 (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
997 (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST);
998//@@TODO (dmik): later (extra buttons)
999// (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK)
1000
1001 QMSG qmsg; // create QMSG structure
1002 qmsg.hwnd = hwnd;
1003 qmsg.msg = msg;
1004 qmsg.mp1 = mp1;
1005 qmsg.mp2 = mp2;
1006 qmsg.time = WinQueryMsgTime( 0 );
1007 if ( isMouseEvent || msg == WM_CONTEXTMENU ) {
1008 qmsg.ptl.x = (short)SHORT1FROMMP(mp1);
1009 qmsg.ptl.y = (short)SHORT2FROMMP(mp1);
1010 WinMapWindowPoints( qmsg.hwnd, HWND_DESKTOP, &qmsg.ptl, 1 );
1011 } else {
1012 WinQueryMsgPos( 0, &qmsg.ptl );
1013 }
1014 // flip y coordinate
1015 qmsg.ptl.y = QApplication::desktop()->height() - (qmsg.ptl.y + 1);
1016
1017/// @todo (dmik) do we need this?
1018// /*
1019// // sometimes the autograb is not released, so the clickevent is sent
1020// // to the wrong window. We ignore this for now, because it doesn't
1021// // cause any problems.
1022// if ( msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN ) {
1023// HWND handle = WindowFromPoint( msg.pt );
1024// if ( msg.hwnd != handle ) {
1025// msg.hwnd = handle;
1026// hwnd = handle;
1027// }
1028// }
1029// */
1030
1031 if ( qt_pmEventFilter( &qmsg, rc ) ) // send through app filter
1032 RETURN( rc );
1033
1034 switch ( msg ) {
1035#if !defined (QT_NO_SESSIONMANAGER)
1036 case WM_SAVEAPPLICATION: {
1037#if defined (DEBUG_SESSIONMANAGER)
1038 qDebug( "WM_SAVEAPPLICATION: sm_gracefulShutdown=%d "
1039 "qt_about_to_destroy_wnd=%d (mp1=%p mp2=%p)",
1040 sm_gracefulShutdown, qt_about_to_destroy_wnd,
1041 mp1, mp2 );
1042#endif
1043 // PM seems to post this message to all top-level windows on system
1044 // shutdown, so react only to the first one. Also, this message is
1045 // always sent by WinDestroyWindow(), where it must be also ignored.
1046 if ( !qt_about_to_destroy_wnd && !sm_smActive &&
1047 !sm_gracefulShutdown ) {
1048 sm_smActive = TRUE;
1049 sm_gracefulShutdown = TRUE;
1050 sm_blockUserInput = TRUE; // prevent user-interaction outside interaction windows
1051 sm_cancel = FALSE;
1052 sm_quitSkipped = FALSE;
1053 if ( qt_session_manager_self )
1054 qApp->commitData( *qt_session_manager_self );
1055 sm_smActive = FALSE; // session management has been finished
1056 if ( sm_cancel ) {
1057 // Here we try to cancel the Extended XWorkplace shutdown.
1058 // If it's XWorkplace who sent us WM_SAVEAPPLICATION, then
1059 // it probably passed us non-NULL parameters, so that
1060 // mp1 = it's window handle and mp2 = WM_COMMAND code to
1061 // cancel the shutdown procedure.
1062 HWND shutdownHwnd = HWNDFROMMP(mp1);
1063 if ( WinIsWindow( 0, shutdownHwnd ) ) {
1064 WinPostMsg( shutdownHwnd, WM_COMMAND, mp2, 0 );
1065 // Ensure we will get WM_QUIT anyway, even if xwp was
1066 // not that fast to post it yet (we need it to correctly
1067 // finish the graceful shutdown procedure)
1068 sm_quitSkipped = TRUE;
1069 }
1070 }
1071 // repost WM_QUIT to ourselves because we might have ignored
1072 // it in qt_app_canQuit(), so will not get one anymore
1073 if ( sm_quitSkipped )
1074 WinPostMsg( hwnd, WM_QUIT, 0, 0 );
1075 }
1076 // PMREF recommends to pass it to WinDefWindowProc()
1077 rc = WinDefWindowProc( hwnd, msg, mp1, mp2 );
1078 RETURN( rc );
1079 }
1080#endif
1081
1082/// @todo (dmik) later
1083// case WM_SETTINGCHANGE:
1084//#ifdef Q_OS_TEMP
1085// // CE SIP hide/show
1086// if ( wParam == SPI_SETSIPINFO ) {
1087// QResizeEvent re( QSize(0, 0), QSize(0, 0) ); // Calculated by QDesktopWidget
1088// QApplication::sendEvent( qt_desktopWidget, &re );
1089// break;
1090// }
1091//#endif
1092// // ignore spurious XP message when user logs in again after locking
1093// if ( qApp->type() == QApplication::Tty )
1094// break;
1095// if ( QApplication::desktopSettingsAware() && wParam != SPI_SETWORKAREA ) {
1096// widget = (QETWidget*)QWidget::find( hwnd );
1097// if ( widget ) {
1098// widget->markFrameStrutDirty();
1099// if ( !widget->parentWidget() )
1100// qt_set_windows_resources();
1101// }
1102// }
1103// break;
1104// case WM_SYSCOLORCHANGE:
1105// if ( qApp->type() == QApplication::Tty )
1106// break;
1107// if ( QApplication::desktopSettingsAware() ) {
1108// widget = (QETWidget*)QWidget::find( hwnd );
1109// if ( widget && !widget->parentWidget() )
1110// qt_set_windows_resources();
1111// }
1112// break;
1113
1114 case WM_BUTTON1DOWN:
1115 case WM_BUTTON2DOWN:
1116 case WM_BUTTON3DOWN:
1117/// @todo (dmik) later (extra buttons)
1118// case WM_XBUTTONDOWN:
1119 if ( ignoreNextMouseReleaseEvent )
1120 ignoreNextMouseReleaseEvent = FALSE;
1121 break;
1122 case WM_BUTTON1UP:
1123 case WM_BUTTON2UP:
1124 case WM_BUTTON3UP:
1125/// @todo (dmik) later (extra buttons)
1126// case WM_XBUTTONUP:
1127 if ( ignoreNextMouseReleaseEvent ) {
1128 ignoreNextMouseReleaseEvent = FALSE;
1129 if ( qt_button_down && qt_button_down->winId() == autoCaptureWnd ) {
1130 releaseAutoCapture();
1131 qt_button_down = 0;
1132 }
1133 RETURN( TRUE );
1134 }
1135 break;
1136
1137 default:
1138 break;
1139 }
1140
1141 if ( !widget )
1142 widget = (QETWidget*)QWidget::find( hwnd );
1143 if ( !widget ) // don't know this widget
1144 goto do_default;
1145
1146 if ( app_do_modal ) { // modal event handling
1147 int ret = 0;
1148 if ( !qt_try_modal( widget, &qmsg, ret ) )
1149 return MRESULT( ret );
1150 }
1151
1152 if ( widget->pmEvent( &qmsg ) ) // send through widget filter
1153 RETURN( TRUE );
1154
1155 if ( isMouseEvent ) { // mouse events
1156 if ( qApp->activePopupWidget() != 0 ) { // in popup mode
1157 QWidget* w = QApplication::widgetAt( qmsg.ptl.x, qmsg.ptl.y, TRUE );
1158 if ( w ) {
1159 POINTL ptl = { SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1) };
1160 WinMapWindowPoints( qmsg.hwnd, w->winId(), &ptl, 1 );
1161 qmsg.mp1 = MPFROM2SHORT( ptl.x, ptl.y );
1162 widget = (QETWidget*)w;
1163 }
1164 }
1165 result = widget->translateMouseEvent( qmsg );
1166 rc = (MRESULT) result;
1167#ifndef QT_NO_WHEELEVENT
1168 } else if ( msg == WM_VSCROLL || msg == WM_HSCROLL ) {
1169 result = widget->translateWheelEvent( qmsg );
1170 rc = (MRESULT) result;
1171#endif
1172#ifndef QT_NO_DRAGANDDROP
1173 } else if ( msg >= WM_DRAGFIRST && msg <= WM_DRAGLAST ) {
1174 RETURN( qt_dispatchDragAndDrop( widget, qmsg ) );
1175#endif
1176 } else {
1177 switch ( msg ) {
1178
1179 case WM_TRANSLATEACCEL:
1180 if ( widget->isTopLevel() ) {
1181 rc = WinDefWindowProc( hwnd, msg, mp1, mp2 );
1182 if ( rc ) {
1183 QMSG &qmsg = *(QMSG*) mp1;
1184 if (
1185 qmsg.msg == WM_SYSCOMMAND &&
1186 WinWindowFromID( widget->winFId(), FID_SYSMENU )
1187 ) {
1188 switch ( SHORT1FROMMP(qmsg.mp1) ) {
1189 case SC_CLOSE:
1190 case SC_TASKMANAGER:
1191 RETURN( TRUE );
1192 default:
1193 break;
1194 }
1195 }
1196 }
1197 }
1198 // return FALSE in all other cases to let Qt process keystrokes
1199 // that are in the system-wide frame accelerator table.
1200 RETURN( FALSE );
1201
1202 case WM_CHAR: { // keyboard event
1203#if 0
1204 qDebug( "WM_CHAR: [%s]", widget->name() );
1205#endif
1206 QWidget *g = QWidget::keyboardGrabber();
1207 if ( g )
1208 widget = (QETWidget*)g;
1209 else if ( qApp->focusWidget() )
1210 widget = (QETWidget*)qApp->focusWidget();
1211 else if ( !widget )
1212/// @todo (dmik) currently we don't use WinSetFocus(). what for? Qt seems
1213// to completely handle focus traversal itself.
1214// || widget->winId() == WinQueryFocus( HWND_DESKTOP ) ) // We faked the message to go to exactly that widget.
1215 widget = (QETWidget*)widget->topLevelWidget();
1216 if ( widget->isEnabled() ) {
1217/// @todo (dmik) we should not pass WM_CHAR to the default window proc,
1218// otherwise it will come to us again through the widget parent (owner in PM)
1219// if the widget is not top-level, and will be treated by translateKeyEvent()
1220// as a key repeat (in case of key down) or a lost key (in case of key up).
1221// NOTE: currently we don't use WinSetFocus(), so the active top-level window
1222// will always have the focus, so it doesn't matter wheither we pass WM_CHAR
1223// to the default window proc or not.
1224// result = widget->translateKeyEvent( qmsg, g != 0 );
1225// rc = (MRESULT) result;
1226 RETURN( widget->translateKeyEvent( qmsg, g != 0 ) );
1227 }
1228 break;
1229 }
1230
1231/// @todo (dmik) later
1232// case WM_APPCOMMAND:
1233// {
1234// uint cmd = GET_APPCOMMAND_LPARAM(lParam);
1235// uint uDevice = GET_DEVICE_LPARAM(lParam);
1236// uint dwKeys = GET_KEYSTATE_LPARAM(lParam);
1237//
1238// int state = translateButtonState( dwKeys, QEvent::KeyPress, 0 );
1239//
1240// switch ( uDevice ) {
1241// case FAPPCOMMAND_KEY:
1242// {
1243// int key = 0;
1244//
1245// switch( cmd ) {
1246// case APPCOMMAND_BASS_BOOST:
1247// key = Qt::Key_BassBoost;
1248// break;
1249// case APPCOMMAND_BASS_DOWN:
1250// key = Qt::Key_BassDown;
1251// break;
1252// case APPCOMMAND_BASS_UP:
1253// key = Qt::Key_BassUp;
1254// break;
1255// case APPCOMMAND_BROWSER_BACKWARD:
1256// key = Qt::Key_Back;
1257// break;
1258// case APPCOMMAND_BROWSER_FAVORITES:
1259// key = Qt::Key_Favorites;
1260// break;
1261// case APPCOMMAND_BROWSER_FORWARD:
1262// key = Qt::Key_Forward;
1263// break;
1264// case APPCOMMAND_BROWSER_HOME:
1265// key = Qt::Key_HomePage;
1266// break;
1267// case APPCOMMAND_BROWSER_REFRESH:
1268// key = Qt::Key_Refresh;
1269// break;
1270// case APPCOMMAND_BROWSER_SEARCH:
1271// key = Qt::Key_Search;
1272// break;
1273// case APPCOMMAND_BROWSER_STOP:
1274// key = Qt::Key_Stop;
1275// break;
1276// case APPCOMMAND_LAUNCH_APP1:
1277// key = Qt::Key_Launch0;
1278// break;
1279// case APPCOMMAND_LAUNCH_APP2:
1280// key = Qt::Key_Launch1;
1281// break;
1282// case APPCOMMAND_LAUNCH_MAIL:
1283// key = Qt::Key_LaunchMail;
1284// break;
1285// case APPCOMMAND_LAUNCH_MEDIA_SELECT:
1286// key = Qt::Key_LaunchMedia;
1287// break;
1288// case APPCOMMAND_MEDIA_NEXTTRACK:
1289// key = Qt::Key_MediaNext;
1290// break;
1291// case APPCOMMAND_MEDIA_PLAY_PAUSE:
1292// key = Qt::Key_MediaPlay;
1293// break;
1294// case APPCOMMAND_MEDIA_PREVIOUSTRACK:
1295// key = Qt::Key_MediaPrev;
1296// break;
1297// case APPCOMMAND_MEDIA_STOP:
1298// key = Qt::Key_MediaStop;
1299// break;
1300// case APPCOMMAND_TREBLE_DOWN:
1301// key = Qt::Key_TrebleDown;
1302// break;
1303// case APPCOMMAND_TREBLE_UP:
1304// key = Qt::Key_TrebleUp;
1305// break;
1306// case APPCOMMAND_VOLUME_DOWN:
1307// key = Qt::Key_VolumeDown;
1308// break;
1309// case APPCOMMAND_VOLUME_MUTE:
1310// key = Qt::Key_VolumeMute;
1311// break;
1312// case APPCOMMAND_VOLUME_UP:
1313// key = Qt::Key_VolumeUp;
1314// break;
1315// default:
1316// break;
1317// }
1318// if ( key ) {
1319// bool res = FALSE;
1320// QWidget *g = QWidget::keyboardGrabber();
1321// if ( g )
1322// widget = (QETWidget*)g;
1323// else if ( qApp->focusWidget() )
1324// widget = (QETWidget*)qApp->focusWidget();
1325// else
1326// widget = (QETWidget*)widget->topLevelWidget();
1327// if ( widget->isEnabled() )
1328// res = ((QETWidget*)widget)->sendKeyEvent( QEvent::KeyPress, key, 0, state, FALSE, QString::null, g != 0 );
1329// if ( res )
1330// return TRUE;
1331// }
1332// }
1333// break;
1334//
1335// default:
1336// break;
1337// }
1338//
1339// result = FALSE;
1340// }
1341// break;
1342
1343//@@TODO (dmik):
1344// we can cause WC_FRAME to send equivalents of WM_NCMOUSEMOVE,
1345// but is it really necesary? We already do some similar stuff in WM_HITTEST
1346//#ifndef Q_OS_TEMP
1347// case WM_NCMOUSEMOVE:
1348// {
1349// // span the application wide cursor over the
1350// // non-client area.
1351// QCursor *c = qt_grab_cursor();
1352// if ( !c )
1353// c = QApplication::overrideCursor();
1354// if ( c ) // application cursor defined
1355// SetCursor( c->handle() );
1356// else
1357// result = FALSE;
1358// // generate leave event also when the caret enters
1359// // the non-client area.
1360// qt_dispatchEnterLeave( 0, QWidget::find(curWin) );
1361// curWin = 0;
1362// }
1363// break;
1364//#endif
1365
1366/// @todo (dmik) later
1367// case WM_SETTINGCHANGE:
1368// if ( !msg.wParam ) {
1369// QString area = QT_WA_INLINE( QString::fromUcs2( (unsigned short *)msg.lParam ),
1370// QString::fromLocal8Bit( (char*)msg.lParam ) );
1371// if ( area == "intl" )
1372// QApplication::postEvent( widget, new QEvent( QEvent::LocaleChange ) );
1373// }
1374// break;
1375//
1376//#ifndef Q_OS_TEMP
1377// case WM_NCLBUTTONDBLCLK:
1378// if ( wParam == HTCAPTION ) {
1379// bool window_state_changed = FALSE;
1380// if ( widget->isMaximized() ) {
1381// window_state_changed = TRUE;
1382// widget->clearWState(Qt::WState_Maximized);
1383// } else if (widget->testWFlags(Qt::WStyle_Maximize)){
1384// window_state_changed = TRUE;
1385// widget->setWState(Qt::WState_Maximized);
1386// }
1387//
1388// if (window_state_changed) {
1389// QEvent e(QEvent::WindowStateChange);
1390// qt_sendSpontaneousEvent(widget, &e);
1391// }
1392// }
1393// result = FALSE;
1394// break;
1395//#endif
1396 case WM_PAINT: // paint event
1397 result = widget->translatePaintEvent( qmsg );
1398 break;
1399 case WM_ERASEBACKGROUND: // erase window background
1400#if defined (QT_PM_NO_WIDGETMASK)
1401 // flush WM_PAINT messages here to update window contents
1402 // instantly while tracking the resize frame (normally these
1403 // messages are delivered after the user has stopped resizing
1404 // for some time). this slows down resizing slightly but gives a
1405 // better look (no invalid window contents can be seen during
1406 // resize). the alternative could be to erase the background only,
1407 // but we need to do it for every non-toplevel window, which can
1408 // also be time-consuming (WM_ERASEBACKGROUND is sent to WC_FRAME
1409 // clients only, so we would have to do all calculations ourselves).
1410 WinUpdateWindow( widget->winId() );
1411#else
1412 // We flush WM_PAINT messages in QETWidget::translateConfigEvent().
1413#endif
1414 RETURN( FALSE );
1415 break;
1416 case WM_CALCVALIDRECTS:
1417 // we must always return this value here to cause PM to reposition
1418 // our children accordingly (othwerwise we would have to do it
1419 // ourselves to keep them top-left aligned).
1420 RETURN( CVR_ALIGNLEFT | CVR_ALIGNTOP );
1421 break;
1422
1423 case WM_MOVE: // move window
1424 case WM_SIZE: // resize window
1425 result = widget->translateConfigEvent( qmsg );
1426 break;
1427
1428 case WM_ACTIVATE:
1429#if 0
1430 qDebug( "WM_ACTIVATE: [%s] %d", widget->name(), SHORT1FROMMP(mp1) );
1431#endif
1432 qApp->pmFocus( widget, SHORT1FROMMP(mp1) );
1433 break;
1434
1435 case WM_SETFOCUS:
1436#if 0
1437 qDebug( "WM_SETFOCUS: [%s] %s [%s]", widget->name(),
1438 SHORT1FROMMP(mp2) ? "<=" : "=>",
1439 QWidget::find( (HWND)mp1 ) ? QWidget::find( (HWND)mp1 )->name()
1440 : "{foreign}" );
1441#endif
1442 result = FALSE;
1443 if ( !SHORT1FROMMP(mp2) ) {
1444 // we're losing focus
1445 if ( !QWidget::find( (HWND)mp1 ) ) {
1446 if ( QApplication::activePopupWidget() ) {
1447 // Another application was activated while our popups are open,
1448 // then close all popups. In case some popup refuses to close,
1449 // we give up after 1024 attempts (to avoid an infinite loop).
1450 int maxiter = 1024;
1451 QWidget *popup;
1452 while ( (popup=QApplication::activePopupWidget()) && maxiter-- )
1453 popup->close();
1454 }
1455 if (
1456 // non-Qt ownees of our WC_FRAME window (such as
1457 // FID_SYSMENU) should not cause the focus to be lost.
1458 WinQueryWindow( (HWND)mp1, QW_OWNER ) ==
1459 widget->topLevelWidget()->winFId()
1460 )
1461 break;
1462 if ( !widget->isTopLevel() )
1463 qApp->pmFocus( widget, SHORT1FROMMP(mp2) );
1464 }
1465 }
1466 break;
1467
1468/// @todo (dmik) remove?
1469//#ifndef Q_OS_TEMP
1470// case WM_MOUSEACTIVATE:
1471// {
1472// const QWidget *tlw = widget->topLevelWidget();
1473// // Do not change activation if the clicked widget is inside a floating dock window
1474// if ( tlw->inherits( "QDockWindow" ) && qApp->activeWindow()
1475// && !qApp->activeWindow()->inherits("QDockWindow") )
1476// RETURN(MA_NOACTIVATE);
1477// }
1478// result = FALSE;
1479// break;
1480//#endif
1481
1482 case WM_SHOW:
1483 if ( !SHORT1FROMMP(mp1) && autoCaptureWnd == widget->winId() )
1484 releaseAutoCapture();
1485 result = FALSE;
1486 break;
1487/// @todo (dmik) remove later
1488// case WM_SHOWWINDOW:
1489//#ifndef Q_OS_TEMP
1490// if ( lParam == SW_PARENTOPENING ) {
1491// if ( widget->testWState(Qt::WState_ForceHide) )
1492// RETURN(0);
1493// }
1494//#endif
1495// if (!wParam && autoCaptureWnd == widget->winId())
1496// releaseAutoCapture();
1497// result = FALSE;
1498// break;
1499
1500 case WM_REALIZEPALETTE: // realize own palette
1501 if ( QColor::hPal() ) {
1502 HPS hps = WinGetPS( widget->winId() );
1503 GpiSelectPalette( hps, QColor::hPal() );
1504 ULONG cclr;
1505 WinRealizePalette( widget->winId(), hps, &cclr );
1506 WinReleasePS( hps );
1507 // on OS/2, the value returned by WinRealizePalette() does not
1508 // necessarily reflect the number of colors that have been
1509 // remapped. therefore, we cannot rely on it and must always
1510 // invalidate the window.
1511 WinInvalidateRect( widget->winId(), NULL, TRUE );
1512 RETURN( 0 );
1513 }
1514 break;
1515
1516 case WM_CLOSE: // close window
1517 widget->translateCloseEvent( qmsg );
1518 RETURN(0); // always handled
1519
1520/// @todo (dmik) it seems we don't need this
1521// case WM_DESTROY: // destroy window
1522// if ( hwnd == curWin ) {
1523// QEvent leave( QEvent::Leave );
1524// QApplication::sendEvent( widget, &leave );
1525// curWin = 0;
1526// }
1527// // We are blown away when our parent reparents, so we have to
1528// // recreate the handle
1529// if (widget->testWState(Qt::WState_Created))
1530// ((QETWidget*)widget)->reparentWorkaround();
1531// if ( widget == popupButtonFocus )
1532// popupButtonFocus = 0;
1533// result = FALSE;
1534// break;
1535
1536 case WM_CONTEXTMENU:
1537 if ( SHORT2FROMMP(mp2) ) {
1538 // keyboard event
1539 QWidget *fw = qApp->focusWidget();
1540 if ( fw ) {
1541 QContextMenuEvent e(
1542 QContextMenuEvent::Keyboard,
1543 QPoint( 5, 5 ),
1544 fw->mapToGlobal( QPoint( 5, 5 ) ),
1545 0
1546 );
1547 result = qt_sendSpontaneousEvent( fw, &e );
1548 rc = (MRESULT) result;
1549 }
1550 } else {
1551 // mouse event
1552 result = widget->translateMouseEvent( qmsg );
1553 rc = (MRESULT) result;
1554 }
1555 break;
1556
1557/// @todo (dmik) remove?
1558// case WM_IME_STARTCOMPOSITION:
1559// result = QInputContext::startComposition();
1560// break;
1561// case WM_IME_ENDCOMPOSITION:
1562// result = QInputContext::endComposition();
1563// break;
1564// case WM_IME_COMPOSITION:
1565// result = QInputContext::composition( lParam );
1566// break;
1567
1568#ifndef QT_NO_CLIPBOARD
1569 case WM_DRAWCLIPBOARD:
1570 case WM_RENDERFMT:
1571 case WM_RENDERALLFMTS:
1572 case WM_DESTROYCLIPBOARD:
1573 if ( qt_clipboard ) {
1574 QCustomEvent e( QEvent::Clipboard, &qmsg );
1575 qt_sendSpontaneousEvent( qt_clipboard, &e );
1576 RETURN(0);
1577 }
1578 result = FALSE;
1579 break;
1580#endif
1581
1582/// @todo (dmik) remove? functionality is implemented in WM_SETFOCUS above.
1583// case WM_KILLFOCUS:
1584// if ( !QWidget::find( (HWND)wParam ) ) { // we don't get focus, so unset it now
1585// if ( !widget->hasFocus() ) // work around Windows bug after minimizing/restoring
1586// widget = (QETWidget*)qApp->focusWidget();
1587// HWND focus = ::GetFocus();
1588// if ( !widget || (focus && ::IsChild( widget->winId(), focus )) ) {
1589// result = FALSE;
1590// } else {
1591// widget->clearFocus();
1592// result = TRUE;
1593// }
1594// } else {
1595// result = FALSE;
1596// }
1597// break;
1598
1599//@@TODO (dmik): later
1600// case WM_THEMECHANGED:
1601// if ( widget->testWFlags( Qt::WType_Desktop ) || !qApp || qApp->closingDown()
1602// || qApp->type() == QApplication::Tty )
1603// break;
1604//
1605// if ( widget->testWState(Qt::WState_Polished) )
1606// qApp->style().unPolish(widget);
1607//
1608// if ( widget->testWState(Qt::WState_Polished) )
1609// qApp->style().polish(widget);
1610// widget->repolishStyle( qApp->style() );
1611// if ( widget->isVisible() )
1612// widget->update();
1613// break;
1614//
1615// case WM_COMMAND:
1616// result = (wParam == 0x1);
1617// if ( result )
1618// QApplication::postEvent( widget, new QEvent( QEvent::OkRequest ) );
1619// break;
1620// case WM_HELP:
1621// QApplication::postEvent( widget, new QEvent( QEvent::HelpRequest ) );
1622// result = TRUE;
1623// break;
1624//#endif
1625
1626 case WM_U_MOUSELEAVE:
1627 // We receive a mouse leave for curWin, meaning
1628 // the mouse was moved outside our widgets
1629 if ( widget->winId() == curWin && (HWND) mp1 == curWin ) {
1630 bool dispatch = !widget->hasMouse();
1631 // hasMouse is updated when dispatching enter/leave,
1632 // so test if it is actually up-to-date
1633 if ( !dispatch ) {
1634 QRect geom = widget->geometry();
1635 if ( widget->parentWidget() && !widget->isTopLevel() ) {
1636 QPoint gp = widget->parentWidget()->mapToGlobal( widget->pos() );
1637 geom.setX( gp.x() );
1638 geom.setY( gp.y() );
1639 }
1640 QPoint cpos = QCursor::pos();
1641 dispatch = !geom.contains( cpos );
1642 }
1643 if ( dispatch ) {
1644 qt_dispatchEnterLeave( 0, QWidget::find( (WId)curWin ) );
1645 curWin = 0;
1646 }
1647 }
1648 break;
1649
1650/// @todo (dmik) remove? functionality is implemented in WM_SETFOCUS above.
1651// case WM_CANCELMODE:
1652// if ( qApp->focusWidget() ) {
1653// QFocusEvent::setReason( QFocusEvent::ActiveWindow );
1654// QFocusEvent e( QEvent::FocusOut );
1655// QApplication::sendEvent( qApp->focusWidget(), &e );
1656// QFocusEvent::resetReason();
1657// }
1658// break;
1659
1660 default:
1661 result = FALSE; // event was not processed
1662 break;
1663 }
1664 }
1665
1666 if ( evt_type != QEvent::None ) { // simple event
1667 QEvent e( evt_type );
1668 result = qt_sendSpontaneousEvent( widget, &e );
1669 }
1670 if ( result )
1671 RETURN( rc );
1672
1673do_default:
1674 RETURN( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
1675/// @todo (dmik) remove?
1676// RETURN( QInputContext::DefWindowProc(hwnd,message,wParam,lParam) )
1677}
1678
1679PFNWP QtOldFrameProc = 0;
1680
1681extern "C" MRESULT EXPENTRY QtFrameProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
1682{
1683 // message handling indicators: if result is true at the end of message
1684 // processing, no default window proc is called but rc is returned.
1685 bool result = FALSE;
1686 MRESULT rc = (MRESULT) FALSE;
1687 QETWidget *widget = 0;
1688 HWND hwndC = 0;
1689
1690 if ( !qApp ) // unstable app state
1691 goto do_default;
1692
1693 // make sure we show widgets (e.g. scrollbars) when the user resizes
1694 if ( inLoop && qApp->loopLevel() )
1695 qApp->sendPostedEvents( 0, QEvent::ShowWindowRequest );
1696
1697 inLoop = TRUE;
1698
1699 hwndC = WinWindowFromID( hwnd, FID_CLIENT );
1700 widget = (QETWidget*)QWidget::find( hwndC );
1701 if ( !widget ) // don't know this widget
1702 goto do_default;
1703
1704 switch ( msg ) {
1705 case WM_HITTEST: {
1706 if ( !WinIsWindowEnabled( hwnd ) ) {
1707 if (
1708 qApp->activePopupWidget() &&
1709 (WinQueryQueueStatus( HWND_DESKTOP ) & QS_MOUSEBUTTON)
1710 ) {
1711 // the user has clicked over the Qt window that is disabled
1712 // by some modal widget, therefore we close all popups. In
1713 // case some popup refuses to close, we give up after 1024
1714 // attempts (to avoid an infinite loop).
1715 int maxiter = 1024;
1716 QWidget *popup;
1717 while ( (popup=QApplication::activePopupWidget()) && maxiter-- )
1718 popup->close();
1719 }
1720#ifndef QT_NO_CURSOR
1721 else {
1722 QCursor *c = qt_grab_cursor();
1723 if ( !c )
1724 c = QApplication::overrideCursor();
1725 if ( c ) // application cursor defined
1726 WinSetPointer( HWND_DESKTOP, c->handle() );
1727 else
1728 WinSetPointer( HWND_DESKTOP, Qt::arrowCursor.handle() );
1729 }
1730#endif
1731 }
1732 break;
1733 }
1734
1735 case WM_ADJUSTWINDOWPOS: {
1736 SWP &swp = *(PSWP) mp1;
1737 if ( swp.fl & SWP_MAXIMIZE ) {
1738 QWExtra *x = widget->xtra();
1739 if ( x ) {
1740 result = TRUE;
1741 rc = QtOldFrameProc( hwnd, msg, mp1, mp2 );
1742 int maxw = QWIDGETSIZE_MAX, maxh = QWIDGETSIZE_MAX;
1743 QTLWExtra *top = widget->top();
1744 if ( x->maxw < QWIDGETSIZE_MAX )
1745 maxw = x->maxw + top->fleft + top->fright;
1746 if ( x->maxh < QWIDGETSIZE_MAX )
1747 maxh = x->maxh + top->ftop + top->fbottom;
1748 if ( maxw < QWIDGETSIZE_MAX ) swp.cx = maxw;
1749 if ( maxh < QWIDGETSIZE_MAX ) {
1750 swp.y = swp.y + swp.cy - maxh;
1751 swp.cy = maxh;
1752 }
1753 }
1754 }
1755 if ( (swp.fl & SWP_RESTORE) &&
1756 !(swp.fl & (SWP_MOVE | SWP_SIZE)) ) {
1757 QRect r = widget->top()->normalGeometry;
1758 if ( r.isValid() ) {
1759 // store normal geometry in window words
1760 USHORT x = r.x();
1761 USHORT y = r.y();
1762 USHORT w = r.width();
1763 USHORT h = r.height();
1764 // flip y coordinate
1765 y = QApplication::desktop()->height() - (y + h);
1766 WinSetWindowUShort( hwnd, QWS_XRESTORE, x );
1767 WinSetWindowUShort( hwnd, QWS_YRESTORE, y );
1768 WinSetWindowUShort( hwnd, QWS_CXRESTORE, w );
1769 WinSetWindowUShort( hwnd, QWS_CYRESTORE, h );
1770 widget->top()->normalGeometry.setWidth( 0 );
1771 }
1772 }
1773 if ( swp.fl & (SWP_ACTIVATE | SWP_ZORDER) ) {
1774 // get the modal widget that made this window blocked
1775 QWidget *m =
1776 (QWidget*) WinQueryWindowULong( widget->winId(), QWL_QTMODAL );
1777 if( m ) {
1778 if ( swp.fl & SWP_ACTIVATE ) {
1779 QWidget *a = qt_modal_stack->first();
1780 if ( !a->isActiveWindow() )
1781 a->setActiveWindow();
1782 swp.fl &= ~SWP_ACTIVATE;
1783 }
1784 if ( swp.fl & SWP_ZORDER ) {
1785 QWidget *mp = m->parentWidget();
1786 if ( mp ) {
1787 mp = mp->topLevelWidget();
1788 if ( !mp->isDesktop() && mp != widget )
1789 m = mp;
1790 }
1791 HWND hm = m->winFId();
1792 if ( swp.hwndInsertBehind != hm ) {
1793 swp.hwndInsertBehind = hm;
1794 }
1795 }
1796 }
1797 }
1798 break;
1799 }
1800
1801 case WM_QUERYTRACKINFO: {
1802 QWExtra *x = widget->xtra();
1803 if ( x ) {
1804 result = TRUE;
1805 rc = QtOldFrameProc( hwnd, msg, mp1, mp2 );
1806 PTRACKINFO pti = (PTRACKINFO) mp2;
1807 int minw = 0, minh = 0;
1808 int maxw = QWIDGETSIZE_MAX, maxh = QWIDGETSIZE_MAX;
1809 QTLWExtra *top = widget->top();
1810 if ( x->minw > 0 )
1811 minw = x->minw + top->fleft + top->fright;
1812 if ( x->minh > 0 )
1813 minh = x->minh + top->ftop + top->fbottom;
1814 if ( x->maxw < QWIDGETSIZE_MAX )
1815 maxw = x->maxw + top->fleft + top->fright;
1816 if ( x->maxh < QWIDGETSIZE_MAX )
1817 maxh = x->maxh + top->ftop + top->fbottom;
1818 // obey system recommended minimum size (to emulate Qt/Win32)
1819 pti->ptlMinTrackSize.x = QMAX( minw, pti->ptlMinTrackSize.x );
1820 pti->ptlMinTrackSize.y = QMAX( minh, pti->ptlMinTrackSize.y );
1821 pti->ptlMaxTrackSize.x = maxw;
1822 pti->ptlMaxTrackSize.y = maxh;
1823 }
1824 break;
1825 }
1826
1827 case WM_TRACKFRAME: {
1828 if ( QApplication::activePopupWidget() ) {
1829 // The user starts to size/move the frame window, therefore
1830 // we close all popups. In case some popup refuses to close,
1831 // we give up after 1024 attempts (to avoid an infinite loop).
1832 int maxiter = 1024;
1833 QWidget *popup;
1834 while ( (popup=QApplication::activePopupWidget()) && maxiter-- )
1835 popup->close();
1836 }
1837 break;
1838 }
1839
1840 case WM_WINDOWPOSCHANGED: {
1841 // We detect spontaneous min/max/restore events here instead of
1842 // WM_MINMAXFRAME, because WM_MINMAXFRAME is a pre-process message
1843 // (i.e. no actual changes have been made) We need actual changes
1844 // in order to update the frame strut and send WindowStateChange.
1845 result = TRUE;
1846 rc = QtOldFrameProc( hwnd, msg, mp1, mp2 );
1847 ULONG awp = LONGFROMMP( mp2 );
1848 bool window_state_change = FALSE;
1849 if ( awp & AWP_MAXIMIZED ) {
1850 window_state_change = TRUE;
1851 widget->setWState( Qt::WState_Maximized );
1852 widget->clearWState( Qt::WState_FullScreen );
1853 if ( widget->isMinimized() ) {
1854 widget->clearWState( Qt::WState_Minimized );
1855 widget->showChildren( TRUE );
1856 QShowEvent e;
1857 qt_sendSpontaneousEvent( widget, &e );
1858 }
1859 } else if ( awp & AWP_MINIMIZED ) {
1860 window_state_change = TRUE;
1861 widget->setWState( Qt::WState_Minimized );
1862 widget->clearWState( Qt::WState_Maximized );
1863 widget->clearWState( Qt::WState_FullScreen );
1864 if ( widget->isVisible() ) {
1865 QHideEvent e;
1866 qt_sendSpontaneousEvent( widget, &e );
1867 widget->hideChildren( TRUE );
1868 }
1869 } else if ( awp & AWP_RESTORED ) {
1870 window_state_change = TRUE;
1871 if ( widget->isMinimized() ) {
1872 widget->showChildren( TRUE );
1873 QShowEvent e;
1874 qt_sendSpontaneousEvent( widget, &e );
1875 }
1876 widget->clearWState( Qt::WState_Minimized );
1877 widget->clearWState( Qt::WState_Maximized );
1878 }
1879 if ( window_state_change ) {
1880 widget->updateFrameStrut();
1881 if ( !widget->top()->in_sendWindowState ) {
1882 // send WindowStateChange event if this message is NOT
1883 // originated from QWidget::setWindowState().
1884 QEvent e( QEvent::WindowStateChange );
1885 qt_sendSpontaneousEvent( widget, &e );
1886 }
1887 }
1888 break;
1889 }
1890
1891 default:
1892 break;
1893 }
1894
1895 if ( result )
1896 RETURN( rc );
1897
1898do_default:
1899 RETURN( QtOldFrameProc( hwnd, msg, mp1, mp2 ) );
1900}
1901
1902/*****************************************************************************
1903 Modal widgets; We have implemented our own modal widget mechanism
1904 to get total control.
1905 A modal widget without a parent becomes application-modal.
1906 A modal widget with a parent becomes modal to its parent and grandparents..
1907
1908//@@TODO (dmik): the above comment is not correct (outdated?): for example,
1909// in accordance with the current Qt logic, a modal widget with a parent
1910// becomes modal to its (grand)parents upto the first of them that has the
1911// WGroupLeader flag, not necessarily to all...
1912
1913 qt_enter_modal()
1914 Enters modal state
1915 Arguments:
1916 QWidget *widget A modal widget
1917
1918 qt_leave_modal()
1919 Leaves modal state for a widget
1920 Arguments:
1921 QWidget *widget A modal widget
1922 *****************************************************************************/
1923
1924Q_EXPORT bool qt_modal_state()
1925{
1926 return app_do_modal;
1927}
1928
1929// helper for qt_dispatchBlocked().
1930// sends block events to the given widget and its children.
1931void qt_sendBlocked( QObject *obj, QWidget *modal, QEvent *e, bool override )
1932{
1933 if ( obj == modal ) {
1934 // don't touch modal itself and its children
1935 return;
1936 }
1937 bool blocked = e->type() == QEvent::WindowBlocked;
1938
1939 if ( obj->isWidgetType() ) {
1940 QWidget *w = (QWidget*) obj;
1941 if ( w->isTopLevel() ) {
1942 if ( w->testWFlags( Qt::WGroupLeader ) && !override ) {
1943 // stop sending on group leaders
1944 return;
1945 }
1946 QWidget *blockedBy =
1947 (QWidget*) WinQueryWindowULong( w->winId(), QWL_QTMODAL );
1948 if ( blocked ) {
1949 // stop sending on alreay blocked widgets
1950 if ( blockedBy )
1951 return;
1952 } else {
1953 // stop sending on widgets blocked by another modal
1954 if ( blockedBy != modal )
1955 return;
1956 }
1957 WinSetWindowULong( w->winId(), QWL_QTMODAL,
1958 blocked ? (ULONG) modal : 0 );
1959 WinEnableWindow( w->winFId(), !blocked );
1960 }
1961 }
1962 QApplication::sendEvent( obj, e );
1963
1964 // now send blocked to children
1965 if ( obj->children() ) {
1966 QObjectListIt it( *obj->children() );
1967 QObject *o;
1968 while( ( o = it.current() ) != 0 ) {
1969 ++it;
1970 qt_sendBlocked( o, modal, e, FALSE );
1971 }
1972 }
1973}
1974
1975// sends blocked/unblocked events to top-level widgets depending on the
1976// modal widget given and the WGroupLeader flag presence.
1977static void qt_dispatchBlocked( QWidget *modal, bool blocked )
1978{
1979 // we process those top-level windows that must be blocked
1980 // by the given modal -- this should correlate with the
1981 // qt_tryModalHelper() logic that is widget-centric (i.e. a try
1982 // to block a particular widget given the current set of
1983 // modals) rather than modal-centric (a try to block the current set
1984 // of widgets given a particular modal); currently it blocks events
1985 // for a top-level widget if the widget doesn't have (a parent with
1986 // with) the WGroupLeader flag or it has but (this parent) has a child
1987 // among the current set of modals. So, the modal-centric logic is
1988 // to block any top-level widget unless it has (a parent with) the
1989 // WGroupLeader flag and (this parent) is not (a child of) the modal's
1990 // group leader.
1991
1992 QEvent e( blocked ? QEvent::WindowBlocked : QEvent::WindowUnblocked );
1993
1994 // find the modal's group leader
1995 QWidget *mgl = modal->parentWidget();
1996 while ( mgl && !mgl->testWFlags( Qt::WGroupLeader ) )
1997 mgl = mgl->parentWidget();
1998 if ( mgl ) {
1999 mgl = mgl->topLevelWidget();
2000 if ( mgl->isDesktop() )
2001 mgl = 0;
2002 }
2003
2004 QWidgetList *list = QApplication::topLevelWidgets();
2005 for( QWidget *w = list->first(); w; w = list->next() ) {
2006 if (
2007 !w->isDesktop() && !w->isPopup() && !w->isHidden() &&
2008 !w->testWFlags( Qt::WGroupLeader ) &&
2009 (!w->parentWidget() || w->parentWidget()->isDesktop())
2010 ) {
2011 qt_sendBlocked( w, modal, &e, FALSE );
2012 }
2013 }
2014
2015 if ( mgl ) {
2016 // send blocked to modal's group leader
2017 qt_sendBlocked( mgl, modal, &e, TRUE );
2018 }
2019 // qt_tryModalHelper() also assumes that the toppest modal widget blocks
2020 // other modals, regardless of WGroupLeader flags in parents. do the same.
2021 // note: the given modal is not yet at the stack here.
2022 if ( qt_modal_stack ) {
2023 QWidget *m = qt_modal_stack->first();
2024 while ( m ) {
2025 qt_sendBlocked( m, modal, &e, TRUE );
2026 m = qt_modal_stack->next();
2027 }
2028 }
2029}
2030
2031Q_EXPORT void qt_enter_modal( QWidget *widget )
2032{
2033 if ( !qt_modal_stack ) { // create modal stack
2034 qt_modal_stack = new QWidgetList;
2035 Q_CHECK_PTR( qt_modal_stack );
2036 }
2037
2038 if ( qt_modal_stack->containsRef( widget ) )
2039 return; // already modal
2040
2041//@@TODO (dmik): Qt/Win32 sends WindowBlocked/WindowUnblocked events only
2042// to the direct parent of the modal widget. Why? We use qt_dispatchBlocked()
2043// to send them to all windows that do not get input when the given widget
2044// is modal; also we disable/enable that windows there, which is essential
2045// for modality support in Qt/OS2 (code in QtOldFrameProc() and qt_try_modal()
2046// functionality depend on it).
2047//
2048// if (widget->parentWidget()) {
2049// QEvent e(QEvent::WindowBlocked);
2050// QApplication::sendEvent(widget->parentWidget(), &e);
2051// WinEnableWindow( widget->parentWidget()->winFId(), FALSE );
2052// }
2053 qt_dispatchBlocked( widget, TRUE );
2054
2055 releaseAutoCapture();
2056 qt_dispatchEnterLeave( 0, QWidget::find((WId)curWin));
2057 qt_modal_stack->insert( 0, widget );
2058 app_do_modal = TRUE;
2059 curWin = 0;
2060 qt_button_down = 0;
2061 ignoreNextMouseReleaseEvent = FALSE;
2062}
2063
2064
2065Q_EXPORT void qt_leave_modal( QWidget *widget )
2066{
2067 if ( qt_modal_stack && qt_modal_stack->removeRef(widget) ) {
2068 if ( qt_modal_stack->isEmpty() ) {
2069 delete qt_modal_stack;
2070 qt_modal_stack = 0;
2071 QPoint p( QCursor::pos() );
2072 app_do_modal = FALSE; // necessary, we may get recursively into qt_try_modal below
2073 QWidget* w = QApplication::widgetAt( p.x(), p.y(), TRUE );
2074 qt_dispatchEnterLeave( w, QWidget::find( curWin ) ); // send synthetic enter event
2075 curWin = w? w->winId() : 0;
2076 }
2077 ignoreNextMouseReleaseEvent = TRUE;
2078
2079 qt_dispatchBlocked( widget, FALSE );
2080 }
2081 app_do_modal = qt_modal_stack != 0;
2082
2083//@@TODO (dmik): see the comments inside qt_enter_modal()
2084//
2085// if (widget->parentWidget()) {
2086// WinEnableWindow( widget->parentWidget()->winFId(), TRUE );
2087// QEvent e(QEvent::WindowUnblocked);
2088// QApplication::sendEvent(widget->parentWidget(), &e);
2089// }
2090}
2091
2092static bool qt_blocked_modal( QWidget *widget )
2093{
2094 if ( !app_do_modal )
2095 return FALSE;
2096 if ( qApp->activePopupWidget() )
2097 return FALSE;
2098 if ( widget->testWFlags(Qt::WStyle_Tool) ) // allow tool windows
2099 return FALSE;
2100
2101 QWidget *modal=0, *top=qt_modal_stack->getFirst();
2102
2103 widget = widget->topLevelWidget();
2104 if ( widget->testWFlags(Qt::WShowModal) ) // widget is modal
2105 modal = widget;
2106 if ( !top || modal == top ) // don't block event
2107 return FALSE;
2108 return TRUE;
2109}
2110
2111static bool qt_try_modal( QWidget *widget, QMSG *qmsg, int &ret )
2112{
2113 QWidget * top = 0;
2114
2115 if ( qt_tryModalHelper( widget, &top ) )
2116 return TRUE;
2117
2118 bool block_event = FALSE;
2119 ULONG type = qmsg->msg;
2120
2121 if ( type == WM_CLOSE ) {
2122 block_event = TRUE;
2123 }
2124
2125 return !block_event;
2126}
2127
2128
2129/*****************************************************************************
2130 Popup widget mechanism
2131
2132 openPopup()
2133 Adds a widget to the list of popup widgets
2134 Arguments:
2135 QWidget *widget The popup widget to be added
2136
2137 closePopup()
2138 Removes a widget from the list of popup widgets
2139 Arguments:
2140 QWidget *widget The popup widget to be removed
2141 *****************************************************************************/
2142
2143void QApplication::openPopup( QWidget *popup )
2144{
2145 if ( !popupWidgets ) { // create list
2146 popupWidgets = new QWidgetList;
2147 Q_CHECK_PTR( popupWidgets );
2148 }
2149 popupWidgets->append( popup ); // add to end of list
2150 if ( !popup->isEnabled() )
2151 return;
2152
2153 if ( popupWidgets->count() == 1 && !qt_nograb() )
2154 setAutoCapture( popup->winId() ); // grab mouse/keyboard
2155 // Popups are not focus-handled by the window system (the first
2156 // popup grabbed the keyboard), so we have to do that manually: A
2157 // new popup gets the focus
2158 QFocusEvent::setReason( QFocusEvent::Popup );
2159 if ( popup->focusWidget())
2160 popup->focusWidget()->setFocus();
2161 else
2162 popup->setFocus();
2163 QFocusEvent::resetReason();
2164}
2165
2166void QApplication::closePopup( QWidget *popup )
2167{
2168 if ( !popupWidgets )
2169 return;
2170 popupWidgets->removeRef( popup );
2171 POINTL curPos;
2172 WinQueryPointerPos( HWND_DESKTOP, &curPos );
2173 // flip y coordinate
2174 curPos.y = desktop()->height() - (curPos.y + 1);
2175 replayPopupMouseEvent = !popup->geometry().contains( QPoint(curPos.x, curPos.y) );
2176 if ( popupWidgets->count() == 0 ) { // this was the last popup
2177 popupCloseDownMode = TRUE; // control mouse events
2178 delete popupWidgets;
2179 popupWidgets = 0;
2180 if ( !popup->isEnabled() )
2181 return;
2182 if ( !qt_nograb() ) // grabbing not disabled
2183 releaseAutoCapture();
2184 if ( active_window ) {
2185 QFocusEvent::setReason( QFocusEvent::Popup );
2186 if ( active_window->focusWidget() )
2187 active_window->focusWidget()->setFocus();
2188 else
2189 active_window->setFocus();
2190 QFocusEvent::resetReason();
2191 }
2192 } else {
2193 // Popups are not focus-handled by the window system (the
2194 // first popup grabbed the keyboard), so we have to do that
2195 // manually: A popup was closed, so the previous popup gets
2196 // the focus.
2197 QFocusEvent::setReason( QFocusEvent::Popup );
2198 QWidget* aw = popupWidgets->getLast();
2199 if ( popupWidgets->count() == 1 )
2200 setAutoCapture( aw->winId() );
2201 if (aw->focusWidget())
2202 aw->focusWidget()->setFocus();
2203 else
2204 aw->setFocus();
2205 QFocusEvent::resetReason();
2206 }
2207}
2208
2209
2210
2211/*****************************************************************************
2212 Event translation; translates OS/2 PM events to Qt events
2213 *****************************************************************************/
2214
2215// State holder for LWIN/RWIN and ALTGr keys
2216// (ALTGr is also necessary since OS/2 doesn't report ALTGr as KC_ALT)
2217static int qt_extraKeyState = 0;
2218
2219static int mouseButtonState()
2220{
2221 int state = 0;
2222
2223 if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON1 ) & 0x8000 )
2224 state |= Qt::LeftButton;
2225 if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON2 ) & 0x8000 )
2226 state |= Qt::RightButton;
2227 if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON3 ) & 0x8000 )
2228 state |= Qt::MidButton;
2229
2230 return state;
2231}
2232
2233//
2234// Auto-capturing for mouse press and mouse release
2235//
2236
2237static void setAutoCapture( HWND h )
2238{
2239 if ( autoCaptureWnd )
2240 releaseAutoCapture();
2241 autoCaptureWnd = h;
2242
2243 if ( !mouseButtonState() ) {
2244 // all buttons released, we don't actually capture the mouse
2245 // (see QWidget::translateMouseEvent())
2246 autoCaptureReleased = TRUE;
2247 } else {
2248 autoCaptureReleased = FALSE;
2249 WinSetCapture( HWND_DESKTOP, h );
2250 }
2251}
2252
2253static void releaseAutoCapture()
2254{
2255 if ( autoCaptureWnd ) {
2256 if ( !autoCaptureReleased ) {
2257 WinSetCapture( HWND_DESKTOP, 0 );
2258 autoCaptureReleased = TRUE;
2259 }
2260 autoCaptureWnd = 0;
2261 }
2262}
2263
2264
2265//
2266// Mouse event translation
2267//
2268
2269static ushort mouseTbl[] = {
2270 WM_MOUSEMOVE, QEvent::MouseMove, 0,
2271 WM_BUTTON1DOWN, QEvent::MouseButtonPress, Qt::LeftButton,
2272 WM_BUTTON1UP, QEvent::MouseButtonRelease, Qt::LeftButton,
2273 WM_BUTTON1DBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
2274 WM_BUTTON2DOWN, QEvent::MouseButtonPress, Qt::RightButton,
2275 WM_BUTTON2UP, QEvent::MouseButtonRelease, Qt::RightButton,
2276 WM_BUTTON2DBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
2277 WM_BUTTON3DOWN, QEvent::MouseButtonPress, Qt::MidButton,
2278 WM_BUTTON3UP, QEvent::MouseButtonRelease, Qt::MidButton,
2279 WM_BUTTON3DBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
2280//@@TODO (dmik): later (extra buttons)
2281// WM_XBUTTONDOWN, QEvent::MouseButtonPress, Qt::MidButton*2, //### Qt::XButton1/2
2282// WM_XBUTTONUP, QEvent::MouseButtonRelease, Qt::MidButton*2,
2283// WM_XBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton*2,
2284 WM_CONTEXTMENU, QEvent::ContextMenu, 0,
2285 0, 0, 0
2286};
2287
2288static int translateButtonState( USHORT s, int type, int button )
2289{
2290 int bst = mouseButtonState();
2291
2292 if ( type == QEvent::ContextMenu ) {
2293 if ( WinGetKeyState( HWND_DESKTOP, VK_SHIFT ) & 0x8000 )
2294 bst |= Qt::ShiftButton;
2295 if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 )
2296 bst |= Qt::AltButton;
2297 if ( WinGetKeyState( HWND_DESKTOP, VK_CTRL ) & 0x8000 )
2298 bst |= Qt::ControlButton;
2299 } else {
2300 if ( s & KC_SHIFT )
2301 bst |= Qt::ShiftButton;
2302 if ( (s & KC_ALT) )
2303 bst |= Qt::AltButton;
2304 if ( s & KC_CTRL )
2305 bst |= Qt::ControlButton;
2306 }
2307 if ( (qt_extraKeyState & Qt::AltButton) )
2308 bst |= Qt::AltButton;
2309 if ( qt_extraKeyState & Qt::MetaButton )
2310 bst |= Qt::MetaButton;
2311
2312 // Translate from OS/2-style "state after event"
2313 // to X-style "state before event"
2314 if ( type == QEvent::MouseButtonPress ||
2315 type == QEvent::MouseButtonDblClick )
2316 bst &= ~button;
2317 else if ( type == QEvent::MouseButtonRelease )
2318 bst |= button;
2319
2320 return bst;
2321}
2322
2323/*! \internal
2324 In DnD, the mouse release event never appears, so the
2325 mouse button state machine must be manually reset
2326*/
2327void qt_pmMouseButtonUp()
2328{
2329 // release any stored mouse capture
2330 qt_button_down = 0;
2331 autoCaptureReleased = TRUE;
2332 releaseAutoCapture();
2333}
2334
2335bool QETWidget::translateMouseEvent( const QMSG &qmsg )
2336{
2337#if 0
2338 static const char *msgNames[] = { // 11 items
2339 "WM_MOUSEMOVE",
2340 "WM_BUTTON1DOWN", "WM_BUTTON1UP", "WM_BUTTON1DBLCLK",
2341 "WM_BUTTON2DOWN", "WM_BUTTON2UP", "WM_BUTTON2DBLCLK",
2342 "WM_BUTTON3DOWN", "WM_BUTTON3UP", "WM_BUTTON3DBLCLK",
2343 "WM_???"
2344 };
2345 int msgIdx = qmsg.msg - WM_MOUSEMOVE;
2346 if (msgIdx < 0 || msgIdx > 9)
2347 msgIdx = 10;
2348 qDebug( "%s (%04lX): [%08lX/%p:%s/%s] %04hd,%04hd hit=%04hX fl=%04hX",
2349 msgNames[msgIdx], qmsg.msg, qmsg.hwnd, this, name(), className(),
2350 SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1),
2351 SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
2352#endif
2353
2354 static QPoint pos; // window pos (y flipped)
2355 static POINTL gpos = { -1, -1 }; // global pos (y flipped)
2356 QEvent::Type type; // event parameters
2357 int button;
2358 int state;
2359 int i;
2360
2361 // candidate for a double click event
2362 static HWND dblClickCandidateWin = 0;
2363
2364 if ( sm_blockUserInput ) //block user interaction during session management
2365 return TRUE;
2366
2367 // Compress mouse move events
2368 if ( qmsg.msg == WM_MOUSEMOVE ) {
2369 QMSG mouseMsg;
2370 mouseMsg.msg = WM_NULL;
2371 while (
2372 WinPeekMsg( 0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
2373 WM_MOUSEMOVE, PM_NOREMOVE )
2374 ) {
2375 if ( mouseMsg.mp2 != qmsg.mp2 )
2376 break; // leave the message in the queue because
2377 // the key state has changed
2378 // Remove the mouse move message
2379 WinPeekMsg( 0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
2380 WM_MOUSEMOVE, PM_REMOVE );
2381 }
2382 // Update the passed in QMSG structure with the
2383 // most recent one.
2384 if ( mouseMsg.msg != WM_NULL ) {
2385 PQMSG pqmsg = (PQMSG)&qmsg;
2386 pqmsg->mp1 = mouseMsg.mp1;
2387 pqmsg->mp2 = mouseMsg.mp2;
2388 pqmsg->time = mouseMsg.time;
2389 pqmsg->ptl.x = (short)SHORT1FROMMP(mouseMsg.mp1);
2390 pqmsg->ptl.y = (short)SHORT2FROMMP(mouseMsg.mp1);
2391 WinMapWindowPoints( pqmsg->hwnd, HWND_DESKTOP, &pqmsg->ptl, 1 );
2392 // flip y coordinate
2393 pqmsg->ptl.y = QApplication::desktop()->height() - (pqmsg->ptl.y + 1);
2394 }
2395 }
2396
2397 for ( i = 0; mouseTbl[i] && (ULONG)mouseTbl[i] != qmsg.msg; i += 3 )
2398 ;
2399 if ( !mouseTbl[i] )
2400 return FALSE;
2401
2402 type = (QEvent::Type)mouseTbl[++i]; // event type
2403 button = mouseTbl[++i]; // which button
2404/// @todo (dmik) later (extra buttons)
2405// if ( button > Qt::MidButton ) {
2406// switch( GET_XBUTTON_WPARAM( msg.wParam ) ) {
2407// case XBUTTON1:
2408// button = Qt::MidButton*2; //### XButton1;
2409// break;
2410// case XBUTTON2:
2411// button = Qt::MidButton*4; //### XButton2;
2412// break;
2413// }
2414// }
2415 state = translateButtonState( SHORT2FROMMP(qmsg.mp2), type, button ); // button state
2416
2417 // It seems, that PM remembers only the WM_BUTTONxDOWN message (instead of
2418 // the WM_BUTTONxDOWN + WM_BUTTONxUP pair) to detect whether the next button
2419 // press should be converted to WM_BUTTONxDBLCLK or not. As a result, the
2420 // window gets WM_BUTTONxDBLCLK even if it didn't receive the preceeding
2421 // WM_BUTTONxUP (this happens if we issue WinSetCapture() on the first
2422 // WM_BUTTONxDOWN), which is obviously wrong and makes problems for QWorkspace
2423 // and QTitleBar system menu handlers that don't expect a double click after
2424 // they opened a popup menu. dblClickCandidateWin is reset to 0 (see a ***
2425 // remmark below) when WinSetCapture is issued that directs messages
2426 // to a window other than one received the first WM_BUTTONxDOWN,
2427 // so we can fix it here. Note that if there is more than one popup window,
2428 // WinSetCapture is issued only for the first of them, so this code doesn't
2429 // prevent MouseButtonDblClick from being delivered to a popup when another
2430 // popup gets closed on the first WM_BUTTONxDOWN (Qt/Win32 behaves in the
2431 // same way, so it's left for compatibility).
2432 if ( type == QEvent::MouseButtonPress ) {
2433 dblClickCandidateWin = qmsg.hwnd;
2434 } else if ( type == QEvent::MouseButtonDblClick ) {
2435 if ( dblClickCandidateWin != qmsg.hwnd )
2436 type = QEvent::MouseButtonPress;
2437 dblClickCandidateWin = 0;
2438 }
2439
2440 if ( type == QEvent::ContextMenu ) {
2441 QPoint g = QPoint( qmsg.ptl.x, qmsg.ptl.y );
2442 QContextMenuEvent e( QContextMenuEvent::Mouse, mapFromGlobal( g ), g, state );
2443 QApplication::sendSpontaneousEvent( this, &e );
2444 return TRUE;
2445 }
2446
2447 if ( type == QEvent::MouseMove ) {
2448 if ( !(state & MouseButtonMask) )
2449 qt_button_down = 0;
2450#ifndef QT_NO_CURSOR
2451 QCursor *c = qt_grab_cursor();
2452 if ( !c )
2453 c = QApplication::overrideCursor();
2454 if ( c ) // application cursor defined
2455 WinSetPointer( HWND_DESKTOP, c->handle() );
2456 else if ( isEnabled() ) // use widget cursor if widget is enabled
2457 WinSetPointer( HWND_DESKTOP, cursor().handle() );
2458 else {
2459 QWidget *parent = parentWidget();
2460 while ( parent && !parent->isEnabled() )
2461 parent = parent->parentWidget();
2462 if ( parent )
2463 WinSetPointer( HWND_DESKTOP, parent->cursor().handle() );
2464 }
2465#else
2466 // pass the msg to the default proc to let it change the pointer shape
2467 WinDefWindowProc( qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2 );
2468#endif
2469 if ( curWin != winId() ) { // new current window
2470/// @todo (dmik)
2471// add CS_HITTEST to our window classes and handle WM_HITTEST,
2472// otherwise disabled windows will not get mouse events?
2473 qt_dispatchEnterLeave( this, QWidget::find(curWin) );
2474 curWin = winId();
2475 }
2476
2477 // *** PM posts a dummy WM_MOUSEMOVE message (with the same, uncahnged
2478 // pointer coordinates) after every WinSetCapture that actually changes
2479 // the capture target. I.e., if the argument of WinSetCapture is
2480 // NULLHANDLE, a window under the mouse pointer gets this message,
2481 // otherwise the specified window gets it unless it is already under the
2482 // pointer. We use this info to check whether the window can be a double
2483 // click candidate (see above).
2484 if ( qmsg.ptl.x == gpos.x && qmsg.ptl.y == gpos.y ) {
2485 if ( dblClickCandidateWin != qmsg.hwnd )
2486 dblClickCandidateWin = 0;
2487 return TRUE;
2488 }
2489
2490 gpos = qmsg.ptl;
2491
2492 if ( state == 0 && autoCaptureWnd == 0 && !hasMouseTracking() &&
2493 !QApplication::hasGlobalMouseTracking() )
2494 return TRUE; // no button
2495
2496 pos = mapFromGlobal( QPoint(gpos.x, gpos.y) );
2497 } else {
2498 if ( type == QEvent::MouseButtonPress && !isActiveWindow() )
2499 setActiveWindow();
2500
2501 gpos = qmsg.ptl;
2502 pos = mapFromGlobal( QPoint(gpos.x, gpos.y) );
2503
2504 if ( type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick ) { // mouse button pressed
2505 // Magic for masked widgets
2506 qt_button_down = findChildWidget( this, pos );
2507 if ( !qt_button_down || !qt_button_down->testWFlags(WMouseNoMask) )
2508 qt_button_down = this;
2509 }
2510 }
2511
2512 // detect special button states
2513 enum { Other, SinglePressed, AllReleased } btnState = Other;
2514 int bs = state & MouseButtonMask;
2515 if ( (type == QEvent::MouseButtonPress ||
2516 type == QEvent::MouseButtonDblClick) && bs == 0
2517 ) {
2518 btnState = SinglePressed;
2519 } else if ( type == QEvent::MouseButtonRelease && bs == button ) {
2520 btnState = AllReleased;
2521 }
2522
2523 if ( qApp->inPopupMode() ) { // in popup mode
2524 if ( !autoCaptureReleased && btnState == AllReleased ) {
2525 // in order to give non-Qt windows the opportunity to see mouse
2526 // messages while our popups are active we need to release the
2527 // mouse capture which is absolute in OS/2. we do it directly
2528 // (not through releaseAutoCapture()) in order to keep
2529 // autoCaptureWnd nonzero to keep forwarding mouse move events
2530 // (actually sent to one of Qt widgets) to the active popup.
2531 autoCaptureReleased = TRUE;
2532 WinSetCapture( HWND_DESKTOP, 0 );
2533 } else if ( autoCaptureReleased && btnState == SinglePressed ) {
2534 // set the mouse capture back if a button is pressed.
2535 if ( autoCaptureWnd ) {
2536 autoCaptureReleased = FALSE;
2537 WinSetCapture( HWND_DESKTOP, autoCaptureWnd );
2538 }
2539 }
2540
2541 replayPopupMouseEvent = FALSE;
2542 QWidget* activePopupWidget = qApp->activePopupWidget();
2543 QWidget *popup = activePopupWidget;
2544
2545 if ( popup != this ) {
2546 if ( testWFlags(WType_Popup) && rect().contains(pos) )
2547 popup = this;
2548 else // send to last popup
2549 pos = popup->mapFromGlobal( QPoint(gpos.x, gpos.y) );
2550 }
2551 QWidget *popupChild = findChildWidget( popup, pos );
2552 bool releaseAfter = FALSE;
2553 switch ( type ) {
2554 case QEvent::MouseButtonPress:
2555 case QEvent::MouseButtonDblClick:
2556 popupButtonFocus = popupChild;
2557 break;
2558 case QEvent::MouseButtonRelease:
2559 releaseAfter = TRUE;
2560 break;
2561 default:
2562 break; // nothing for mouse move
2563 }
2564
2565 if ( popupButtonFocus ) {
2566 QMouseEvent e( type,
2567 popupButtonFocus->mapFromGlobal(QPoint(gpos.x,gpos.y)),
2568 QPoint(gpos.x,gpos.y), button, state );
2569 QApplication::sendSpontaneousEvent( popupButtonFocus, &e );
2570 if ( releaseAfter ) {
2571 popupButtonFocus = 0;
2572 }
2573 } else if ( popupChild ) {
2574 QMouseEvent e( type,
2575 popupChild->mapFromGlobal(QPoint(gpos.x,gpos.y)),
2576 QPoint(gpos.x,gpos.y), button, state );
2577 QApplication::sendSpontaneousEvent( popupChild, &e );
2578 } else {
2579 QMouseEvent e( type, pos, QPoint(gpos.x,gpos.y), button, state );
2580 QApplication::sendSpontaneousEvent( popup, &e );
2581 }
2582
2583 if ( releaseAfter )
2584 qt_button_down = 0;
2585
2586 if ( type == QEvent::MouseButtonPress
2587 && qApp->activePopupWidget() != activePopupWidget
2588 && replayPopupMouseEvent ) {
2589 // the popup dissappeared. Replay the event
2590 QWidget* w = QApplication::widgetAt( gpos.x, gpos.y, TRUE );
2591 if ( w && !qt_blocked_modal( w ) ) {
2592 QPoint wpos = w->mapFromGlobal(QPoint(gpos.x, gpos.y));
2593 // flip y coordinate
2594 wpos.ry() = w->height() - (wpos.y() + 1);
2595 // Note: it's important to post this message rather than send:
2596 // QPushButton::popupPressed() depends on this so that
2597 // popup->exec() must return before this message is delivered
2598 // as QWidget::keyPressEvent().
2599 WinPostMsg( w->winId(), qmsg.msg,
2600 MPFROM2SHORT( wpos.x(), wpos.y() ), qmsg.mp2 );
2601 }
2602 }
2603 } else { // not popup mode
2604 if ( btnState == SinglePressed && QWidget::mouseGrabber() == 0 )
2605 setAutoCapture( winId() );
2606 else if ( btnState == AllReleased && QWidget::mouseGrabber() == 0 )
2607 releaseAutoCapture();
2608
2609 QWidget *widget = this;
2610 QWidget *w = QWidget::mouseGrabber();
2611 if ( !w )
2612 w = qt_button_down;
2613 if ( w && w != this ) {
2614 widget = w;
2615 pos = w->mapFromGlobal(QPoint(gpos.x, gpos.y));
2616 }
2617
2618 if ( type == QEvent::MouseButtonRelease &&
2619 (state & (~button) & ( MouseButtonMask )) == 0 ) {
2620 qt_button_down = 0;
2621 }
2622
2623 QMouseEvent e( type, pos, QPoint(gpos.x,gpos.y), button, state );
2624 QApplication::sendSpontaneousEvent( widget, &e );
2625
2626 if ( type != QEvent::MouseMove )
2627 pos.rx() = pos.ry() = -9999; // init for move compression
2628 }
2629 return TRUE;
2630}
2631
2632
2633//
2634// Keyboard event translation
2635//
2636
2637static const ushort KeyTbl[] = { // keyboard mapping table
2638 VK_ESC, Qt::Key_Escape, // misc keys
2639 VK_TAB, Qt::Key_Tab,
2640 VK_BACKTAB, Qt::Key_Backtab,
2641 VK_BACKSPACE, Qt::Key_Backspace,
2642 VK_ENTER, Qt::Key_Enter,
2643 VK_NEWLINE, Qt::Key_Return,
2644 VK_INSERT, Qt::Key_Insert,
2645 VK_DELETE, Qt::Key_Delete,
2646 VK_CLEAR, Qt::Key_Clear,
2647 VK_PAUSE, Qt::Key_Pause,
2648 VK_PRINTSCRN, Qt::Key_Print,
2649 VK_SPACE, Qt::Key_Space,
2650 VK_HOME, Qt::Key_Home, // cursor movement
2651 VK_END, Qt::Key_End,
2652 VK_LEFT, Qt::Key_Left,
2653 VK_UP, Qt::Key_Up,
2654 VK_RIGHT, Qt::Key_Right,
2655 VK_DOWN, Qt::Key_Down,
2656 VK_PAGEUP, Qt::Key_Prior,
2657 VK_PAGEDOWN, Qt::Key_Next,
2658 VK_SHIFT, Qt::Key_Shift, // modifiers
2659 VK_CTRL, Qt::Key_Control,
2660 VK_ALT, Qt::Key_Alt,
2661 VK_CAPSLOCK, Qt::Key_CapsLock,
2662 VK_NUMLOCK, Qt::Key_NumLock,
2663 VK_SCRLLOCK, Qt::Key_ScrollLock,
2664 0, 0
2665};
2666
2667// when the compatibility mode is FALSE Qt/OS2 uses the following rule
2668// to calculate QKeyEvent::key() codes when an alpha-numeric key is
2669// pressed: key code is the ASCII (Latin 1) character code of that key as if
2670// there were no any keyboard modifiers (CTRL, SHIFT, ALT) pressed, with the
2671// exception that alpha characters are uppercased.
2672// when the compatibility mode is TRUE Qt/OS2 behaves mostly like Qt/Win32.
2673Q_EXPORT bool qt_kbd_compatibility = TRUE;
2674
2675/// @todo (dmik) currentlly, qt_kbd_compatibility is TRUE because
2676// qt_scan2Ascii function below is not well implemented yet (in particular,
2677// it uses the 850 code page that may not be available on some systems...).
2678// Once we find a way to translate scans to US ASCII regardless of the current
2679// code page and/or NLS state (keyboard layout), qt_kbd_compatibility may be
2680// set to FALSE. This, in particular, will enable more correct handling of
2681// Alt+letter combinations when the keyboard is in the NLS state:
2682// QKeyEvent::key() will return a non-null Qt::Key_XXX code corresponding to
2683// the ASCII code of a pressed key, which in turn will let Qt process latin
2684// Alt+letter shortcuts in the NLS keyboard mode together with Alt+NLS_letter
2685// shortcuts (nice feature imho). Note that Alt+NLS_letter shortcuts are
2686// correctly processed in any case.
2687
2688// cache table to store Qt::Key_... values for 256 hardware scancodes
2689// (even byte is for non-shifted keys, odd byte is for shifted ones).
2690// used to decrease the number of calls to KbdXlate.
2691static uchar ScanTbl[512] = { 0xFF };
2692
2693static uchar qt_scan2Ascii( uchar scan, bool shift )
2694{
2695 uchar ascii = 0;
2696 HFILE kbd;
2697 ULONG dummy;
2698 DosOpen( "KBD$", &kbd, &dummy, 0,
2699 FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
2700 OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL );
2701 // parameter packet
2702 struct CPID {
2703 USHORT idCodePage;
2704 USHORT reserved;
2705 } cpid = { 850, 0 };
2706 ULONG szCpid = sizeof(CPID);
2707 // data packet
2708 KBDTRANS kt;
2709 ULONG szKt = sizeof(KBDTRANS);
2710 // reset all kbd states and modifiers
2711 memset( &kt, 0, szKt );
2712 // reflect Shift state to distinguish between [ and { etc.
2713 if ( qt_kbd_compatibility && shift )
2714 kt.fsState = KBDSTF_RIGHTSHIFT;
2715 kt.chScan = scan;
2716 DosDevIOCtl( kbd, IOCTL_KEYBOARD, KBD_XLATESCAN,
2717 &cpid, szCpid, &szCpid, &kt, szKt, &szKt );
2718 // store in cache
2719 uint idx = scan << 1;
2720 if ( qt_kbd_compatibility && shift )
2721 idx++;
2722 ascii = ScanTbl[idx] = toupper( kt.chChar );
2723 DosClose( kbd );
2724 return ascii;
2725}
2726
2727// translates WM_CHAR to Qt::Key_..., ascii, state and text
2728static void translateKeyCode( CHRMSG &chm, int &code, int &ascii, int &state,
2729 QString &text )
2730{
2731 if ( chm.fs & KC_SHIFT )
2732 state |= Qt::ShiftButton;
2733 if ( chm.fs & KC_CTRL )
2734 state |= Qt::ControlButton;
2735 if ( chm.fs & KC_ALT )
2736 state |= Qt::AltButton;
2737 if ( qt_extraKeyState & Qt::MetaButton )
2738 state |= Qt::MetaButton;
2739
2740 unsigned char ch = chm.chr;
2741
2742 if ( chm.fs & KC_VIRTUALKEY ) {
2743 if ( !chm.vkey ) {
2744 // The only known situation when KC_VIRTUALKEY is present but
2745 // vkey is zero is when Alt+Shift is pressed to switch the
2746 // keyboard layout state from latin to national and back.
2747 // It seems that this way the system informs applications about
2748 // layout changes: chm.chr is 0xF1 when the user switches
2749 // to the national layout (i.e. presses Alt + Left Shift)
2750 // and it is 0xF0 when he switches back (presses Alt + Right Shift).
2751 // We assume this and restore fs, vkey, scancode and chr accordingly.
2752 if ( chm.chr == 0xF0 || chm.chr == 0xF1 ) {
2753 chm.fs |= KC_ALT | KC_SHIFT;
2754 chm.vkey = VK_SHIFT;
2755 chm.scancode = chm.chr == 0xF1 ? 0x2A : 0x36;
2756 chm.chr = ch = 0;
2757 state |= Qt::AltButton | Qt::ShiftButton;
2758 // code will be assigned by the normal procedure below
2759 }
2760 }
2761 if ( chm.vkey >= VK_F1 && chm.vkey <= VK_F24 ) {
2762 // function keys
2763 code = Qt::Key_F1 + (chm.vkey - VK_F1);
2764 } else if ( chm.vkey == VK_ALTGRAF ) {
2765 code = Qt::Key_Alt;
2766 if ( !(chm.fs & KC_KEYUP) )
2767 qt_extraKeyState |= Qt::AltButton;
2768 else
2769 qt_extraKeyState &= ~Qt::AltButton;
2770 } else {
2771 // any other keys
2772 int i = 0;
2773 while ( KeyTbl[i] ) {
2774 if ( chm.vkey == (int)KeyTbl[i] ) {
2775 code = KeyTbl[i+1];
2776 break;
2777 }
2778 i += 2;
2779 }
2780 }
2781 } else {
2782 if ( qt_kbd_compatibility && ch && ch < 0x80 ) {
2783 code = toupper( ch );
2784 } else if ( !qt_kbd_compatibility && (chm.fs & KC_CHAR) && isalpha( ch ) ) {
2785 code = toupper( ch );
2786 } else {
2787 // detect some special keys that have a pseudo char code
2788 // in the high byte of chm.chr (probably this is less
2789 // device-dependent than scancode)
2790 switch ( chm.chr ) {
2791 case 0xEC00: // LWIN
2792 case 0xED00: // RWIN
2793 code = Qt::Key_Meta;
2794 if ( !(chm.fs & KC_KEYUP) )
2795 qt_extraKeyState |= Qt::MetaButton;
2796 else
2797 qt_extraKeyState &= ~Qt::MetaButton;
2798 break;
2799 case 0xEE00: // WINAPP (menu with arrow)
2800 code = Qt::Key_Menu;
2801 break;
2802 case 0x5600: // additional '\' (0x56 is actually its scancode)
2803 ch = state & Qt::ShiftButton ? '|' : '\\';
2804 if ( qt_kbd_compatibility ) code = ch;
2805 else code = '\\';
2806 break;
2807 default:
2808 // break if qt_kbd_compatibility = TRUE to avoid using
2809 // qt_scan2Ascii(), see comments to qt_kbd_compatibility
2810 if ( qt_kbd_compatibility ) break;
2811 // deduce Qt::Key... from scancode
2812 if ( ScanTbl[0] == 0xFF )
2813 memset( &ScanTbl, 0, sizeof(ScanTbl) );
2814 uint idx = chm.scancode << 1;
2815 if ( qt_kbd_compatibility && (state & Qt::ShiftButton) )
2816 idx++;
2817 code = ScanTbl[idx];
2818 if ( !code )
2819 // not found in cache
2820 code = qt_scan2Ascii( chm.scancode, (state & Qt::ShiftButton) );
2821 break;
2822 }
2823 }
2824 }
2825 // check extraState AFTER updating it
2826 if ( qt_extraKeyState & Qt::AltButton )
2827 state |= Qt::AltButton;
2828
2829 // detect numeric keypad keys
2830 if ( chm.vkey == VK_ENTER || chm.vkey == VK_NUMLOCK ) {
2831 // these always come from the numpad
2832 state |= Qt::Keypad;
2833 } else if (
2834 ((chm.vkey >= VK_PAGEUP && chm.vkey <= VK_DOWN) ||
2835 chm.vkey == VK_INSERT || chm.vkey == VK_DELETE)
2836 ) {
2837 if ( ch != 0xE0 ) {
2838 state |= Qt::Keypad;
2839 if ( ch ) {
2840 // override code to make it Qt::Key_0..Qt::Key_9 etc.
2841 code = toupper( ch );
2842 }
2843 } else {
2844 ch = 0;
2845 }
2846 }
2847 // detect other numpad keys. OS/2 doesn't assign virtual keys to them
2848 // so use scancodes (it can be device-dependent, is there a better way?)
2849 switch ( chm.scancode ) {
2850 case 0x4C: // 5
2851 // scancode is zero if Numlock is set
2852 if ( !code ) code = Qt::Key_Clear;
2853 state |= Qt::Keypad;
2854 break;
2855 case 0x37: // *
2856 // OS/2 assigns VK_PRINTSCRN to it when pressed with Shift, also
2857 // it sets chr to zero when it is released with Alt or Ctrl
2858 // leaving vkey as zero too, and does few other strange things --
2859 // override them all
2860 code = Qt::Key_Asterisk;
2861 state |= Qt::Keypad;
2862 break;
2863 case 0x5C: // /
2864 code = Qt::Key_Slash;
2865 // fall through
2866 case 0x4A: // -
2867 case 0x4E: // +
2868 // the code for the above two is obtained by KbdXlate above
2869 state |= Qt::Keypad;
2870 break;
2871 }
2872
2873 if ( (state & Qt::ControlButton) && !(state & Qt::Keypad) ) {
2874 if ( !(state & Qt::AltButton) ) {
2875 unsigned char cch = toupper( ch ), newCh = 0;
2876 // Ctrl + A..Z etc. produce ascii from 0x01 to 0x1F
2877 if ( cch >= 0x41 && cch <= 0x5F ) newCh = cch - 0x40;
2878 // the below emulates OS/2 functionality. It differs from
2879 // Win32 one.
2880 else if ( cch == 0x36 && !(state & Qt::Keypad) ) newCh = 0x1E;
2881 else if ( cch == 0x2D ) newCh = 0x1F;
2882 else if ( cch >= 0x7B && cch <= 0x7D ) newCh = cch - 0x60;
2883 if ( newCh )
2884 ch = newCh;
2885 }
2886 }
2887
2888 ascii = ch;
2889 if ( ascii > 0x7F ) ascii = 0;
2890 if ( ch )
2891 text = QString::fromLocal8Bit( (char*)&ch, 1 );
2892}
2893
2894struct KeyRec {
2895 KeyRec(unsigned char s, int c, int a, const QString& t) :
2896 scan(s), code(c), ascii(a), text(t) { }
2897 KeyRec() { }
2898 unsigned char scan;
2899 int code, ascii;
2900 QString text;
2901};
2902
2903static const int maxrecs=64; // User has LOTS of fingers...
2904static KeyRec key_rec[maxrecs];
2905static int nrecs=0;
2906
2907static KeyRec* find_key_rec( unsigned char scan, bool remove )
2908{
2909 KeyRec *result = 0;
2910 for (int i=0; i<nrecs; i++) {
2911 if (key_rec[i].scan == scan) {
2912 if (remove) {
2913 static KeyRec tmp;
2914 tmp = key_rec[i];
2915 while (i+1 < nrecs) {
2916 key_rec[i] = key_rec[i+1];
2917 i++;
2918 }
2919 nrecs--;
2920 result = &tmp;
2921 } else {
2922 result = &key_rec[i];
2923 }
2924 break;
2925 }
2926 }
2927 return result;
2928}
2929
2930static KeyRec* find_key_rec( int code, bool remove )
2931{
2932 KeyRec *result = 0;
2933 for (int i=0; i<nrecs; i++) {
2934 if (key_rec[i].code == code) {
2935 if (remove) {
2936 static KeyRec tmp;
2937 tmp = key_rec[i];
2938 while (i+1 < nrecs) {
2939 key_rec[i] = key_rec[i+1];
2940 i++;
2941 }
2942 nrecs--;
2943 result = &tmp;
2944 } else {
2945 result = &key_rec[i];
2946 }
2947 break;
2948 }
2949 }
2950 return result;
2951}
2952
2953static void store_key_rec( unsigned char scan, int code, int ascii,
2954 const QString& text )
2955{
2956 if ( nrecs == maxrecs ) {
2957#if defined(QT_CHECK_RANGE)
2958 qWarning( "Qt: Internal keyboard buffer overflow" );
2959#endif
2960 return;
2961 }
2962
2963 key_rec[nrecs++] = KeyRec( scan, code, ascii, text );
2964}
2965
2966bool QETWidget::translateKeyEvent( const QMSG &qmsg, bool grab )
2967{
2968 CHRMSG chm = *((PCHRMSG)(((char*)&qmsg) + sizeof(HWND) + sizeof(ULONG)));
2969
2970#if 0
2971 qDebug( "WM_CHAR: [%s] fs: %04X cRepeat: %03d scancode: %02X chr: %04X vkey: %04X %s",
2972 name(), chm.fs, chm.cRepeat, chm.scancode, chm.chr, chm.vkey, (grab ? "{grab}" : "") );
2973#endif
2974
2975 bool k0 = FALSE, k1 = FALSE;
2976 int code = 0, ascii = 0, state = 0;
2977 QString text;
2978
2979 if ( sm_blockUserInput ) // block user interaction during session management
2980 return TRUE;
2981
2982 translateKeyCode( chm, code, ascii, state, text );
2983/// @todo (dmik) currently WM_CHARs chars with zero virtual code or zero
2984// scancode are totally ignored. -- are they?
2985// if ( !code || !chm.scancode ) return FALSE;
2986
2987 // Invert state logic
2988 if ( code == Key_Alt )
2989 state = state ^ AltButton;
2990 else if ( code == Key_Control )
2991 state = state ^ ControlButton;
2992 else if ( code == Key_Shift )
2993 state = state ^ ShiftButton;
2994
2995 if ( !(chm.fs & KC_KEYUP) ) {
2996 // KEYDOWN
2997 KeyRec* rec = find_key_rec( chm.scancode, FALSE );
2998
2999 if ( state == Qt::AltButton ) {
3000 // Special handling of global PM hotkeys
3001 switch ( code ) {
3002 case Qt::Key_Space:
3003 if ( qt_show_system_menu( topLevelWidget() ) ) {
3004 // remove the Key_Alt from the buffer (otherwise we will
3005 // not get the next "Alt pressed" event because the
3006 // "Alt depressed" event, that must preceed it, will be
3007 // eaten by the system)
3008 find_key_rec( Qt::Key_Alt, TRUE );
3009/// @todo (dmik) do the same for other global keys (ALT+TAB, ALT+ESC, CTRL+ESC)
3010// by handling this situation when we obtain/loose focus)
3011/// @todo (dmik) update: I don't actually think the above should be done, because
3012// it will not solve the problem of stuck modifier keys in general (there may be
3013// other combinations stolen by the system or other apps). More over, I guess
3014// that find_key_rec() above should also be removed to get identical behavior for
3015// all stolen keys. This will allow to solve the problem on the Qt application
3016// level if needed (and even in a platform-independent manner).
3017 }
3018 return TRUE;
3019 case Qt::Key_F4:
3020 // we handle this key combination ourselves because not
3021 // all top-level widgets have the system menu
3022 WinPostMsg( topLevelWidget()->winFId(), WM_CLOSE, 0, 0 );
3023 // see the comment above
3024 find_key_rec( Qt::Key_Alt, TRUE );
3025 return TRUE;
3026 default:
3027 break;
3028 }
3029 }
3030
3031 if ( rec ) {
3032 // it is already down (so it is auto-repeating)
3033 if ( rec->code < Key_Shift || rec->code > Key_ScrollLock ) {
3034 k0 = sendKeyEvent( QEvent::KeyRelease, rec->code, rec->ascii,
3035 state, grab, rec->text, TRUE );
3036 k1 = sendKeyEvent( QEvent::KeyPress, rec->code, rec->ascii,
3037 state, grab, rec->text, TRUE );
3038 }
3039 } else {
3040 // map shift+tab to shift+backtab, QAccel knows about it
3041 // and will handle it
3042 if ( code == Key_Tab && ( state & ShiftButton ) == ShiftButton )
3043 code = Key_BackTab;
3044 store_key_rec( chm.scancode, code, ascii, text );
3045 k0 = sendKeyEvent( QEvent::KeyPress, code, ascii,
3046 state, grab, text );
3047 }
3048 } else {
3049 // KEYUP
3050 KeyRec* rec = find_key_rec( chm.scancode, TRUE );
3051 if ( !rec ) {
3052 // Someone ate the key down event
3053 } else {
3054 k0 = sendKeyEvent( QEvent::KeyRelease, rec->code, rec->ascii,
3055 state, grab, rec->text );
3056
3057 // keyboard context menu event
3058 if ( rec->code == Key_Menu && !state )
3059 WinPostMsg( qmsg.hwnd, WM_CONTEXTMENU, 0, MPFROM2SHORT( 0, 1 ) );
3060 }
3061 }
3062
3063#if 0
3064 qDebug("WM_CHAR: RESULT = %d", (k0 || k1));
3065#endif
3066 return k0 || k1;
3067}
3068
3069#ifndef QT_NO_WHEELEVENT
3070bool QETWidget::translateWheelEvent( const QMSG &qmsg )
3071{
3072 enum { WHEEL_DELTA = 120 };
3073
3074 if ( sm_blockUserInput ) // block user interaction during session management
3075 return TRUE;
3076
3077 // consume duplicate wheel events sent by the AMouse driver to emulate
3078 // multiline scrolls. we need this since currently Qt (QScrollBar, for
3079 // instance) maintains the number of lines to scroll per wheel rotation
3080 // (including the special handling of CTRL and SHIFT modifiers) on its own
3081 // and doesn't have a setting to tell it to be aware of system settings
3082 // for the mouse wheel. if we had processed events as they are, we would
3083 // get a confusing behavior (too many lines scrolled etc.).
3084 {
3085 int devh = QApplication::desktop()->height();
3086 QMSG wheelMsg;
3087 while (
3088 WinPeekMsg( 0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_NOREMOVE )
3089 ) {
3090 // PM bug: ptl contains SHORT coordinates although fields are LONG
3091 wheelMsg.ptl.x = (short) wheelMsg.ptl.x;
3092 wheelMsg.ptl.y = (short) wheelMsg.ptl.y;
3093 // flip y coordinate
3094 wheelMsg.ptl.y = devh - (wheelMsg.ptl.y + 1);
3095 if (
3096 wheelMsg.mp1 != qmsg.mp1 ||
3097 wheelMsg.mp2 != qmsg.mp2 ||
3098 wheelMsg.ptl.x != qmsg.ptl.x ||
3099 wheelMsg.ptl.y != qmsg.ptl.y
3100 )
3101 break;
3102 WinPeekMsg( 0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_REMOVE );
3103 }
3104 }
3105
3106 int delta;
3107 USHORT cmd = SHORT2FROMMP(qmsg.mp2);
3108 switch ( cmd ) {
3109 case SB_LINEUP:
3110 case SB_PAGEUP:
3111 delta = WHEEL_DELTA;
3112 break;
3113 case SB_LINEDOWN:
3114 case SB_PAGEDOWN:
3115 delta = -WHEEL_DELTA;
3116 break;
3117 default:
3118 return FALSE;
3119 }
3120
3121 int state = 0;
3122 if ( WinGetKeyState( HWND_DESKTOP, VK_SHIFT ) & 0x8000 )
3123 state |= ShiftButton;
3124 if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 ||
3125 (qt_extraKeyState & Qt::AltButton)
3126 )
3127 state |= AltButton;
3128 if ( WinGetKeyState( HWND_DESKTOP, VK_CTRL ) & 0x8000 )
3129 state |= ControlButton;
3130 if ( qt_extraKeyState & Qt::MetaButton )
3131 state |= MetaButton;
3132
3133 Orientation orient;
3134 // Alt inverts scroll orientation (Qt/Win32 behavior)
3135 if ( state & AltButton )
3136 orient = qmsg.msg == WM_VSCROLL ? Horizontal : Vertical;
3137 else
3138 orient = qmsg.msg == WM_VSCROLL ? Vertical : Horizontal;
3139
3140 QPoint globalPos (qmsg.ptl.x, qmsg.ptl.y);
3141
3142 // if there is a widget under the mouse and it is not shadowed
3143 // by modality, we send the event to it first
3144 int ret = 0;
3145 QWidget* w = QApplication::widgetAt( globalPos, TRUE );
3146 if ( !w || !qt_try_modal( w, (QMSG*)&qmsg, ret ) )
3147 w = this;
3148
3149 // send the event to the widget or its ancestors
3150 {
3151 QWidget* popup = qApp->activePopupWidget();
3152 if ( popup && w->topLevelWidget() != popup )
3153 popup->close();
3154 QWheelEvent e( w->mapFromGlobal( globalPos ), globalPos, delta, state, orient );
3155 if ( QApplication::sendSpontaneousEvent( w, &e ) )
3156 return TRUE;
3157 }
3158
3159 // send the event to the widget that has the focus or its ancestors, if different
3160 if ( w != qApp->focusWidget() && ( w = qApp->focusWidget() ) ) {
3161 QWidget* popup = qApp->activePopupWidget();
3162 if ( popup && w->topLevelWidget() != popup )
3163 popup->close();
3164 QWheelEvent e( w->mapFromGlobal( globalPos ), globalPos, delta, state, orient );
3165 if ( QApplication::sendSpontaneousEvent( w, &e ) )
3166 return TRUE;
3167 }
3168 return FALSE;
3169}
3170#endif
3171
3172static bool isModifierKey(int code)
3173{
3174 return code >= Qt::Key_Shift && code <= Qt::Key_ScrollLock;
3175}
3176
3177bool QETWidget::sendKeyEvent( QEvent::Type type, int code, int ascii,
3178 int state, bool grab, const QString& text,
3179 bool autor )
3180{
3181 if ( type == QEvent::KeyPress && !grab ) {
3182 // send accel events if the keyboard is not grabbed
3183 QKeyEvent a( type, code, ascii, state, text, autor, QMAX(1, int(text.length())) );
3184 if ( qt_tryAccelEvent( this, &a ) )
3185 return TRUE;
3186 }
3187 if ( !isEnabled() )
3188 return FALSE;
3189 QKeyEvent e( type, code, ascii, state, text, autor, QMAX(1, int(text.length())) );
3190 QApplication::sendSpontaneousEvent( this, &e );
3191 if ( !isModifierKey(code) && state == Qt::AltButton
3192 && ((code>=Key_A && code<=Key_Z) || (code>=Key_0 && code<=Key_9))
3193 && type == QEvent::KeyPress && !e.isAccepted() )
3194 QApplication::beep(); // emulate PM behavior
3195 return e.isAccepted();
3196}
3197
3198
3199//
3200// Paint event translation
3201//
3202bool QETWidget::translatePaintEvent( const QMSG & )
3203{
3204 HPS displayPS = qt_display_ps();
3205
3206#if !defined (QT_PM_NO_WIDGETMASK)
3207 // Since we don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN bits (see
3208 // qwidget_pm.cpp), we have to validate areas that intersect with our
3209 // children and siblings, taking their clip regions into account.
3210 validateObstacles();
3211#endif
3212
3213 HRGN hrgn = GpiCreateRegion( displayPS, 0, NULL );
3214 LONG rc = WinQueryUpdateRegion( winId(), hrgn );
3215 if ( rc == RGN_ERROR ) {
3216 GpiDestroyRegion( displayPS, hrgn );
3217 hps = 0;
3218 clearWState( WState_InPaintEvent );
3219 return FALSE;
3220 }
3221
3222 setWState( WState_InPaintEvent );
3223 RECTL rcl;
3224 hps = WinBeginPaint( winId(), 0, &rcl );
3225
3226 // convert to width and height
3227 rcl.xRight -= rcl.xLeft;
3228 rcl.yTop -= rcl.yBottom;
3229
3230 // it's possible that the update rectangle is empty
3231 if ( !rcl.xRight || !rcl.yTop ) {
3232 WinEndPaint( hps );
3233 GpiDestroyRegion( displayPS, hrgn );
3234 hps = 0;
3235 clearWState( WState_InPaintEvent );
3236 return TRUE;
3237 }
3238
3239#if !defined (QT_PM_NO_WIDGETMASK)
3240 if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
3241 // Correct the update region by intersecting it with the clip
3242 // region (PM doesn't do that itself). It is necessary
3243 // to have a correct QRegion in QPaintEvent.
3244 HRGN hcrgn = GpiCreateRegion( displayPS, 0, NULL );
3245 WinQueryClipRegion( winId(), hcrgn );
3246 GpiCombineRegion( displayPS, hrgn, hrgn, hcrgn, CRGN_AND );
3247 GpiDestroyRegion( displayPS, hcrgn );
3248 }
3249#endif
3250
3251 // flip y coordinate
3252 rcl.yBottom = height() - (rcl.yBottom + rcl.yTop);
3253
3254 // erase background
3255#if !defined (DEBUG_REPAINTRESIZE)
3256 bool erase = !( testWFlags( WRepaintNoErase ) );
3257#else
3258 // Some oldish Qt widgets think that if they specify WRepaintNoErase but
3259 // not WResizeNoErase, the background should still be erased for them
3260 // in *repaint* events. The code below is left to debug these widgets
3261 // (to ensure this is the exact cause of repaint problems)
3262 bool erase = testWFlags( WRepaintNoErase | WResizeNoErase ) != WRepaintNoErase | WResizeNoErase;
3263#endif
3264 if ( erase )
3265 this->erase( rcl.xLeft, rcl.yBottom,
3266 rcl.xRight, rcl.yTop );
3267
3268#if defined (DEBUG_REPAINTRESIZE)
3269 qDebug( "WM_PAINT: [%s/%s/%08X] %ld,%ld; %ld,%ld erase: %d",
3270 name(), className(), widget_flags,
3271 rcl.xLeft, rcl.yBottom, rcl.xRight, rcl.yTop, erase );
3272#endif
3273
3274 // create a region that will take ownership of hrgn
3275 QRegion rgn( hrgn, height() );
3276
3277 QPaintEvent e( rgn, QRect( rcl.xLeft, rcl.yBottom, rcl.xRight, rcl.yTop ),
3278 erase );
3279 QApplication::sendSpontaneousEvent( this, (QEvent*) &e );
3280
3281 WinEndPaint( hps );
3282 hps = 0;
3283 clearWState( WState_InPaintEvent );
3284 return TRUE;
3285}
3286
3287//
3288// Window move and resize (configure) events
3289//
3290
3291bool QETWidget::translateConfigEvent( const QMSG &qmsg )
3292{
3293 if ( !testWState(WState_Created) ) // in QWidget::create()
3294 return TRUE;
3295
3296 WId fId = winFId();
3297 ULONG fStyle = WinQueryWindowULong( fId, QWL_STYLE );
3298 if ( testWState( WState_ConfigPending ) ) {
3299 // it's possible that we're trying to set the frame size smaller
3300 // than it possible for WC_FRAME in QWidget::internalSetGeometry().
3301 // here we correct this (crect there is set before WinSetWindowPos()
3302 // that sends WM_SIZE).
3303 QSize newSize( SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
3304 if ( qmsg.msg == WM_SIZE && size() != newSize ) {
3305 crect.setSize( newSize );
3306 }
3307 return TRUE;
3308 }
3309 setWState( WState_ConfigPending ); // set config flag
3310 QRect cr = geometry();
3311 if ( qmsg.msg == WM_SIZE ) { // resize event
3312 QSize oldSize = size();
3313 QSize newSize( SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
3314 cr.setSize( newSize );
3315 crect = cr;
3316 if ( isTopLevel() ) { // update caption/icon text
3317 createTLExtra();
3318 QString txt;
3319 if ( (fStyle & WS_MAXIMIZED) && !!iconText() )
3320 txt = iconText();
3321 else
3322 if ( !caption().isNull() )
3323 txt = caption();
3324
3325 if ( !!txt ) {
3326 WinSetWindowText( fId, txt.local8Bit() );
3327 }
3328 }
3329 if ( oldSize != newSize) {
3330#if !defined (QT_PM_NO_WIDGETMASK)
3331 // Spontaneous (external to Qt) WM_SIZE messages should occur only
3332 // on top-level widgets. If we get them for a non top-level widget,
3333 // the result will most likely be incorrect because widget masks will
3334 // not be properly processed (i.e. in the way it is done in
3335 // QWidget::internalSetGeometry() when the geometry is changed from
3336 // within Qt). So far, I see no need to support this (who will ever
3337 // need to move a non top-level window of a foreign process?).
3338 Q_ASSERT( isTopLevel() );
3339#endif
3340 if ( isVisible() ) {
3341 QResizeEvent e( newSize, oldSize );
3342 QApplication::sendSpontaneousEvent( this, &e );
3343 if ( !testWFlags( WStaticContents ) )
3344 repaint( !testWFlags(WResizeNoErase) );
3345#if !defined (QT_PM_NO_WIDGETMASK)
3346 // Flush WM_PAINT messages here to update window contents
3347 // instantly while tracking the resize frame (normally these
3348 // messages are delivered after resizing is stopped for some
3349 // time). It makes resizing a bit slower but gives a better look
3350 // (no invalid window contents can be seen during resize).
3351 // The alternative could be to erase the background only
3352 // (similarly to Win32), but we need to do it for every
3353 // non-toplevel window, which can be also time-consuming
3354 WinUpdateWindow( winId() );
3355#endif
3356 } else {
3357 QResizeEvent *e = new QResizeEvent( newSize, oldSize );
3358 QApplication::postEvent( this, e );
3359 }
3360 }
3361 } else if ( qmsg.msg == WM_MOVE ) { // move event
3362 QPoint oldPos = geometry().topLeft();
3363 SWP swp;
3364 if ( isTopLevel() ) {
3365 WinQueryWindowPos( fId, &swp );
3366 // flip y coordinate
3367 swp.y = QApplication::desktop()->height() - ( swp.y + swp.cy );
3368 QTLWExtra *top = topData();
3369 swp.x += top->fleft;
3370 swp.y += top->ftop;
3371 } else {
3372 WinQueryWindowPos( winId(), &swp );
3373 // flip y coordinate
3374 swp.y = parentWidget()->height() - ( swp.y + swp.cy );
3375 }
3376 QPoint newCPos( swp.x, swp.y );
3377 if ( newCPos != oldPos ) {
3378 cr.moveTopLeft( newCPos );
3379 crect = cr;
3380 if ( isVisible() ) {
3381 QMoveEvent e( newCPos, oldPos ); // cpos (client position)
3382 QApplication::sendSpontaneousEvent( this, &e );
3383 } else {
3384 QMoveEvent * e = new QMoveEvent( newCPos, oldPos );
3385 QApplication::postEvent( this, e );
3386 }
3387 }
3388 }
3389 clearWState( WState_ConfigPending ); // clear config flag
3390 return TRUE;
3391}
3392
3393
3394//
3395// Close window event translation.
3396//
3397// This class is a friend of QApplication because it needs to emit the
3398// lastWindowClosed() signal when the last top level widget is closed.
3399//
3400
3401bool QETWidget::translateCloseEvent( const QMSG & )
3402{
3403 return close(FALSE);
3404}
3405
3406void QApplication::setCursorFlashTime( int msecs )
3407{
3408 WinSetSysValue( HWND_DESKTOP, SV_CURSORRATE, msecs / 2 );
3409 cursor_flash_time = msecs;
3410}
3411
3412int QApplication::cursorFlashTime()
3413{
3414 int blink = (int) WinQuerySysValue( HWND_DESKTOP, SV_CURSORRATE );
3415 if ( !blink )
3416 return cursor_flash_time;
3417 if (blink > 0)
3418 return 2*blink;
3419 return 0;
3420}
3421
3422void QApplication::setDoubleClickInterval( int ms )
3423{
3424 WinSetSysValue( HWND_DESKTOP, SV_DBLCLKTIME, ms );
3425 mouse_double_click_time = ms;
3426}
3427
3428
3429int QApplication::doubleClickInterval()
3430{
3431 int ms = (int) WinQuerySysValue( HWND_DESKTOP, SV_DBLCLKTIME );
3432 if ( ms != 0 )
3433 return ms;
3434 return mouse_double_click_time;
3435}
3436
3437void QApplication::setWheelScrollLines( int n )
3438{
3439 wheel_scroll_lines = n;
3440}
3441
3442int QApplication::wheelScrollLines()
3443{
3444 return wheel_scroll_lines;
3445}
3446
3447void QApplication::setEffectEnabled( Qt::UIEffect effect, bool enable )
3448{
3449#ifndef QT_NO_EFFECTS
3450 switch (effect) {
3451 case UI_AnimateMenu:
3452 if ( enable ) fade_menu = FALSE;
3453 animate_menu = enable;
3454 break;
3455 case UI_FadeMenu:
3456 if ( enable )
3457 animate_menu = TRUE;
3458 fade_menu = enable;
3459 break;
3460 case UI_AnimateCombo:
3461 animate_combo = enable;
3462 break;
3463 case UI_AnimateTooltip:
3464 if ( enable ) fade_tooltip = FALSE;
3465 animate_tooltip = enable;
3466 break;
3467 case UI_FadeTooltip:
3468 if ( enable )
3469 animate_tooltip = TRUE;
3470 fade_tooltip = enable;
3471 break;
3472 case UI_AnimateToolBox:
3473 animate_toolbox = enable;
3474 break;
3475 default:
3476 animate_ui = enable;
3477 break;
3478 }
3479#endif
3480}
3481
3482bool QApplication::isEffectEnabled( Qt::UIEffect effect )
3483{
3484#ifndef QT_NO_EFFECTS
3485 if ( QColor::numBitPlanes() < 16 || !animate_ui )
3486 return FALSE;
3487
3488 switch( effect ) {
3489 case UI_AnimateMenu:
3490 return animate_menu;
3491 case UI_FadeMenu:
3492 return fade_menu;
3493 case UI_AnimateCombo:
3494 return animate_combo;
3495 case UI_AnimateTooltip:
3496 return animate_tooltip;
3497 case UI_FadeTooltip:
3498 return fade_tooltip;
3499 case UI_AnimateToolBox:
3500 return animate_toolbox;
3501 default:
3502 return animate_ui;
3503 }
3504#else
3505 return FALSE;
3506#endif
3507}
3508
3509void QApplication::flush()
3510{
3511}
3512
3513#if !defined (QT_NO_SESSIONMANAGER)
3514
3515bool qt_app_canQuit()
3516{
3517#if defined (DEBUG_SESSIONMANAGER)
3518 qDebug( "qt_app_canQuit(): sm_smActive=%d qt_about_to_destroy_wnd=%d "
3519 "sm_gracefulShutdown=%d sm_cancel=%d",
3520 sm_smActive, qt_about_to_destroy_wnd,
3521 sm_gracefulShutdown, sm_cancel );
3522#endif
3523
3524 BOOL answer = FALSE;
3525
3526 // We can get multiple WM_QUIT messages while the "session termination
3527 // procedure" (i.e. the QApplication::commitData() call) is still in
3528 // progress. Ignore them.
3529 if ( !sm_smActive ) {
3530 if ( sm_gracefulShutdown ) {
3531 // this is WM_QUIT after WM_SAVEAPPLICATION (either posted by the OS
3532 // or by ourselves), confirm the quit depending on what the user wants
3533 sm_quitSkipped = FALSE;
3534 answer = !sm_cancel;
3535 if ( sm_cancel ) {
3536 // the shutdown has been canceled, reset the flag to let the
3537 // graceful shutdown happen again later
3538 sm_gracefulShutdown = FALSE;
3539 }
3540 } else {
3541 // sm_gracefulShutdown is FALSE, so allowsInteraction() and friends
3542 // will return FALSE during commitData() (assuming that WM_QUIT w/o
3543 // WM_SAVEAPPLICATION is an emergency termination)
3544 sm_smActive = TRUE;
3545 sm_blockUserInput = TRUE; // prevent user-interaction outside interaction windows
3546 sm_cancel = FALSE;
3547 if ( qt_session_manager_self )
3548 qApp->commitData( *qt_session_manager_self );
3549 sm_smActive = FALSE;
3550 answer = TRUE; // ignore sm_cancel
3551 }
3552 } else {
3553 // if this is a WM_QUIT received during WM_SAVEAPPLICATION handling,
3554 // remember we've skipped (refused) it
3555 if ( sm_gracefulShutdown )
3556 sm_quitSkipped = TRUE;
3557 }
3558
3559#if defined (DEBUG_SESSIONMANAGER)
3560 qDebug( "qt_app_canQuit(): answer=%ld", answer );
3561#endif
3562
3563 return answer;
3564}
3565
3566bool QSessionManager::allowsInteraction()
3567{
3568 // Allow interation only when the system is being normally shutdown
3569 // and informs us using WM_SAVEAPPLICATION. When we receive WM_QUIT directly
3570 // (so sm_gracefulShutdown is FALSE), interaction is disallowed.
3571 if ( sm_smActive && sm_gracefulShutdown ) {
3572 sm_blockUserInput = FALSE;
3573 return TRUE;
3574 }
3575
3576 return FALSE;
3577}
3578
3579bool QSessionManager::allowsErrorInteraction()
3580{
3581 // Allow interation only when the system is being normally shutdown
3582 // and informs us using WM_SAVEAPPLICATION. When we receive WM_QUIT directly
3583 // (so sm_gracefulShutdown is FALSE), interaction is disallowed.
3584 if ( sm_smActive && sm_gracefulShutdown ) {
3585 sm_blockUserInput = FALSE;
3586 return TRUE;
3587 }
3588
3589 return FALSE;
3590}
3591
3592void QSessionManager::release()
3593{
3594 if ( sm_smActive && sm_gracefulShutdown )
3595 sm_blockUserInput = TRUE;
3596}
3597
3598void QSessionManager::cancel()
3599{
3600 if ( sm_smActive && sm_gracefulShutdown )
3601 sm_cancel = TRUE;
3602}
3603
3604#endif
Note: See TracBrowser for help on using the repository browser.