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

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

Widgets: Implemented QDesktopWidget::availableGeometry().

  • Property svn:keywords set to Id
File size: 125.2 KB
Line 
1/****************************************************************************
2** $Id: qapplication_pm.cpp 110 2006-07-30 17:11:51Z 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
953enum {
954 // some undocumented messages (they have the WM_U_ prefix for clarity)
955
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 // some undocumented system values
966
967 SV_WORKAREA_YTOP = 51,
968 SV_WORKAREA_YBOTTOM = 52,
969 SV_WORKAREA_XRIGHT = 53,
970 SV_WORKAREA_XLEFT = 54,
971};
972
973static bool inLoop = FALSE;
974
975#define RETURN(x) { inLoop = FALSE; return (MRESULT) (x); }
976
977inline bool qt_sendSpontaneousEvent( QObject *receiver, QEvent *event )
978{
979 return QApplication::sendSpontaneousEvent( receiver, event );
980}
981
982extern "C" MRESULT EXPENTRY QtWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
983{
984 // message handling indicators: if result is true at the end of message
985 // processing, no default window proc is called but rc is returned.
986 bool result = TRUE;
987 MRESULT rc = (MRESULT) 0;
988
989 QEvent::Type evt_type = QEvent::None;
990 QETWidget *widget = 0;
991 bool isMouseEvent = FALSE;
992
993 if ( !qApp ) // unstable app state
994 goto do_default;
995
996 // make sure we show widgets (e.g. scrollbars) when the user resizes
997 if ( inLoop && qApp->loopLevel() )
998 qApp->sendPostedEvents( 0, QEvent::ShowWindowRequest );
999
1000 inLoop = TRUE;
1001
1002 isMouseEvent =
1003 (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
1004 (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST);
1005//@@TODO (dmik): later (extra buttons)
1006// (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK)
1007
1008 QMSG qmsg; // create QMSG structure
1009 qmsg.hwnd = hwnd;
1010 qmsg.msg = msg;
1011 qmsg.mp1 = mp1;
1012 qmsg.mp2 = mp2;
1013 qmsg.time = WinQueryMsgTime( 0 );
1014 if ( isMouseEvent || msg == WM_CONTEXTMENU ) {
1015 qmsg.ptl.x = (short)SHORT1FROMMP(mp1);
1016 qmsg.ptl.y = (short)SHORT2FROMMP(mp1);
1017 WinMapWindowPoints( qmsg.hwnd, HWND_DESKTOP, &qmsg.ptl, 1 );
1018 } else {
1019 WinQueryMsgPos( 0, &qmsg.ptl );
1020 }
1021 // flip y coordinate
1022 qmsg.ptl.y = QApplication::desktop()->height() - (qmsg.ptl.y + 1);
1023
1024/// @todo (dmik) do we need this?
1025// /*
1026// // sometimes the autograb is not released, so the clickevent is sent
1027// // to the wrong window. We ignore this for now, because it doesn't
1028// // cause any problems.
1029// if ( msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN ) {
1030// HWND handle = WindowFromPoint( msg.pt );
1031// if ( msg.hwnd != handle ) {
1032// msg.hwnd = handle;
1033// hwnd = handle;
1034// }
1035// }
1036// */
1037
1038 if ( qt_pmEventFilter( &qmsg, rc ) ) // send through app filter
1039 RETURN( rc );
1040
1041 switch ( msg ) {
1042#if !defined (QT_NO_SESSIONMANAGER)
1043 case WM_SAVEAPPLICATION: {
1044#if defined (DEBUG_SESSIONMANAGER)
1045 qDebug( "WM_SAVEAPPLICATION: sm_gracefulShutdown=%d "
1046 "qt_about_to_destroy_wnd=%d (mp1=%p mp2=%p)",
1047 sm_gracefulShutdown, qt_about_to_destroy_wnd,
1048 mp1, mp2 );
1049#endif
1050 // PM seems to post this message to all top-level windows on system
1051 // shutdown, so react only to the first one. Also, this message is
1052 // always sent by WinDestroyWindow(), where it must be also ignored.
1053 if ( !qt_about_to_destroy_wnd && !sm_smActive &&
1054 !sm_gracefulShutdown ) {
1055 sm_smActive = TRUE;
1056 sm_gracefulShutdown = TRUE;
1057 sm_blockUserInput = TRUE; // prevent user-interaction outside interaction windows
1058 sm_cancel = FALSE;
1059 sm_quitSkipped = FALSE;
1060 if ( qt_session_manager_self )
1061 qApp->commitData( *qt_session_manager_self );
1062 sm_smActive = FALSE; // session management has been finished
1063 if ( sm_cancel ) {
1064 // Here we try to cancel the Extended XWorkplace shutdown.
1065 // If it's XWorkplace who sent us WM_SAVEAPPLICATION, then
1066 // it probably passed us non-NULL parameters, so that
1067 // mp1 = it's window handle and mp2 = WM_COMMAND code to
1068 // cancel the shutdown procedure.
1069 HWND shutdownHwnd = HWNDFROMMP(mp1);
1070 if ( WinIsWindow( 0, shutdownHwnd ) ) {
1071 WinPostMsg( shutdownHwnd, WM_COMMAND, mp2, 0 );
1072 // Ensure we will get WM_QUIT anyway, even if xwp was
1073 // not that fast to post it yet (we need it to correctly
1074 // finish the graceful shutdown procedure)
1075 sm_quitSkipped = TRUE;
1076 }
1077 }
1078 // repost WM_QUIT to ourselves because we might have ignored
1079 // it in qt_app_canQuit(), so will not get one anymore
1080 if ( sm_quitSkipped )
1081 WinPostMsg( hwnd, WM_QUIT, 0, 0 );
1082 }
1083 // PMREF recommends to pass it to WinDefWindowProc()
1084 rc = WinDefWindowProc( hwnd, msg, mp1, mp2 );
1085 RETURN( rc );
1086 }
1087#endif
1088
1089 case WM_SYSVALUECHANGED: {
1090 // This message is sent to all top-level widgets, handle only once
1091 QWidgetList *list = QApplication::topLevelWidgets();
1092 bool firstWidget = list->first()->winId() == hwnd;
1093 delete list;
1094 if ( !firstWidget )
1095 break;
1096 LONG from = (LONG) mp1;
1097 LONG to = (LONG) mp2;
1098 #define _IS_SV(sv) (from >= (sv) && to <= (sv))
1099 if ( _IS_SV( SV_WORKAREA_XLEFT ) || _IS_SV( SV_WORKAREA_XRIGHT ) ||
1100 _IS_SV( SV_WORKAREA_YBOTTOM ) || _IS_SV( SV_WORKAREA_YTOP ) ) {
1101 // send a special invalid resize event to QDesktopWidget
1102 QResizeEvent re( QSize( -1, -1 ), QSize( -1, -1 ) );
1103 QApplication::sendEvent( qt_desktopWidget, &re );
1104 /// @todo (dmik) enumerate all top-level widgets and
1105 // remaximize those that are maximized
1106 } else {
1107 /// @todo (dmik) call qt_set_pm_resources() in the way it is
1108 // done in WM_SYSCOLORCHANGE for relevant SV_ values.
1109 }
1110 #undef _IS_SV
1111 break;
1112 }
1113
1114 case WM_SYSCOLORCHANGE: {
1115 // This message is sent to all top-level widgets, handle only once
1116 QWidgetList *list = QApplication::topLevelWidgets();
1117 bool firstWidget = list->first()->winId() == hwnd;
1118 delete list;
1119 if ( !firstWidget )
1120 break;
1121 if ( qApp->type() == QApplication::Tty )
1122 break;
1123 if ( QApplication::desktopSettingsAware() ) {
1124 widget = (QETWidget*)QWidget::find( hwnd );
1125 if ( widget && !widget->parentWidget() )
1126 qt_set_pm_resources();
1127 }
1128 break;
1129 }
1130
1131 case WM_BUTTON1DOWN:
1132 case WM_BUTTON2DOWN:
1133 case WM_BUTTON3DOWN:
1134/// @todo (dmik) later (extra buttons)
1135// case WM_XBUTTONDOWN:
1136 if ( ignoreNextMouseReleaseEvent )
1137 ignoreNextMouseReleaseEvent = FALSE;
1138 break;
1139 case WM_BUTTON1UP:
1140 case WM_BUTTON2UP:
1141 case WM_BUTTON3UP:
1142/// @todo (dmik) later (extra buttons)
1143// case WM_XBUTTONUP:
1144 if ( ignoreNextMouseReleaseEvent ) {
1145 ignoreNextMouseReleaseEvent = FALSE;
1146 if ( qt_button_down && qt_button_down->winId() == autoCaptureWnd ) {
1147 releaseAutoCapture();
1148 qt_button_down = 0;
1149 }
1150 RETURN( TRUE );
1151 }
1152 break;
1153
1154 default:
1155 break;
1156 }
1157
1158 if ( !widget )
1159 widget = (QETWidget*)QWidget::find( hwnd );
1160 if ( !widget ) // don't know this widget
1161 goto do_default;
1162
1163 if ( app_do_modal ) { // modal event handling
1164 int ret = 0;
1165 if ( !qt_try_modal( widget, &qmsg, ret ) )
1166 return MRESULT( ret );
1167 }
1168
1169 if ( widget->pmEvent( &qmsg ) ) // send through widget filter
1170 RETURN( TRUE );
1171
1172 if ( isMouseEvent ) { // mouse events
1173 if ( qApp->activePopupWidget() != 0 ) { // in popup mode
1174 QWidget* w = QApplication::widgetAt( qmsg.ptl.x, qmsg.ptl.y, TRUE );
1175 if ( w ) {
1176 POINTL ptl = { SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1) };
1177 WinMapWindowPoints( qmsg.hwnd, w->winId(), &ptl, 1 );
1178 qmsg.mp1 = MPFROM2SHORT( ptl.x, ptl.y );
1179 widget = (QETWidget*)w;
1180 }
1181 }
1182 result = widget->translateMouseEvent( qmsg );
1183 rc = (MRESULT) result;
1184#ifndef QT_NO_WHEELEVENT
1185 } else if ( msg == WM_VSCROLL || msg == WM_HSCROLL ) {
1186 result = widget->translateWheelEvent( qmsg );
1187 rc = (MRESULT) result;
1188#endif
1189#ifndef QT_NO_DRAGANDDROP
1190 } else if ( msg >= WM_DRAGFIRST && msg <= WM_DRAGLAST ) {
1191 RETURN( qt_dispatchDragAndDrop( widget, qmsg ) );
1192#endif
1193 } else {
1194 switch ( msg ) {
1195
1196 case WM_TRANSLATEACCEL:
1197 if ( widget->isTopLevel() ) {
1198 rc = WinDefWindowProc( hwnd, msg, mp1, mp2 );
1199 if ( rc ) {
1200 QMSG &qmsg = *(QMSG*) mp1;
1201 if (
1202 qmsg.msg == WM_SYSCOMMAND &&
1203 WinWindowFromID( widget->winFId(), FID_SYSMENU )
1204 ) {
1205 switch ( SHORT1FROMMP(qmsg.mp1) ) {
1206 case SC_CLOSE:
1207 case SC_TASKMANAGER:
1208 RETURN( TRUE );
1209 default:
1210 break;
1211 }
1212 }
1213 }
1214 }
1215 // return FALSE in all other cases to let Qt process keystrokes
1216 // that are in the system-wide frame accelerator table.
1217 RETURN( FALSE );
1218
1219 case WM_CHAR: { // keyboard event
1220#if 0
1221 qDebug( "WM_CHAR: [%s]", widget->name() );
1222#endif
1223 QWidget *g = QWidget::keyboardGrabber();
1224 if ( g )
1225 widget = (QETWidget*)g;
1226 else if ( qApp->focusWidget() )
1227 widget = (QETWidget*)qApp->focusWidget();
1228 else if ( !widget )
1229/// @todo (dmik) currently we don't use WinSetFocus(). what for? Qt seems
1230// to completely handle focus traversal itself.
1231// || widget->winId() == WinQueryFocus( HWND_DESKTOP ) ) // We faked the message to go to exactly that widget.
1232 widget = (QETWidget*)widget->topLevelWidget();
1233 if ( widget->isEnabled() ) {
1234/// @todo (dmik) we should not pass WM_CHAR to the default window proc,
1235// otherwise it will come to us again through the widget parent (owner in PM)
1236// if the widget is not top-level, and will be treated by translateKeyEvent()
1237// as a key repeat (in case of key down) or a lost key (in case of key up).
1238// NOTE: currently we don't use WinSetFocus(), so the active top-level window
1239// will always have the focus, so it doesn't matter wheither we pass WM_CHAR
1240// to the default window proc or not.
1241// result = widget->translateKeyEvent( qmsg, g != 0 );
1242// rc = (MRESULT) result;
1243 RETURN( widget->translateKeyEvent( qmsg, g != 0 ) );
1244 }
1245 break;
1246 }
1247
1248/// @todo (dmik) later
1249// case WM_APPCOMMAND:
1250// {
1251// uint cmd = GET_APPCOMMAND_LPARAM(lParam);
1252// uint uDevice = GET_DEVICE_LPARAM(lParam);
1253// uint dwKeys = GET_KEYSTATE_LPARAM(lParam);
1254//
1255// int state = translateButtonState( dwKeys, QEvent::KeyPress, 0 );
1256//
1257// switch ( uDevice ) {
1258// case FAPPCOMMAND_KEY:
1259// {
1260// int key = 0;
1261//
1262// switch( cmd ) {
1263// case APPCOMMAND_BASS_BOOST:
1264// key = Qt::Key_BassBoost;
1265// break;
1266// case APPCOMMAND_BASS_DOWN:
1267// key = Qt::Key_BassDown;
1268// break;
1269// case APPCOMMAND_BASS_UP:
1270// key = Qt::Key_BassUp;
1271// break;
1272// case APPCOMMAND_BROWSER_BACKWARD:
1273// key = Qt::Key_Back;
1274// break;
1275// case APPCOMMAND_BROWSER_FAVORITES:
1276// key = Qt::Key_Favorites;
1277// break;
1278// case APPCOMMAND_BROWSER_FORWARD:
1279// key = Qt::Key_Forward;
1280// break;
1281// case APPCOMMAND_BROWSER_HOME:
1282// key = Qt::Key_HomePage;
1283// break;
1284// case APPCOMMAND_BROWSER_REFRESH:
1285// key = Qt::Key_Refresh;
1286// break;
1287// case APPCOMMAND_BROWSER_SEARCH:
1288// key = Qt::Key_Search;
1289// break;
1290// case APPCOMMAND_BROWSER_STOP:
1291// key = Qt::Key_Stop;
1292// break;
1293// case APPCOMMAND_LAUNCH_APP1:
1294// key = Qt::Key_Launch0;
1295// break;
1296// case APPCOMMAND_LAUNCH_APP2:
1297// key = Qt::Key_Launch1;
1298// break;
1299// case APPCOMMAND_LAUNCH_MAIL:
1300// key = Qt::Key_LaunchMail;
1301// break;
1302// case APPCOMMAND_LAUNCH_MEDIA_SELECT:
1303// key = Qt::Key_LaunchMedia;
1304// break;
1305// case APPCOMMAND_MEDIA_NEXTTRACK:
1306// key = Qt::Key_MediaNext;
1307// break;
1308// case APPCOMMAND_MEDIA_PLAY_PAUSE:
1309// key = Qt::Key_MediaPlay;
1310// break;
1311// case APPCOMMAND_MEDIA_PREVIOUSTRACK:
1312// key = Qt::Key_MediaPrev;
1313// break;
1314// case APPCOMMAND_MEDIA_STOP:
1315// key = Qt::Key_MediaStop;
1316// break;
1317// case APPCOMMAND_TREBLE_DOWN:
1318// key = Qt::Key_TrebleDown;
1319// break;
1320// case APPCOMMAND_TREBLE_UP:
1321// key = Qt::Key_TrebleUp;
1322// break;
1323// case APPCOMMAND_VOLUME_DOWN:
1324// key = Qt::Key_VolumeDown;
1325// break;
1326// case APPCOMMAND_VOLUME_MUTE:
1327// key = Qt::Key_VolumeMute;
1328// break;
1329// case APPCOMMAND_VOLUME_UP:
1330// key = Qt::Key_VolumeUp;
1331// break;
1332// default:
1333// break;
1334// }
1335// if ( key ) {
1336// bool res = FALSE;
1337// QWidget *g = QWidget::keyboardGrabber();
1338// if ( g )
1339// widget = (QETWidget*)g;
1340// else if ( qApp->focusWidget() )
1341// widget = (QETWidget*)qApp->focusWidget();
1342// else
1343// widget = (QETWidget*)widget->topLevelWidget();
1344// if ( widget->isEnabled() )
1345// res = ((QETWidget*)widget)->sendKeyEvent( QEvent::KeyPress, key, 0, state, FALSE, QString::null, g != 0 );
1346// if ( res )
1347// return TRUE;
1348// }
1349// }
1350// break;
1351//
1352// default:
1353// break;
1354// }
1355//
1356// result = FALSE;
1357// }
1358// break;
1359
1360//@@TODO (dmik):
1361// we can cause WC_FRAME to send equivalents of WM_NCMOUSEMOVE,
1362// but is it really necesary? We already do some similar stuff in WM_HITTEST
1363//#ifndef Q_OS_TEMP
1364// case WM_NCMOUSEMOVE:
1365// {
1366// // span the application wide cursor over the
1367// // non-client area.
1368// QCursor *c = qt_grab_cursor();
1369// if ( !c )
1370// c = QApplication::overrideCursor();
1371// if ( c ) // application cursor defined
1372// SetCursor( c->handle() );
1373// else
1374// result = FALSE;
1375// // generate leave event also when the caret enters
1376// // the non-client area.
1377// qt_dispatchEnterLeave( 0, QWidget::find(curWin) );
1378// curWin = 0;
1379// }
1380// break;
1381//#endif
1382
1383/// @todo (dmik) later
1384// case WM_SETTINGCHANGE:
1385// if ( !msg.wParam ) {
1386// QString area = QT_WA_INLINE( QString::fromUcs2( (unsigned short *)msg.lParam ),
1387// QString::fromLocal8Bit( (char*)msg.lParam ) );
1388// if ( area == "intl" )
1389// QApplication::postEvent( widget, new QEvent( QEvent::LocaleChange ) );
1390// }
1391// break;
1392//
1393//#ifndef Q_OS_TEMP
1394// case WM_NCLBUTTONDBLCLK:
1395// if ( wParam == HTCAPTION ) {
1396// bool window_state_changed = FALSE;
1397// if ( widget->isMaximized() ) {
1398// window_state_changed = TRUE;
1399// widget->clearWState(Qt::WState_Maximized);
1400// } else if (widget->testWFlags(Qt::WStyle_Maximize)){
1401// window_state_changed = TRUE;
1402// widget->setWState(Qt::WState_Maximized);
1403// }
1404//
1405// if (window_state_changed) {
1406// QEvent e(QEvent::WindowStateChange);
1407// qt_sendSpontaneousEvent(widget, &e);
1408// }
1409// }
1410// result = FALSE;
1411// break;
1412//#endif
1413 case WM_PAINT: // paint event
1414 result = widget->translatePaintEvent( qmsg );
1415 break;
1416 case WM_ERASEBACKGROUND: // erase window background
1417#if defined (QT_PM_NO_WIDGETMASK)
1418 // flush WM_PAINT messages here to update window contents
1419 // instantly while tracking the resize frame (normally these
1420 // messages are delivered after the user has stopped resizing
1421 // for some time). this slows down resizing slightly but gives a
1422 // better look (no invalid window contents can be seen during
1423 // resize). the alternative could be to erase the background only,
1424 // but we need to do it for every non-toplevel window, which can
1425 // also be time-consuming (WM_ERASEBACKGROUND is sent to WC_FRAME
1426 // clients only, so we would have to do all calculations ourselves).
1427 WinUpdateWindow( widget->winId() );
1428#else
1429 // We flush WM_PAINT messages in QETWidget::translateConfigEvent().
1430#endif
1431 RETURN( FALSE );
1432 break;
1433 case WM_CALCVALIDRECTS:
1434 // we must always return this value here to cause PM to reposition
1435 // our children accordingly (othwerwise we would have to do it
1436 // ourselves to keep them top-left aligned).
1437 RETURN( CVR_ALIGNLEFT | CVR_ALIGNTOP );
1438 break;
1439
1440 case WM_MOVE: // move window
1441 case WM_SIZE: // resize window
1442 result = widget->translateConfigEvent( qmsg );
1443 break;
1444
1445 case WM_ACTIVATE:
1446#if 0
1447 qDebug( "WM_ACTIVATE: [%s] %d", widget->name(), SHORT1FROMMP(mp1) );
1448#endif
1449 qApp->pmFocus( widget, SHORT1FROMMP(mp1) );
1450 break;
1451
1452 case WM_SETFOCUS:
1453#if 0
1454 qDebug( "WM_SETFOCUS: [%s] %s [%s]", widget->name(),
1455 SHORT1FROMMP(mp2) ? "<=" : "=>",
1456 QWidget::find( (HWND)mp1 ) ? QWidget::find( (HWND)mp1 )->name()
1457 : "{foreign}" );
1458#endif
1459 result = FALSE;
1460 if ( !SHORT1FROMMP(mp2) ) {
1461 // we're losing focus
1462 if ( !QWidget::find( (HWND)mp1 ) ) {
1463 if ( QApplication::activePopupWidget() ) {
1464 // Another application was activated while our popups are open,
1465 // then close all popups. In case some popup refuses to close,
1466 // we give up after 1024 attempts (to avoid an infinite loop).
1467 int maxiter = 1024;
1468 QWidget *popup;
1469 while ( (popup=QApplication::activePopupWidget()) && maxiter-- )
1470 popup->close();
1471 }
1472 if (
1473 // non-Qt ownees of our WC_FRAME window (such as
1474 // FID_SYSMENU) should not cause the focus to be lost.
1475 WinQueryWindow( (HWND)mp1, QW_OWNER ) ==
1476 widget->topLevelWidget()->winFId()
1477 )
1478 break;
1479 if ( !widget->isTopLevel() )
1480 qApp->pmFocus( widget, SHORT1FROMMP(mp2) );
1481 }
1482 }
1483 break;
1484
1485/// @todo (dmik) remove?
1486//#ifndef Q_OS_TEMP
1487// case WM_MOUSEACTIVATE:
1488// {
1489// const QWidget *tlw = widget->topLevelWidget();
1490// // Do not change activation if the clicked widget is inside a floating dock window
1491// if ( tlw->inherits( "QDockWindow" ) && qApp->activeWindow()
1492// && !qApp->activeWindow()->inherits("QDockWindow") )
1493// RETURN(MA_NOACTIVATE);
1494// }
1495// result = FALSE;
1496// break;
1497//#endif
1498
1499 case WM_SHOW:
1500 if ( !SHORT1FROMMP(mp1) && autoCaptureWnd == widget->winId() )
1501 releaseAutoCapture();
1502 result = FALSE;
1503 break;
1504/// @todo (dmik) remove later
1505// case WM_SHOWWINDOW:
1506//#ifndef Q_OS_TEMP
1507// if ( lParam == SW_PARENTOPENING ) {
1508// if ( widget->testWState(Qt::WState_ForceHide) )
1509// RETURN(0);
1510// }
1511//#endif
1512// if (!wParam && autoCaptureWnd == widget->winId())
1513// releaseAutoCapture();
1514// result = FALSE;
1515// break;
1516
1517 case WM_REALIZEPALETTE: // realize own palette
1518 if ( QColor::hPal() ) {
1519 HPS hps = WinGetPS( widget->winId() );
1520 GpiSelectPalette( hps, QColor::hPal() );
1521 ULONG cclr;
1522 WinRealizePalette( widget->winId(), hps, &cclr );
1523 WinReleasePS( hps );
1524 // on OS/2, the value returned by WinRealizePalette() does not
1525 // necessarily reflect the number of colors that have been
1526 // remapped. therefore, we cannot rely on it and must always
1527 // invalidate the window.
1528 WinInvalidateRect( widget->winId(), NULL, TRUE );
1529 RETURN( 0 );
1530 }
1531 break;
1532
1533 case WM_CLOSE: // close window
1534 widget->translateCloseEvent( qmsg );
1535 RETURN(0); // always handled
1536
1537/// @todo (dmik) it seems we don't need this
1538// case WM_DESTROY: // destroy window
1539// if ( hwnd == curWin ) {
1540// QEvent leave( QEvent::Leave );
1541// QApplication::sendEvent( widget, &leave );
1542// curWin = 0;
1543// }
1544// // We are blown away when our parent reparents, so we have to
1545// // recreate the handle
1546// if (widget->testWState(Qt::WState_Created))
1547// ((QETWidget*)widget)->reparentWorkaround();
1548// if ( widget == popupButtonFocus )
1549// popupButtonFocus = 0;
1550// result = FALSE;
1551// break;
1552
1553 case WM_CONTEXTMENU:
1554 if ( SHORT2FROMMP(mp2) ) {
1555 // keyboard event
1556 QWidget *fw = qApp->focusWidget();
1557 if ( fw ) {
1558 QContextMenuEvent e(
1559 QContextMenuEvent::Keyboard,
1560 QPoint( 5, 5 ),
1561 fw->mapToGlobal( QPoint( 5, 5 ) ),
1562 0
1563 );
1564 result = qt_sendSpontaneousEvent( fw, &e );
1565 rc = (MRESULT) result;
1566 }
1567 } else {
1568 // mouse event
1569 result = widget->translateMouseEvent( qmsg );
1570 rc = (MRESULT) result;
1571 }
1572 break;
1573
1574/// @todo (dmik) remove?
1575// case WM_IME_STARTCOMPOSITION:
1576// result = QInputContext::startComposition();
1577// break;
1578// case WM_IME_ENDCOMPOSITION:
1579// result = QInputContext::endComposition();
1580// break;
1581// case WM_IME_COMPOSITION:
1582// result = QInputContext::composition( lParam );
1583// break;
1584
1585#ifndef QT_NO_CLIPBOARD
1586 case WM_DRAWCLIPBOARD:
1587 case WM_RENDERFMT:
1588 case WM_RENDERALLFMTS:
1589 case WM_DESTROYCLIPBOARD:
1590 if ( qt_clipboard ) {
1591 QCustomEvent e( QEvent::Clipboard, &qmsg );
1592 qt_sendSpontaneousEvent( qt_clipboard, &e );
1593 RETURN(0);
1594 }
1595 result = FALSE;
1596 break;
1597#endif
1598
1599/// @todo (dmik) remove? functionality is implemented in WM_SETFOCUS above.
1600// case WM_KILLFOCUS:
1601// if ( !QWidget::find( (HWND)wParam ) ) { // we don't get focus, so unset it now
1602// if ( !widget->hasFocus() ) // work around Windows bug after minimizing/restoring
1603// widget = (QETWidget*)qApp->focusWidget();
1604// HWND focus = ::GetFocus();
1605// if ( !widget || (focus && ::IsChild( widget->winId(), focus )) ) {
1606// result = FALSE;
1607// } else {
1608// widget->clearFocus();
1609// result = TRUE;
1610// }
1611// } else {
1612// result = FALSE;
1613// }
1614// break;
1615
1616//@@TODO (dmik): later
1617// case WM_THEMECHANGED:
1618// if ( widget->testWFlags( Qt::WType_Desktop ) || !qApp || qApp->closingDown()
1619// || qApp->type() == QApplication::Tty )
1620// break;
1621//
1622// if ( widget->testWState(Qt::WState_Polished) )
1623// qApp->style().unPolish(widget);
1624//
1625// if ( widget->testWState(Qt::WState_Polished) )
1626// qApp->style().polish(widget);
1627// widget->repolishStyle( qApp->style() );
1628// if ( widget->isVisible() )
1629// widget->update();
1630// break;
1631//
1632// case WM_COMMAND:
1633// result = (wParam == 0x1);
1634// if ( result )
1635// QApplication::postEvent( widget, new QEvent( QEvent::OkRequest ) );
1636// break;
1637// case WM_HELP:
1638// QApplication::postEvent( widget, new QEvent( QEvent::HelpRequest ) );
1639// result = TRUE;
1640// break;
1641//#endif
1642
1643 case WM_U_MOUSELEAVE:
1644 // We receive a mouse leave for curWin, meaning
1645 // the mouse was moved outside our widgets
1646 if ( widget->winId() == curWin && (HWND) mp1 == curWin ) {
1647 bool dispatch = !widget->hasMouse();
1648 // hasMouse is updated when dispatching enter/leave,
1649 // so test if it is actually up-to-date
1650 if ( !dispatch ) {
1651 QRect geom = widget->geometry();
1652 if ( widget->parentWidget() && !widget->isTopLevel() ) {
1653 QPoint gp = widget->parentWidget()->mapToGlobal( widget->pos() );
1654 geom.setX( gp.x() );
1655 geom.setY( gp.y() );
1656 }
1657 QPoint cpos = QCursor::pos();
1658 dispatch = !geom.contains( cpos );
1659 }
1660 if ( dispatch ) {
1661 qt_dispatchEnterLeave( 0, QWidget::find( (WId)curWin ) );
1662 curWin = 0;
1663 }
1664 }
1665 break;
1666
1667/// @todo (dmik) remove? functionality is implemented in WM_SETFOCUS above.
1668// case WM_CANCELMODE:
1669// if ( qApp->focusWidget() ) {
1670// QFocusEvent::setReason( QFocusEvent::ActiveWindow );
1671// QFocusEvent e( QEvent::FocusOut );
1672// QApplication::sendEvent( qApp->focusWidget(), &e );
1673// QFocusEvent::resetReason();
1674// }
1675// break;
1676
1677 default:
1678 result = FALSE; // event was not processed
1679 break;
1680 }
1681 }
1682
1683 if ( evt_type != QEvent::None ) { // simple event
1684 QEvent e( evt_type );
1685 result = qt_sendSpontaneousEvent( widget, &e );
1686 }
1687 if ( result )
1688 RETURN( rc );
1689
1690do_default:
1691 RETURN( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
1692/// @todo (dmik) remove?
1693// RETURN( QInputContext::DefWindowProc(hwnd,message,wParam,lParam) )
1694}
1695
1696PFNWP QtOldFrameProc = 0;
1697
1698extern "C" MRESULT EXPENTRY QtFrameProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
1699{
1700 // message handling indicators: if result is true at the end of message
1701 // processing, no default window proc is called but rc is returned.
1702 bool result = FALSE;
1703 MRESULT rc = (MRESULT) FALSE;
1704 QETWidget *widget = 0;
1705 HWND hwndC = 0;
1706
1707 if ( !qApp ) // unstable app state
1708 goto do_default;
1709
1710 // make sure we show widgets (e.g. scrollbars) when the user resizes
1711 if ( inLoop && qApp->loopLevel() )
1712 qApp->sendPostedEvents( 0, QEvent::ShowWindowRequest );
1713
1714 inLoop = TRUE;
1715
1716 hwndC = WinWindowFromID( hwnd, FID_CLIENT );
1717 widget = (QETWidget*)QWidget::find( hwndC );
1718 if ( !widget ) // don't know this widget
1719 goto do_default;
1720
1721 switch ( msg ) {
1722 case WM_HITTEST: {
1723 if ( !WinIsWindowEnabled( hwnd ) ) {
1724 if (
1725 qApp->activePopupWidget() &&
1726 (WinQueryQueueStatus( HWND_DESKTOP ) & QS_MOUSEBUTTON)
1727 ) {
1728 // the user has clicked over the Qt window that is disabled
1729 // by some modal widget, therefore we close all popups. In
1730 // case some popup refuses to close, we give up after 1024
1731 // attempts (to avoid an infinite loop).
1732 int maxiter = 1024;
1733 QWidget *popup;
1734 while ( (popup=QApplication::activePopupWidget()) && maxiter-- )
1735 popup->close();
1736 }
1737#ifndef QT_NO_CURSOR
1738 else {
1739 QCursor *c = qt_grab_cursor();
1740 if ( !c )
1741 c = QApplication::overrideCursor();
1742 if ( c ) // application cursor defined
1743 WinSetPointer( HWND_DESKTOP, c->handle() );
1744 else
1745 WinSetPointer( HWND_DESKTOP, Qt::arrowCursor.handle() );
1746 }
1747#endif
1748 }
1749 break;
1750 }
1751
1752 case WM_ADJUSTWINDOWPOS: {
1753 SWP &swp = *(PSWP) mp1;
1754 if ( swp.fl & SWP_MAXIMIZE ) {
1755 QWExtra *x = widget->xtra();
1756 if ( x ) {
1757 result = TRUE;
1758 rc = QtOldFrameProc( hwnd, msg, mp1, mp2 );
1759 int maxw = QWIDGETSIZE_MAX, maxh = QWIDGETSIZE_MAX;
1760 QTLWExtra *top = widget->top();
1761 if ( x->maxw < QWIDGETSIZE_MAX )
1762 maxw = x->maxw + top->fleft + top->fright;
1763 if ( x->maxh < QWIDGETSIZE_MAX )
1764 maxh = x->maxh + top->ftop + top->fbottom;
1765 if ( maxw < QWIDGETSIZE_MAX ) swp.cx = maxw;
1766 if ( maxh < QWIDGETSIZE_MAX ) {
1767 swp.y = swp.y + swp.cy - maxh;
1768 swp.cy = maxh;
1769 }
1770 }
1771 }
1772 if ( (swp.fl & SWP_RESTORE) &&
1773 !(swp.fl & (SWP_MOVE | SWP_SIZE)) ) {
1774 QRect r = widget->top()->normalGeometry;
1775 if ( r.isValid() ) {
1776 // store normal geometry in window words
1777 USHORT x = r.x();
1778 USHORT y = r.y();
1779 USHORT w = r.width();
1780 USHORT h = r.height();
1781 // flip y coordinate
1782 y = QApplication::desktop()->height() - (y + h);
1783 WinSetWindowUShort( hwnd, QWS_XRESTORE, x );
1784 WinSetWindowUShort( hwnd, QWS_YRESTORE, y );
1785 WinSetWindowUShort( hwnd, QWS_CXRESTORE, w );
1786 WinSetWindowUShort( hwnd, QWS_CYRESTORE, h );
1787 widget->top()->normalGeometry.setWidth( 0 );
1788 }
1789 }
1790 if ( swp.fl & (SWP_ACTIVATE | SWP_ZORDER) ) {
1791 // get the modal widget that made this window blocked
1792 QWidget *m =
1793 (QWidget*) WinQueryWindowULong( widget->winId(), QWL_QTMODAL );
1794 if( m ) {
1795 if ( swp.fl & SWP_ACTIVATE ) {
1796 QWidget *a = qt_modal_stack->first();
1797 if ( !a->isActiveWindow() )
1798 a->setActiveWindow();
1799 swp.fl &= ~SWP_ACTIVATE;
1800 }
1801 if ( swp.fl & SWP_ZORDER ) {
1802 QWidget *mp = m->parentWidget();
1803 if ( mp ) {
1804 mp = mp->topLevelWidget();
1805 if ( !mp->isDesktop() && mp != widget )
1806 m = mp;
1807 }
1808 HWND hm = m->winFId();
1809 if ( swp.hwndInsertBehind != hm ) {
1810 swp.hwndInsertBehind = hm;
1811 }
1812 }
1813 }
1814 }
1815 break;
1816 }
1817
1818 case WM_QUERYTRACKINFO: {
1819 QWExtra *x = widget->xtra();
1820 if ( x ) {
1821 result = TRUE;
1822 rc = QtOldFrameProc( hwnd, msg, mp1, mp2 );
1823 PTRACKINFO pti = (PTRACKINFO) mp2;
1824 int minw = 0, minh = 0;
1825 int maxw = QWIDGETSIZE_MAX, maxh = QWIDGETSIZE_MAX;
1826 QTLWExtra *top = widget->top();
1827 if ( x->minw > 0 )
1828 minw = x->minw + top->fleft + top->fright;
1829 if ( x->minh > 0 )
1830 minh = x->minh + top->ftop + top->fbottom;
1831 if ( x->maxw < QWIDGETSIZE_MAX )
1832 maxw = x->maxw + top->fleft + top->fright;
1833 if ( x->maxh < QWIDGETSIZE_MAX )
1834 maxh = x->maxh + top->ftop + top->fbottom;
1835 // obey system recommended minimum size (to emulate Qt/Win32)
1836 pti->ptlMinTrackSize.x = QMAX( minw, pti->ptlMinTrackSize.x );
1837 pti->ptlMinTrackSize.y = QMAX( minh, pti->ptlMinTrackSize.y );
1838 pti->ptlMaxTrackSize.x = maxw;
1839 pti->ptlMaxTrackSize.y = maxh;
1840 }
1841 break;
1842 }
1843
1844 case WM_TRACKFRAME: {
1845 if ( QApplication::activePopupWidget() ) {
1846 // The user starts to size/move the frame window, therefore
1847 // we close all popups. In case some popup refuses to close,
1848 // we give up after 1024 attempts (to avoid an infinite loop).
1849 int maxiter = 1024;
1850 QWidget *popup;
1851 while ( (popup=QApplication::activePopupWidget()) && maxiter-- )
1852 popup->close();
1853 }
1854 break;
1855 }
1856
1857 case WM_WINDOWPOSCHANGED: {
1858 // We detect spontaneous min/max/restore events here instead of
1859 // WM_MINMAXFRAME, because WM_MINMAXFRAME is a pre-process message
1860 // (i.e. no actual changes have been made) We need actual changes
1861 // in order to update the frame strut and send WindowStateChange.
1862 result = TRUE;
1863 rc = QtOldFrameProc( hwnd, msg, mp1, mp2 );
1864 ULONG awp = LONGFROMMP( mp2 );
1865 bool window_state_change = FALSE;
1866 if ( awp & AWP_MAXIMIZED ) {
1867 window_state_change = TRUE;
1868 widget->setWState( Qt::WState_Maximized );
1869 widget->clearWState( Qt::WState_FullScreen );
1870 if ( widget->isMinimized() ) {
1871 widget->clearWState( Qt::WState_Minimized );
1872 widget->showChildren( TRUE );
1873 QShowEvent e;
1874 qt_sendSpontaneousEvent( widget, &e );
1875 }
1876 } else if ( awp & AWP_MINIMIZED ) {
1877 window_state_change = TRUE;
1878 widget->setWState( Qt::WState_Minimized );
1879 widget->clearWState( Qt::WState_Maximized );
1880 widget->clearWState( Qt::WState_FullScreen );
1881 if ( widget->isVisible() ) {
1882 QHideEvent e;
1883 qt_sendSpontaneousEvent( widget, &e );
1884 widget->hideChildren( TRUE );
1885 }
1886 } else if ( awp & AWP_RESTORED ) {
1887 window_state_change = TRUE;
1888 if ( widget->isMinimized() ) {
1889 widget->showChildren( TRUE );
1890 QShowEvent e;
1891 qt_sendSpontaneousEvent( widget, &e );
1892 }
1893 widget->clearWState( Qt::WState_Minimized );
1894 widget->clearWState( Qt::WState_Maximized );
1895 }
1896 if ( window_state_change ) {
1897 widget->updateFrameStrut();
1898 if ( !widget->top()->in_sendWindowState ) {
1899 // send WindowStateChange event if this message is NOT
1900 // originated from QWidget::setWindowState().
1901 QEvent e( QEvent::WindowStateChange );
1902 qt_sendSpontaneousEvent( widget, &e );
1903 }
1904 }
1905 break;
1906 }
1907
1908 default:
1909 break;
1910 }
1911
1912 if ( result )
1913 RETURN( rc );
1914
1915do_default:
1916 RETURN( QtOldFrameProc( hwnd, msg, mp1, mp2 ) );
1917}
1918
1919/*****************************************************************************
1920 Modal widgets; We have implemented our own modal widget mechanism
1921 to get total control.
1922 A modal widget without a parent becomes application-modal.
1923 A modal widget with a parent becomes modal to its parent and grandparents..
1924
1925//@@TODO (dmik): the above comment is not correct (outdated?): for example,
1926// in accordance with the current Qt logic, a modal widget with a parent
1927// becomes modal to its (grand)parents upto the first of them that has the
1928// WGroupLeader flag, not necessarily to all...
1929
1930 qt_enter_modal()
1931 Enters modal state
1932 Arguments:
1933 QWidget *widget A modal widget
1934
1935 qt_leave_modal()
1936 Leaves modal state for a widget
1937 Arguments:
1938 QWidget *widget A modal widget
1939 *****************************************************************************/
1940
1941Q_EXPORT bool qt_modal_state()
1942{
1943 return app_do_modal;
1944}
1945
1946// helper for qt_dispatchBlocked().
1947// sends block events to the given widget and its children.
1948void qt_sendBlocked( QObject *obj, QWidget *modal, QEvent *e, bool override )
1949{
1950 if ( obj == modal ) {
1951 // don't touch modal itself and its children
1952 return;
1953 }
1954 bool blocked = e->type() == QEvent::WindowBlocked;
1955
1956 if ( obj->isWidgetType() ) {
1957 QWidget *w = (QWidget*) obj;
1958 if ( w->isTopLevel() ) {
1959 if ( w->testWFlags( Qt::WGroupLeader ) && !override ) {
1960 // stop sending on group leaders
1961 return;
1962 }
1963 QWidget *blockedBy =
1964 (QWidget*) WinQueryWindowULong( w->winId(), QWL_QTMODAL );
1965 if ( blocked ) {
1966 // stop sending on alreay blocked widgets
1967 if ( blockedBy )
1968 return;
1969 } else {
1970 // stop sending on widgets blocked by another modal
1971 if ( blockedBy != modal )
1972 return;
1973 }
1974 WinSetWindowULong( w->winId(), QWL_QTMODAL,
1975 blocked ? (ULONG) modal : 0 );
1976 WinEnableWindow( w->winFId(), !blocked );
1977 }
1978 }
1979 QApplication::sendEvent( obj, e );
1980
1981 // now send blocked to children
1982 if ( obj->children() ) {
1983 QObjectListIt it( *obj->children() );
1984 QObject *o;
1985 while( ( o = it.current() ) != 0 ) {
1986 ++it;
1987 qt_sendBlocked( o, modal, e, FALSE );
1988 }
1989 }
1990}
1991
1992// sends blocked/unblocked events to top-level widgets depending on the
1993// modal widget given and the WGroupLeader flag presence.
1994static void qt_dispatchBlocked( QWidget *modal, bool blocked )
1995{
1996 // we process those top-level windows that must be blocked
1997 // by the given modal -- this should correlate with the
1998 // qt_tryModalHelper() logic that is widget-centric (i.e. a try
1999 // to block a particular widget given the current set of
2000 // modals) rather than modal-centric (a try to block the current set
2001 // of widgets given a particular modal); currently it blocks events
2002 // for a top-level widget if the widget doesn't have (a parent with
2003 // with) the WGroupLeader flag or it has but (this parent) has a child
2004 // among the current set of modals. So, the modal-centric logic is
2005 // to block any top-level widget unless it has (a parent with) the
2006 // WGroupLeader flag and (this parent) is not (a child of) the modal's
2007 // group leader.
2008
2009 QEvent e( blocked ? QEvent::WindowBlocked : QEvent::WindowUnblocked );
2010
2011 // find the modal's group leader
2012 QWidget *mgl = modal->parentWidget();
2013 while ( mgl && !mgl->testWFlags( Qt::WGroupLeader ) )
2014 mgl = mgl->parentWidget();
2015 if ( mgl ) {
2016 mgl = mgl->topLevelWidget();
2017 if ( mgl->isDesktop() )
2018 mgl = 0;
2019 }
2020
2021 QWidgetList *list = QApplication::topLevelWidgets();
2022 for( QWidget *w = list->first(); w; w = list->next() ) {
2023 if (
2024 !w->isDesktop() && !w->isPopup() && !w->isHidden() &&
2025 !w->testWFlags( Qt::WGroupLeader ) &&
2026 (!w->parentWidget() || w->parentWidget()->isDesktop())
2027 ) {
2028 qt_sendBlocked( w, modal, &e, FALSE );
2029 }
2030 }
2031 delete list;
2032
2033 if ( mgl ) {
2034 // send blocked to modal's group leader
2035 qt_sendBlocked( mgl, modal, &e, TRUE );
2036 }
2037 // qt_tryModalHelper() also assumes that the toppest modal widget blocks
2038 // other modals, regardless of WGroupLeader flags in parents. do the same.
2039 // note: the given modal is not yet at the stack here.
2040 if ( qt_modal_stack ) {
2041 QWidget *m = qt_modal_stack->first();
2042 while ( m ) {
2043 qt_sendBlocked( m, modal, &e, TRUE );
2044 m = qt_modal_stack->next();
2045 }
2046 }
2047}
2048
2049Q_EXPORT void qt_enter_modal( QWidget *widget )
2050{
2051 if ( !qt_modal_stack ) { // create modal stack
2052 qt_modal_stack = new QWidgetList;
2053 Q_CHECK_PTR( qt_modal_stack );
2054 }
2055
2056 if ( qt_modal_stack->containsRef( widget ) )
2057 return; // already modal
2058
2059//@@TODO (dmik): Qt/Win32 sends WindowBlocked/WindowUnblocked events only
2060// to the direct parent of the modal widget. Why? We use qt_dispatchBlocked()
2061// to send them to all windows that do not get input when the given widget
2062// is modal; also we disable/enable that windows there, which is essential
2063// for modality support in Qt/OS2 (code in QtOldFrameProc() and qt_try_modal()
2064// functionality depend on it).
2065//
2066// if (widget->parentWidget()) {
2067// QEvent e(QEvent::WindowBlocked);
2068// QApplication::sendEvent(widget->parentWidget(), &e);
2069// WinEnableWindow( widget->parentWidget()->winFId(), FALSE );
2070// }
2071 qt_dispatchBlocked( widget, TRUE );
2072
2073 releaseAutoCapture();
2074 qt_dispatchEnterLeave( 0, QWidget::find((WId)curWin));
2075 qt_modal_stack->insert( 0, widget );
2076 app_do_modal = TRUE;
2077 curWin = 0;
2078 qt_button_down = 0;
2079 ignoreNextMouseReleaseEvent = FALSE;
2080}
2081
2082
2083Q_EXPORT void qt_leave_modal( QWidget *widget )
2084{
2085 if ( qt_modal_stack && qt_modal_stack->removeRef(widget) ) {
2086 if ( qt_modal_stack->isEmpty() ) {
2087 delete qt_modal_stack;
2088 qt_modal_stack = 0;
2089 QPoint p( QCursor::pos() );
2090 app_do_modal = FALSE; // necessary, we may get recursively into qt_try_modal below
2091 QWidget* w = QApplication::widgetAt( p.x(), p.y(), TRUE );
2092 qt_dispatchEnterLeave( w, QWidget::find( curWin ) ); // send synthetic enter event
2093 curWin = w? w->winId() : 0;
2094 }
2095 ignoreNextMouseReleaseEvent = TRUE;
2096
2097 qt_dispatchBlocked( widget, FALSE );
2098 }
2099 app_do_modal = qt_modal_stack != 0;
2100
2101//@@TODO (dmik): see the comments inside qt_enter_modal()
2102//
2103// if (widget->parentWidget()) {
2104// WinEnableWindow( widget->parentWidget()->winFId(), TRUE );
2105// QEvent e(QEvent::WindowUnblocked);
2106// QApplication::sendEvent(widget->parentWidget(), &e);
2107// }
2108}
2109
2110static bool qt_blocked_modal( QWidget *widget )
2111{
2112 if ( !app_do_modal )
2113 return FALSE;
2114 if ( qApp->activePopupWidget() )
2115 return FALSE;
2116 if ( widget->testWFlags(Qt::WStyle_Tool) ) // allow tool windows
2117 return FALSE;
2118
2119 QWidget *modal=0, *top=qt_modal_stack->getFirst();
2120
2121 widget = widget->topLevelWidget();
2122 if ( widget->testWFlags(Qt::WShowModal) ) // widget is modal
2123 modal = widget;
2124 if ( !top || modal == top ) // don't block event
2125 return FALSE;
2126 return TRUE;
2127}
2128
2129static bool qt_try_modal( QWidget *widget, QMSG *qmsg, int &ret )
2130{
2131 QWidget * top = 0;
2132
2133 if ( qt_tryModalHelper( widget, &top ) )
2134 return TRUE;
2135
2136 bool block_event = FALSE;
2137 ULONG type = qmsg->msg;
2138
2139 if ( type == WM_CLOSE ) {
2140 block_event = TRUE;
2141 }
2142
2143 return !block_event;
2144}
2145
2146
2147/*****************************************************************************
2148 Popup widget mechanism
2149
2150 openPopup()
2151 Adds a widget to the list of popup widgets
2152 Arguments:
2153 QWidget *widget The popup widget to be added
2154
2155 closePopup()
2156 Removes a widget from the list of popup widgets
2157 Arguments:
2158 QWidget *widget The popup widget to be removed
2159 *****************************************************************************/
2160
2161void QApplication::openPopup( QWidget *popup )
2162{
2163 if ( !popupWidgets ) { // create list
2164 popupWidgets = new QWidgetList;
2165 Q_CHECK_PTR( popupWidgets );
2166 }
2167 popupWidgets->append( popup ); // add to end of list
2168 if ( !popup->isEnabled() )
2169 return;
2170
2171 if ( popupWidgets->count() == 1 && !qt_nograb() )
2172 setAutoCapture( popup->winId() ); // grab mouse/keyboard
2173 // Popups are not focus-handled by the window system (the first
2174 // popup grabbed the keyboard), so we have to do that manually: A
2175 // new popup gets the focus
2176 QFocusEvent::setReason( QFocusEvent::Popup );
2177 if ( popup->focusWidget())
2178 popup->focusWidget()->setFocus();
2179 else
2180 popup->setFocus();
2181 QFocusEvent::resetReason();
2182}
2183
2184void QApplication::closePopup( QWidget *popup )
2185{
2186 if ( !popupWidgets )
2187 return;
2188 popupWidgets->removeRef( popup );
2189 POINTL curPos;
2190 WinQueryPointerPos( HWND_DESKTOP, &curPos );
2191 // flip y coordinate
2192 curPos.y = desktop()->height() - (curPos.y + 1);
2193 replayPopupMouseEvent = !popup->geometry().contains( QPoint(curPos.x, curPos.y) );
2194 if ( popupWidgets->count() == 0 ) { // this was the last popup
2195 popupCloseDownMode = TRUE; // control mouse events
2196 delete popupWidgets;
2197 popupWidgets = 0;
2198 if ( !popup->isEnabled() )
2199 return;
2200 if ( !qt_nograb() ) // grabbing not disabled
2201 releaseAutoCapture();
2202 if ( active_window ) {
2203 QFocusEvent::setReason( QFocusEvent::Popup );
2204 if ( active_window->focusWidget() )
2205 active_window->focusWidget()->setFocus();
2206 else
2207 active_window->setFocus();
2208 QFocusEvent::resetReason();
2209 }
2210 } else {
2211 // Popups are not focus-handled by the window system (the
2212 // first popup grabbed the keyboard), so we have to do that
2213 // manually: A popup was closed, so the previous popup gets
2214 // the focus.
2215 QFocusEvent::setReason( QFocusEvent::Popup );
2216 QWidget* aw = popupWidgets->getLast();
2217 if ( popupWidgets->count() == 1 )
2218 setAutoCapture( aw->winId() );
2219 if (aw->focusWidget())
2220 aw->focusWidget()->setFocus();
2221 else
2222 aw->setFocus();
2223 QFocusEvent::resetReason();
2224 }
2225}
2226
2227
2228
2229/*****************************************************************************
2230 Event translation; translates OS/2 PM events to Qt events
2231 *****************************************************************************/
2232
2233// State holder for LWIN/RWIN and ALTGr keys
2234// (ALTGr is also necessary since OS/2 doesn't report ALTGr as KC_ALT)
2235static int qt_extraKeyState = 0;
2236
2237static int mouseButtonState()
2238{
2239 int state = 0;
2240
2241 if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON1 ) & 0x8000 )
2242 state |= Qt::LeftButton;
2243 if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON2 ) & 0x8000 )
2244 state |= Qt::RightButton;
2245 if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON3 ) & 0x8000 )
2246 state |= Qt::MidButton;
2247
2248 return state;
2249}
2250
2251//
2252// Auto-capturing for mouse press and mouse release
2253//
2254
2255static void setAutoCapture( HWND h )
2256{
2257 if ( autoCaptureWnd )
2258 releaseAutoCapture();
2259 autoCaptureWnd = h;
2260
2261 if ( !mouseButtonState() ) {
2262 // all buttons released, we don't actually capture the mouse
2263 // (see QWidget::translateMouseEvent())
2264 autoCaptureReleased = TRUE;
2265 } else {
2266 autoCaptureReleased = FALSE;
2267 WinSetCapture( HWND_DESKTOP, h );
2268 }
2269}
2270
2271static void releaseAutoCapture()
2272{
2273 if ( autoCaptureWnd ) {
2274 if ( !autoCaptureReleased ) {
2275 WinSetCapture( HWND_DESKTOP, 0 );
2276 autoCaptureReleased = TRUE;
2277 }
2278 autoCaptureWnd = 0;
2279 }
2280}
2281
2282
2283//
2284// Mouse event translation
2285//
2286
2287static ushort mouseTbl[] = {
2288 WM_MOUSEMOVE, QEvent::MouseMove, 0,
2289 WM_BUTTON1DOWN, QEvent::MouseButtonPress, Qt::LeftButton,
2290 WM_BUTTON1UP, QEvent::MouseButtonRelease, Qt::LeftButton,
2291 WM_BUTTON1DBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
2292 WM_BUTTON2DOWN, QEvent::MouseButtonPress, Qt::RightButton,
2293 WM_BUTTON2UP, QEvent::MouseButtonRelease, Qt::RightButton,
2294 WM_BUTTON2DBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
2295 WM_BUTTON3DOWN, QEvent::MouseButtonPress, Qt::MidButton,
2296 WM_BUTTON3UP, QEvent::MouseButtonRelease, Qt::MidButton,
2297 WM_BUTTON3DBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
2298//@@TODO (dmik): later (extra buttons)
2299// WM_XBUTTONDOWN, QEvent::MouseButtonPress, Qt::MidButton*2, //### Qt::XButton1/2
2300// WM_XBUTTONUP, QEvent::MouseButtonRelease, Qt::MidButton*2,
2301// WM_XBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton*2,
2302 WM_CONTEXTMENU, QEvent::ContextMenu, 0,
2303 0, 0, 0
2304};
2305
2306static int translateButtonState( USHORT s, int type, int button )
2307{
2308 int bst = mouseButtonState();
2309
2310 if ( type == QEvent::ContextMenu ) {
2311 if ( WinGetKeyState( HWND_DESKTOP, VK_SHIFT ) & 0x8000 )
2312 bst |= Qt::ShiftButton;
2313 if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 )
2314 bst |= Qt::AltButton;
2315 if ( WinGetKeyState( HWND_DESKTOP, VK_CTRL ) & 0x8000 )
2316 bst |= Qt::ControlButton;
2317 } else {
2318 if ( s & KC_SHIFT )
2319 bst |= Qt::ShiftButton;
2320 if ( (s & KC_ALT) )
2321 bst |= Qt::AltButton;
2322 if ( s & KC_CTRL )
2323 bst |= Qt::ControlButton;
2324 }
2325 if ( (qt_extraKeyState & Qt::AltButton) )
2326 bst |= Qt::AltButton;
2327 if ( qt_extraKeyState & Qt::MetaButton )
2328 bst |= Qt::MetaButton;
2329
2330 // Translate from OS/2-style "state after event"
2331 // to X-style "state before event"
2332 if ( type == QEvent::MouseButtonPress ||
2333 type == QEvent::MouseButtonDblClick )
2334 bst &= ~button;
2335 else if ( type == QEvent::MouseButtonRelease )
2336 bst |= button;
2337
2338 return bst;
2339}
2340
2341/*! \internal
2342 In DnD, the mouse release event never appears, so the
2343 mouse button state machine must be manually reset
2344*/
2345void qt_pmMouseButtonUp()
2346{
2347 // release any stored mouse capture
2348 qt_button_down = 0;
2349 autoCaptureReleased = TRUE;
2350 releaseAutoCapture();
2351}
2352
2353bool QETWidget::translateMouseEvent( const QMSG &qmsg )
2354{
2355#if 0
2356 static const char *msgNames[] = { // 11 items
2357 "WM_MOUSEMOVE",
2358 "WM_BUTTON1DOWN", "WM_BUTTON1UP", "WM_BUTTON1DBLCLK",
2359 "WM_BUTTON2DOWN", "WM_BUTTON2UP", "WM_BUTTON2DBLCLK",
2360 "WM_BUTTON3DOWN", "WM_BUTTON3UP", "WM_BUTTON3DBLCLK",
2361 "WM_???"
2362 };
2363 int msgIdx = qmsg.msg - WM_MOUSEMOVE;
2364 if (msgIdx < 0 || msgIdx > 9)
2365 msgIdx = 10;
2366 qDebug( "%s (%04lX): [%08lX/%p:%s/%s] %04hd,%04hd hit=%04hX fl=%04hX",
2367 msgNames[msgIdx], qmsg.msg, qmsg.hwnd, this, name(), className(),
2368 SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1),
2369 SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
2370#endif
2371
2372 static QPoint pos; // window pos (y flipped)
2373 static POINTL gpos = { -1, -1 }; // global pos (y flipped)
2374 QEvent::Type type; // event parameters
2375 int button;
2376 int state;
2377 int i;
2378
2379 // candidate for a double click event
2380 static HWND dblClickCandidateWin = 0;
2381
2382 if ( sm_blockUserInput ) //block user interaction during session management
2383 return TRUE;
2384
2385 // Compress mouse move events
2386 if ( qmsg.msg == WM_MOUSEMOVE ) {
2387 QMSG mouseMsg;
2388 mouseMsg.msg = WM_NULL;
2389 while (
2390 WinPeekMsg( 0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
2391 WM_MOUSEMOVE, PM_NOREMOVE )
2392 ) {
2393 if ( mouseMsg.mp2 != qmsg.mp2 )
2394 break; // leave the message in the queue because
2395 // the key state has changed
2396 // Remove the mouse move message
2397 WinPeekMsg( 0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
2398 WM_MOUSEMOVE, PM_REMOVE );
2399 }
2400 // Update the passed in QMSG structure with the
2401 // most recent one.
2402 if ( mouseMsg.msg != WM_NULL ) {
2403 PQMSG pqmsg = (PQMSG)&qmsg;
2404 pqmsg->mp1 = mouseMsg.mp1;
2405 pqmsg->mp2 = mouseMsg.mp2;
2406 pqmsg->time = mouseMsg.time;
2407 pqmsg->ptl.x = (short)SHORT1FROMMP(mouseMsg.mp1);
2408 pqmsg->ptl.y = (short)SHORT2FROMMP(mouseMsg.mp1);
2409 WinMapWindowPoints( pqmsg->hwnd, HWND_DESKTOP, &pqmsg->ptl, 1 );
2410 // flip y coordinate
2411 pqmsg->ptl.y = QApplication::desktop()->height() - (pqmsg->ptl.y + 1);
2412 }
2413 }
2414
2415 for ( i = 0; mouseTbl[i] && (ULONG)mouseTbl[i] != qmsg.msg; i += 3 )
2416 ;
2417 if ( !mouseTbl[i] )
2418 return FALSE;
2419
2420 type = (QEvent::Type)mouseTbl[++i]; // event type
2421 button = mouseTbl[++i]; // which button
2422/// @todo (dmik) later (extra buttons)
2423// if ( button > Qt::MidButton ) {
2424// switch( GET_XBUTTON_WPARAM( msg.wParam ) ) {
2425// case XBUTTON1:
2426// button = Qt::MidButton*2; //### XButton1;
2427// break;
2428// case XBUTTON2:
2429// button = Qt::MidButton*4; //### XButton2;
2430// break;
2431// }
2432// }
2433 state = translateButtonState( SHORT2FROMMP(qmsg.mp2), type, button ); // button state
2434
2435 // It seems, that PM remembers only the WM_BUTTONxDOWN message (instead of
2436 // the WM_BUTTONxDOWN + WM_BUTTONxUP pair) to detect whether the next button
2437 // press should be converted to WM_BUTTONxDBLCLK or not. As a result, the
2438 // window gets WM_BUTTONxDBLCLK even if it didn't receive the preceeding
2439 // WM_BUTTONxUP (this happens if we issue WinSetCapture() on the first
2440 // WM_BUTTONxDOWN), which is obviously wrong and makes problems for QWorkspace
2441 // and QTitleBar system menu handlers that don't expect a double click after
2442 // they opened a popup menu. dblClickCandidateWin is reset to 0 (see a ***
2443 // remmark below) when WinSetCapture is issued that directs messages
2444 // to a window other than one received the first WM_BUTTONxDOWN,
2445 // so we can fix it here. Note that if there is more than one popup window,
2446 // WinSetCapture is issued only for the first of them, so this code doesn't
2447 // prevent MouseButtonDblClick from being delivered to a popup when another
2448 // popup gets closed on the first WM_BUTTONxDOWN (Qt/Win32 behaves in the
2449 // same way, so it's left for compatibility).
2450 if ( type == QEvent::MouseButtonPress ) {
2451 dblClickCandidateWin = qmsg.hwnd;
2452 } else if ( type == QEvent::MouseButtonDblClick ) {
2453 if ( dblClickCandidateWin != qmsg.hwnd )
2454 type = QEvent::MouseButtonPress;
2455 dblClickCandidateWin = 0;
2456 }
2457
2458 if ( type == QEvent::ContextMenu ) {
2459 QPoint g = QPoint( qmsg.ptl.x, qmsg.ptl.y );
2460 QContextMenuEvent e( QContextMenuEvent::Mouse, mapFromGlobal( g ), g, state );
2461 QApplication::sendSpontaneousEvent( this, &e );
2462 return TRUE;
2463 }
2464
2465 if ( type == QEvent::MouseMove ) {
2466 if ( !(state & MouseButtonMask) )
2467 qt_button_down = 0;
2468#ifndef QT_NO_CURSOR
2469 QCursor *c = qt_grab_cursor();
2470 if ( !c )
2471 c = QApplication::overrideCursor();
2472 if ( c ) // application cursor defined
2473 WinSetPointer( HWND_DESKTOP, c->handle() );
2474 else if ( isEnabled() ) // use widget cursor if widget is enabled
2475 WinSetPointer( HWND_DESKTOP, cursor().handle() );
2476 else {
2477 QWidget *parent = parentWidget();
2478 while ( parent && !parent->isEnabled() )
2479 parent = parent->parentWidget();
2480 if ( parent )
2481 WinSetPointer( HWND_DESKTOP, parent->cursor().handle() );
2482 }
2483#else
2484 // pass the msg to the default proc to let it change the pointer shape
2485 WinDefWindowProc( qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2 );
2486#endif
2487 if ( curWin != winId() ) { // new current window
2488/// @todo (dmik)
2489// add CS_HITTEST to our window classes and handle WM_HITTEST,
2490// otherwise disabled windows will not get mouse events?
2491 qt_dispatchEnterLeave( this, QWidget::find(curWin) );
2492 curWin = winId();
2493 }
2494
2495 // *** PM posts a dummy WM_MOUSEMOVE message (with the same, uncahnged
2496 // pointer coordinates) after every WinSetCapture that actually changes
2497 // the capture target. I.e., if the argument of WinSetCapture is
2498 // NULLHANDLE, a window under the mouse pointer gets this message,
2499 // otherwise the specified window gets it unless it is already under the
2500 // pointer. We use this info to check whether the window can be a double
2501 // click candidate (see above).
2502 if ( qmsg.ptl.x == gpos.x && qmsg.ptl.y == gpos.y ) {
2503 if ( dblClickCandidateWin != qmsg.hwnd )
2504 dblClickCandidateWin = 0;
2505 return TRUE;
2506 }
2507
2508 gpos = qmsg.ptl;
2509
2510 if ( state == 0 && autoCaptureWnd == 0 && !hasMouseTracking() &&
2511 !QApplication::hasGlobalMouseTracking() )
2512 return TRUE; // no button
2513
2514 pos = mapFromGlobal( QPoint(gpos.x, gpos.y) );
2515 } else {
2516 if ( type == QEvent::MouseButtonPress && !isActiveWindow() )
2517 setActiveWindow();
2518
2519 gpos = qmsg.ptl;
2520 pos = mapFromGlobal( QPoint(gpos.x, gpos.y) );
2521
2522 if ( type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick ) { // mouse button pressed
2523 // Magic for masked widgets
2524 qt_button_down = findChildWidget( this, pos );
2525 if ( !qt_button_down || !qt_button_down->testWFlags(WMouseNoMask) )
2526 qt_button_down = this;
2527 }
2528 }
2529
2530 // detect special button states
2531 enum { Other, SinglePressed, AllReleased } btnState = Other;
2532 int bs = state & MouseButtonMask;
2533 if ( (type == QEvent::MouseButtonPress ||
2534 type == QEvent::MouseButtonDblClick) && bs == 0
2535 ) {
2536 btnState = SinglePressed;
2537 } else if ( type == QEvent::MouseButtonRelease && bs == button ) {
2538 btnState = AllReleased;
2539 }
2540
2541 if ( qApp->inPopupMode() ) { // in popup mode
2542 if ( !autoCaptureReleased && btnState == AllReleased ) {
2543 // in order to give non-Qt windows the opportunity to see mouse
2544 // messages while our popups are active we need to release the
2545 // mouse capture which is absolute in OS/2. we do it directly
2546 // (not through releaseAutoCapture()) in order to keep
2547 // autoCaptureWnd nonzero to keep forwarding mouse move events
2548 // (actually sent to one of Qt widgets) to the active popup.
2549 autoCaptureReleased = TRUE;
2550 WinSetCapture( HWND_DESKTOP, 0 );
2551 } else if ( autoCaptureReleased && btnState == SinglePressed ) {
2552 // set the mouse capture back if a button is pressed.
2553 if ( autoCaptureWnd ) {
2554 autoCaptureReleased = FALSE;
2555 WinSetCapture( HWND_DESKTOP, autoCaptureWnd );
2556 }
2557 }
2558
2559 replayPopupMouseEvent = FALSE;
2560 QWidget* activePopupWidget = qApp->activePopupWidget();
2561 QWidget *popup = activePopupWidget;
2562
2563 if ( popup != this ) {
2564 if ( testWFlags(WType_Popup) && rect().contains(pos) )
2565 popup = this;
2566 else // send to last popup
2567 pos = popup->mapFromGlobal( QPoint(gpos.x, gpos.y) );
2568 }
2569 QWidget *popupChild = findChildWidget( popup, pos );
2570 bool releaseAfter = FALSE;
2571 switch ( type ) {
2572 case QEvent::MouseButtonPress:
2573 case QEvent::MouseButtonDblClick:
2574 popupButtonFocus = popupChild;
2575 break;
2576 case QEvent::MouseButtonRelease:
2577 releaseAfter = TRUE;
2578 break;
2579 default:
2580 break; // nothing for mouse move
2581 }
2582
2583 if ( popupButtonFocus ) {
2584 QMouseEvent e( type,
2585 popupButtonFocus->mapFromGlobal(QPoint(gpos.x,gpos.y)),
2586 QPoint(gpos.x,gpos.y), button, state );
2587 QApplication::sendSpontaneousEvent( popupButtonFocus, &e );
2588 if ( releaseAfter ) {
2589 popupButtonFocus = 0;
2590 }
2591 } else if ( popupChild ) {
2592 QMouseEvent e( type,
2593 popupChild->mapFromGlobal(QPoint(gpos.x,gpos.y)),
2594 QPoint(gpos.x,gpos.y), button, state );
2595 QApplication::sendSpontaneousEvent( popupChild, &e );
2596 } else {
2597 QMouseEvent e( type, pos, QPoint(gpos.x,gpos.y), button, state );
2598 QApplication::sendSpontaneousEvent( popup, &e );
2599 }
2600
2601 if ( releaseAfter )
2602 qt_button_down = 0;
2603
2604 if ( type == QEvent::MouseButtonPress
2605 && qApp->activePopupWidget() != activePopupWidget
2606 && replayPopupMouseEvent ) {
2607 // the popup dissappeared. Replay the event
2608 QWidget* w = QApplication::widgetAt( gpos.x, gpos.y, TRUE );
2609 if ( w && !qt_blocked_modal( w ) ) {
2610 QPoint wpos = w->mapFromGlobal(QPoint(gpos.x, gpos.y));
2611 // flip y coordinate
2612 wpos.ry() = w->height() - (wpos.y() + 1);
2613 // Note: it's important to post this message rather than send:
2614 // QPushButton::popupPressed() depends on this so that
2615 // popup->exec() must return before this message is delivered
2616 // as QWidget::keyPressEvent().
2617 WinPostMsg( w->winId(), qmsg.msg,
2618 MPFROM2SHORT( wpos.x(), wpos.y() ), qmsg.mp2 );
2619 }
2620 }
2621 } else { // not popup mode
2622 if ( btnState == SinglePressed && QWidget::mouseGrabber() == 0 )
2623 setAutoCapture( winId() );
2624 else if ( btnState == AllReleased && QWidget::mouseGrabber() == 0 )
2625 releaseAutoCapture();
2626
2627 QWidget *widget = this;
2628 QWidget *w = QWidget::mouseGrabber();
2629 if ( !w )
2630 w = qt_button_down;
2631 if ( w && w != this ) {
2632 widget = w;
2633 pos = w->mapFromGlobal(QPoint(gpos.x, gpos.y));
2634 }
2635
2636 if ( type == QEvent::MouseButtonRelease &&
2637 (state & (~button) & ( MouseButtonMask )) == 0 ) {
2638 qt_button_down = 0;
2639 }
2640
2641 QMouseEvent e( type, pos, QPoint(gpos.x,gpos.y), button, state );
2642 QApplication::sendSpontaneousEvent( widget, &e );
2643
2644 if ( type != QEvent::MouseMove )
2645 pos.rx() = pos.ry() = -9999; // init for move compression
2646 }
2647 return TRUE;
2648}
2649
2650
2651//
2652// Keyboard event translation
2653//
2654
2655static const ushort KeyTbl[] = { // keyboard mapping table
2656 VK_ESC, Qt::Key_Escape, // misc keys
2657 VK_TAB, Qt::Key_Tab,
2658 VK_BACKTAB, Qt::Key_Backtab,
2659 VK_BACKSPACE, Qt::Key_Backspace,
2660 VK_ENTER, Qt::Key_Enter,
2661 VK_NEWLINE, Qt::Key_Return,
2662 VK_INSERT, Qt::Key_Insert,
2663 VK_DELETE, Qt::Key_Delete,
2664 VK_CLEAR, Qt::Key_Clear,
2665 VK_PAUSE, Qt::Key_Pause,
2666 VK_PRINTSCRN, Qt::Key_Print,
2667 VK_SPACE, Qt::Key_Space,
2668 VK_HOME, Qt::Key_Home, // cursor movement
2669 VK_END, Qt::Key_End,
2670 VK_LEFT, Qt::Key_Left,
2671 VK_UP, Qt::Key_Up,
2672 VK_RIGHT, Qt::Key_Right,
2673 VK_DOWN, Qt::Key_Down,
2674 VK_PAGEUP, Qt::Key_Prior,
2675 VK_PAGEDOWN, Qt::Key_Next,
2676 VK_SHIFT, Qt::Key_Shift, // modifiers
2677 VK_CTRL, Qt::Key_Control,
2678 VK_ALT, Qt::Key_Alt,
2679 VK_CAPSLOCK, Qt::Key_CapsLock,
2680 VK_NUMLOCK, Qt::Key_NumLock,
2681 VK_SCRLLOCK, Qt::Key_ScrollLock,
2682 0, 0
2683};
2684
2685// when the compatibility mode is FALSE Qt/OS2 uses the following rule
2686// to calculate QKeyEvent::key() codes when an alpha-numeric key is
2687// pressed: key code is the ASCII (Latin 1) character code of that key as if
2688// there were no any keyboard modifiers (CTRL, SHIFT, ALT) pressed, with the
2689// exception that alpha characters are uppercased.
2690// when the compatibility mode is TRUE Qt/OS2 behaves mostly like Qt/Win32.
2691Q_EXPORT bool qt_kbd_compatibility = TRUE;
2692
2693/// @todo (dmik) currentlly, qt_kbd_compatibility is TRUE because
2694// qt_scan2Ascii function below is not well implemented yet (in particular,
2695// it uses the 850 code page that may not be available on some systems...).
2696// Once we find a way to translate scans to US ASCII regardless of the current
2697// code page and/or NLS state (keyboard layout), qt_kbd_compatibility may be
2698// set to FALSE. This, in particular, will enable more correct handling of
2699// Alt+letter combinations when the keyboard is in the NLS state:
2700// QKeyEvent::key() will return a non-null Qt::Key_XXX code corresponding to
2701// the ASCII code of a pressed key, which in turn will let Qt process latin
2702// Alt+letter shortcuts in the NLS keyboard mode together with Alt+NLS_letter
2703// shortcuts (nice feature imho). Note that Alt+NLS_letter shortcuts are
2704// correctly processed in any case.
2705
2706// cache table to store Qt::Key_... values for 256 hardware scancodes
2707// (even byte is for non-shifted keys, odd byte is for shifted ones).
2708// used to decrease the number of calls to KbdXlate.
2709static uchar ScanTbl[512] = { 0xFF };
2710
2711static uchar qt_scan2Ascii( uchar scan, bool shift )
2712{
2713 uchar ascii = 0;
2714 HFILE kbd;
2715 ULONG dummy;
2716 DosOpen( "KBD$", &kbd, &dummy, 0,
2717 FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
2718 OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL );
2719 // parameter packet
2720 struct CPID {
2721 USHORT idCodePage;
2722 USHORT reserved;
2723 } cpid = { 850, 0 };
2724 ULONG szCpid = sizeof(CPID);
2725 // data packet
2726 KBDTRANS kt;
2727 ULONG szKt = sizeof(KBDTRANS);
2728 // reset all kbd states and modifiers
2729 memset( &kt, 0, szKt );
2730 // reflect Shift state to distinguish between [ and { etc.
2731 if ( qt_kbd_compatibility && shift )
2732 kt.fsState = KBDSTF_RIGHTSHIFT;
2733 kt.chScan = scan;
2734 DosDevIOCtl( kbd, IOCTL_KEYBOARD, KBD_XLATESCAN,
2735 &cpid, szCpid, &szCpid, &kt, szKt, &szKt );
2736 // store in cache
2737 uint idx = scan << 1;
2738 if ( qt_kbd_compatibility && shift )
2739 idx++;
2740 ascii = ScanTbl[idx] = toupper( kt.chChar );
2741 DosClose( kbd );
2742 return ascii;
2743}
2744
2745// translates WM_CHAR to Qt::Key_..., ascii, state and text
2746static void translateKeyCode( CHRMSG &chm, int &code, int &ascii, int &state,
2747 QString &text )
2748{
2749 if ( chm.fs & KC_SHIFT )
2750 state |= Qt::ShiftButton;
2751 if ( chm.fs & KC_CTRL )
2752 state |= Qt::ControlButton;
2753 if ( chm.fs & KC_ALT )
2754 state |= Qt::AltButton;
2755 if ( qt_extraKeyState & Qt::MetaButton )
2756 state |= Qt::MetaButton;
2757
2758 unsigned char ch = chm.chr;
2759
2760 if ( chm.fs & KC_VIRTUALKEY ) {
2761 if ( !chm.vkey ) {
2762 // The only known situation when KC_VIRTUALKEY is present but
2763 // vkey is zero is when Alt+Shift is pressed to switch the
2764 // keyboard layout state from latin to national and back.
2765 // It seems that this way the system informs applications about
2766 // layout changes: chm.chr is 0xF1 when the user switches
2767 // to the national layout (i.e. presses Alt + Left Shift)
2768 // and it is 0xF0 when he switches back (presses Alt + Right Shift).
2769 // We assume this and restore fs, vkey, scancode and chr accordingly.
2770 if ( chm.chr == 0xF0 || chm.chr == 0xF1 ) {
2771 chm.fs |= KC_ALT | KC_SHIFT;
2772 chm.vkey = VK_SHIFT;
2773 chm.scancode = chm.chr == 0xF1 ? 0x2A : 0x36;
2774 chm.chr = ch = 0;
2775 state |= Qt::AltButton | Qt::ShiftButton;
2776 // code will be assigned by the normal procedure below
2777 }
2778 }
2779 if ( chm.vkey >= VK_F1 && chm.vkey <= VK_F24 ) {
2780 // function keys
2781 code = Qt::Key_F1 + (chm.vkey - VK_F1);
2782 } else if ( chm.vkey == VK_ALTGRAF ) {
2783 code = Qt::Key_Alt;
2784 if ( !(chm.fs & KC_KEYUP) )
2785 qt_extraKeyState |= Qt::AltButton;
2786 else
2787 qt_extraKeyState &= ~Qt::AltButton;
2788 } else {
2789 // any other keys
2790 int i = 0;
2791 while ( KeyTbl[i] ) {
2792 if ( chm.vkey == (int)KeyTbl[i] ) {
2793 code = KeyTbl[i+1];
2794 break;
2795 }
2796 i += 2;
2797 }
2798 }
2799 } else {
2800 if ( qt_kbd_compatibility && ch && ch < 0x80 ) {
2801 code = toupper( ch );
2802 } else if ( !qt_kbd_compatibility && (chm.fs & KC_CHAR) && isalpha( ch ) ) {
2803 code = toupper( ch );
2804 } else {
2805 // detect some special keys that have a pseudo char code
2806 // in the high byte of chm.chr (probably this is less
2807 // device-dependent than scancode)
2808 switch ( chm.chr ) {
2809 case 0xEC00: // LWIN
2810 case 0xED00: // RWIN
2811 code = Qt::Key_Meta;
2812 if ( !(chm.fs & KC_KEYUP) )
2813 qt_extraKeyState |= Qt::MetaButton;
2814 else
2815 qt_extraKeyState &= ~Qt::MetaButton;
2816 break;
2817 case 0xEE00: // WINAPP (menu with arrow)
2818 code = Qt::Key_Menu;
2819 break;
2820 case 0x5600: // additional '\' (0x56 is actually its scancode)
2821 ch = state & Qt::ShiftButton ? '|' : '\\';
2822 if ( qt_kbd_compatibility ) code = ch;
2823 else code = '\\';
2824 break;
2825 default:
2826 // break if qt_kbd_compatibility = TRUE to avoid using
2827 // qt_scan2Ascii(), see comments to qt_kbd_compatibility
2828 if ( qt_kbd_compatibility ) break;
2829 // deduce Qt::Key... from scancode
2830 if ( ScanTbl[0] == 0xFF )
2831 memset( &ScanTbl, 0, sizeof(ScanTbl) );
2832 uint idx = chm.scancode << 1;
2833 if ( qt_kbd_compatibility && (state & Qt::ShiftButton) )
2834 idx++;
2835 code = ScanTbl[idx];
2836 if ( !code )
2837 // not found in cache
2838 code = qt_scan2Ascii( chm.scancode, (state & Qt::ShiftButton) );
2839 break;
2840 }
2841 }
2842 }
2843 // check extraState AFTER updating it
2844 if ( qt_extraKeyState & Qt::AltButton )
2845 state |= Qt::AltButton;
2846
2847 // detect numeric keypad keys
2848 if ( chm.vkey == VK_ENTER || chm.vkey == VK_NUMLOCK ) {
2849 // these always come from the numpad
2850 state |= Qt::Keypad;
2851 } else if (
2852 ((chm.vkey >= VK_PAGEUP && chm.vkey <= VK_DOWN) ||
2853 chm.vkey == VK_INSERT || chm.vkey == VK_DELETE)
2854 ) {
2855 if ( ch != 0xE0 ) {
2856 state |= Qt::Keypad;
2857 if ( ch ) {
2858 // override code to make it Qt::Key_0..Qt::Key_9 etc.
2859 code = toupper( ch );
2860 }
2861 } else {
2862 ch = 0;
2863 }
2864 }
2865 // detect other numpad keys. OS/2 doesn't assign virtual keys to them
2866 // so use scancodes (it can be device-dependent, is there a better way?)
2867 switch ( chm.scancode ) {
2868 case 0x4C: // 5
2869 // scancode is zero if Numlock is set
2870 if ( !code ) code = Qt::Key_Clear;
2871 state |= Qt::Keypad;
2872 break;
2873 case 0x37: // *
2874 // OS/2 assigns VK_PRINTSCRN to it when pressed with Shift, also
2875 // it sets chr to zero when it is released with Alt or Ctrl
2876 // leaving vkey as zero too, and does few other strange things --
2877 // override them all
2878 code = Qt::Key_Asterisk;
2879 state |= Qt::Keypad;
2880 break;
2881 case 0x5C: // /
2882 code = Qt::Key_Slash;
2883 // fall through
2884 case 0x4A: // -
2885 case 0x4E: // +
2886 // the code for the above two is obtained by KbdXlate above
2887 state |= Qt::Keypad;
2888 break;
2889 }
2890
2891 if ( (state & Qt::ControlButton) && !(state & Qt::Keypad) ) {
2892 if ( !(state & Qt::AltButton) ) {
2893 unsigned char cch = toupper( ch ), newCh = 0;
2894 // Ctrl + A..Z etc. produce ascii from 0x01 to 0x1F
2895 if ( cch >= 0x41 && cch <= 0x5F ) newCh = cch - 0x40;
2896 // the below emulates OS/2 functionality. It differs from
2897 // Win32 one.
2898 else if ( cch == 0x36 && !(state & Qt::Keypad) ) newCh = 0x1E;
2899 else if ( cch == 0x2D ) newCh = 0x1F;
2900 else if ( cch >= 0x7B && cch <= 0x7D ) newCh = cch - 0x60;
2901 if ( newCh )
2902 ch = newCh;
2903 }
2904 }
2905
2906 ascii = ch;
2907 if ( ascii > 0x7F ) ascii = 0;
2908 if ( ch )
2909 text = QString::fromLocal8Bit( (char*)&ch, 1 );
2910}
2911
2912struct KeyRec {
2913 KeyRec(unsigned char s, int c, int a, const QString& t) :
2914 scan(s), code(c), ascii(a), text(t) { }
2915 KeyRec() { }
2916 unsigned char scan;
2917 int code, ascii;
2918 QString text;
2919};
2920
2921static const int maxrecs=64; // User has LOTS of fingers...
2922static KeyRec key_rec[maxrecs];
2923static int nrecs=0;
2924
2925static KeyRec* find_key_rec( unsigned char scan, bool remove )
2926{
2927 KeyRec *result = 0;
2928 for (int i=0; i<nrecs; i++) {
2929 if (key_rec[i].scan == scan) {
2930 if (remove) {
2931 static KeyRec tmp;
2932 tmp = key_rec[i];
2933 while (i+1 < nrecs) {
2934 key_rec[i] = key_rec[i+1];
2935 i++;
2936 }
2937 nrecs--;
2938 result = &tmp;
2939 } else {
2940 result = &key_rec[i];
2941 }
2942 break;
2943 }
2944 }
2945 return result;
2946}
2947
2948static KeyRec* find_key_rec( int code, bool remove )
2949{
2950 KeyRec *result = 0;
2951 for (int i=0; i<nrecs; i++) {
2952 if (key_rec[i].code == code) {
2953 if (remove) {
2954 static KeyRec tmp;
2955 tmp = key_rec[i];
2956 while (i+1 < nrecs) {
2957 key_rec[i] = key_rec[i+1];
2958 i++;
2959 }
2960 nrecs--;
2961 result = &tmp;
2962 } else {
2963 result = &key_rec[i];
2964 }
2965 break;
2966 }
2967 }
2968 return result;
2969}
2970
2971static void store_key_rec( unsigned char scan, int code, int ascii,
2972 const QString& text )
2973{
2974 if ( nrecs == maxrecs ) {
2975#if defined(QT_CHECK_RANGE)
2976 qWarning( "Qt: Internal keyboard buffer overflow" );
2977#endif
2978 return;
2979 }
2980
2981 key_rec[nrecs++] = KeyRec( scan, code, ascii, text );
2982}
2983
2984bool QETWidget::translateKeyEvent( const QMSG &qmsg, bool grab )
2985{
2986 CHRMSG chm = *((PCHRMSG)(((char*)&qmsg) + sizeof(HWND) + sizeof(ULONG)));
2987
2988#if 0
2989 qDebug( "WM_CHAR: [%s] fs: %04X cRepeat: %03d scancode: %02X chr: %04X vkey: %04X %s",
2990 name(), chm.fs, chm.cRepeat, chm.scancode, chm.chr, chm.vkey, (grab ? "{grab}" : "") );
2991#endif
2992
2993 bool k0 = FALSE, k1 = FALSE;
2994 int code = 0, ascii = 0, state = 0;
2995 QString text;
2996
2997 if ( sm_blockUserInput ) // block user interaction during session management
2998 return TRUE;
2999
3000 translateKeyCode( chm, code, ascii, state, text );
3001/// @todo (dmik) currently WM_CHARs chars with zero virtual code or zero
3002// scancode are totally ignored. -- are they?
3003// if ( !code || !chm.scancode ) return FALSE;
3004
3005 // Invert state logic
3006 if ( code == Key_Alt )
3007 state = state ^ AltButton;
3008 else if ( code == Key_Control )
3009 state = state ^ ControlButton;
3010 else if ( code == Key_Shift )
3011 state = state ^ ShiftButton;
3012
3013 if ( !(chm.fs & KC_KEYUP) ) {
3014 // KEYDOWN
3015 KeyRec* rec = find_key_rec( chm.scancode, FALSE );
3016
3017 if ( state == Qt::AltButton ) {
3018 // Special handling of global PM hotkeys
3019 switch ( code ) {
3020 case Qt::Key_Space:
3021 if ( qt_show_system_menu( topLevelWidget() ) ) {
3022 // remove the Key_Alt from the buffer (otherwise we will
3023 // not get the next "Alt pressed" event because the
3024 // "Alt depressed" event, that must preceed it, will be
3025 // eaten by the system)
3026 find_key_rec( Qt::Key_Alt, TRUE );
3027/// @todo (dmik) do the same for other global keys (ALT+TAB, ALT+ESC, CTRL+ESC)
3028// by handling this situation when we obtain/loose focus)
3029/// @todo (dmik) update: I don't actually think the above should be done, because
3030// it will not solve the problem of stuck modifier keys in general (there may be
3031// other combinations stolen by the system or other apps). More over, I guess
3032// that find_key_rec() above should also be removed to get identical behavior for
3033// all stolen keys. This will allow to solve the problem on the Qt application
3034// level if needed (and even in a platform-independent manner).
3035 }
3036 return TRUE;
3037 case Qt::Key_F4:
3038 // we handle this key combination ourselves because not
3039 // all top-level widgets have the system menu
3040 WinPostMsg( topLevelWidget()->winFId(), WM_CLOSE, 0, 0 );
3041 // see the comment above
3042 find_key_rec( Qt::Key_Alt, TRUE );
3043 return TRUE;
3044 default:
3045 break;
3046 }
3047 }
3048
3049 if ( rec ) {
3050 // it is already down (so it is auto-repeating)
3051 if ( rec->code < Key_Shift || rec->code > Key_ScrollLock ) {
3052 k0 = sendKeyEvent( QEvent::KeyRelease, rec->code, rec->ascii,
3053 state, grab, rec->text, TRUE );
3054 k1 = sendKeyEvent( QEvent::KeyPress, rec->code, rec->ascii,
3055 state, grab, rec->text, TRUE );
3056 }
3057 } else {
3058 // map shift+tab to shift+backtab, QAccel knows about it
3059 // and will handle it
3060 if ( code == Key_Tab && ( state & ShiftButton ) == ShiftButton )
3061 code = Key_BackTab;
3062 store_key_rec( chm.scancode, code, ascii, text );
3063 k0 = sendKeyEvent( QEvent::KeyPress, code, ascii,
3064 state, grab, text );
3065 }
3066 } else {
3067 // KEYUP
3068 KeyRec* rec = find_key_rec( chm.scancode, TRUE );
3069 if ( !rec ) {
3070 // Someone ate the key down event
3071 } else {
3072 k0 = sendKeyEvent( QEvent::KeyRelease, rec->code, rec->ascii,
3073 state, grab, rec->text );
3074
3075 // keyboard context menu event
3076 if ( rec->code == Key_Menu && !state )
3077 WinPostMsg( qmsg.hwnd, WM_CONTEXTMENU, 0, MPFROM2SHORT( 0, 1 ) );
3078 }
3079 }
3080
3081#if 0
3082 qDebug("WM_CHAR: RESULT = %d", (k0 || k1));
3083#endif
3084 return k0 || k1;
3085}
3086
3087#ifndef QT_NO_WHEELEVENT
3088bool QETWidget::translateWheelEvent( const QMSG &qmsg )
3089{
3090 enum { WHEEL_DELTA = 120 };
3091
3092 if ( sm_blockUserInput ) // block user interaction during session management
3093 return TRUE;
3094
3095 // consume duplicate wheel events sent by the AMouse driver to emulate
3096 // multiline scrolls. we need this since currently Qt (QScrollBar, for
3097 // instance) maintains the number of lines to scroll per wheel rotation
3098 // (including the special handling of CTRL and SHIFT modifiers) on its own
3099 // and doesn't have a setting to tell it to be aware of system settings
3100 // for the mouse wheel. if we had processed events as they are, we would
3101 // get a confusing behavior (too many lines scrolled etc.).
3102 {
3103 int devh = QApplication::desktop()->height();
3104 QMSG wheelMsg;
3105 while (
3106 WinPeekMsg( 0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_NOREMOVE )
3107 ) {
3108 // PM bug: ptl contains SHORT coordinates although fields are LONG
3109 wheelMsg.ptl.x = (short) wheelMsg.ptl.x;
3110 wheelMsg.ptl.y = (short) wheelMsg.ptl.y;
3111 // flip y coordinate
3112 wheelMsg.ptl.y = devh - (wheelMsg.ptl.y + 1);
3113 if (
3114 wheelMsg.mp1 != qmsg.mp1 ||
3115 wheelMsg.mp2 != qmsg.mp2 ||
3116 wheelMsg.ptl.x != qmsg.ptl.x ||
3117 wheelMsg.ptl.y != qmsg.ptl.y
3118 )
3119 break;
3120 WinPeekMsg( 0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_REMOVE );
3121 }
3122 }
3123
3124 int delta;
3125 USHORT cmd = SHORT2FROMMP(qmsg.mp2);
3126 switch ( cmd ) {
3127 case SB_LINEUP:
3128 case SB_PAGEUP:
3129 delta = WHEEL_DELTA;
3130 break;
3131 case SB_LINEDOWN:
3132 case SB_PAGEDOWN:
3133 delta = -WHEEL_DELTA;
3134 break;
3135 default:
3136 return FALSE;
3137 }
3138
3139 int state = 0;
3140 if ( WinGetKeyState( HWND_DESKTOP, VK_SHIFT ) & 0x8000 )
3141 state |= ShiftButton;
3142 if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 ||
3143 (qt_extraKeyState & Qt::AltButton)
3144 )
3145 state |= AltButton;
3146 if ( WinGetKeyState( HWND_DESKTOP, VK_CTRL ) & 0x8000 )
3147 state |= ControlButton;
3148 if ( qt_extraKeyState & Qt::MetaButton )
3149 state |= MetaButton;
3150
3151 Orientation orient;
3152 // Alt inverts scroll orientation (Qt/Win32 behavior)
3153 if ( state & AltButton )
3154 orient = qmsg.msg == WM_VSCROLL ? Horizontal : Vertical;
3155 else
3156 orient = qmsg.msg == WM_VSCROLL ? Vertical : Horizontal;
3157
3158 QPoint globalPos (qmsg.ptl.x, qmsg.ptl.y);
3159
3160 // if there is a widget under the mouse and it is not shadowed
3161 // by modality, we send the event to it first
3162 int ret = 0;
3163 QWidget* w = QApplication::widgetAt( globalPos, TRUE );
3164 if ( !w || !qt_try_modal( w, (QMSG*)&qmsg, ret ) )
3165 w = this;
3166
3167 // send the event to the widget or its ancestors
3168 {
3169 QWidget* popup = qApp->activePopupWidget();
3170 if ( popup && w->topLevelWidget() != popup )
3171 popup->close();
3172 QWheelEvent e( w->mapFromGlobal( globalPos ), globalPos, delta, state, orient );
3173 if ( QApplication::sendSpontaneousEvent( w, &e ) )
3174 return TRUE;
3175 }
3176
3177 // send the event to the widget that has the focus or its ancestors, if different
3178 if ( w != qApp->focusWidget() && ( w = qApp->focusWidget() ) ) {
3179 QWidget* popup = qApp->activePopupWidget();
3180 if ( popup && w->topLevelWidget() != popup )
3181 popup->close();
3182 QWheelEvent e( w->mapFromGlobal( globalPos ), globalPos, delta, state, orient );
3183 if ( QApplication::sendSpontaneousEvent( w, &e ) )
3184 return TRUE;
3185 }
3186 return FALSE;
3187}
3188#endif
3189
3190static bool isModifierKey(int code)
3191{
3192 return code >= Qt::Key_Shift && code <= Qt::Key_ScrollLock;
3193}
3194
3195bool QETWidget::sendKeyEvent( QEvent::Type type, int code, int ascii,
3196 int state, bool grab, const QString& text,
3197 bool autor )
3198{
3199 if ( type == QEvent::KeyPress && !grab ) {
3200 // send accel events if the keyboard is not grabbed
3201 QKeyEvent a( type, code, ascii, state, text, autor, QMAX(1, int(text.length())) );
3202 if ( qt_tryAccelEvent( this, &a ) )
3203 return TRUE;
3204 }
3205 if ( !isEnabled() )
3206 return FALSE;
3207 QKeyEvent e( type, code, ascii, state, text, autor, QMAX(1, int(text.length())) );
3208 QApplication::sendSpontaneousEvent( this, &e );
3209 if ( !isModifierKey(code) && state == Qt::AltButton
3210 && ((code>=Key_A && code<=Key_Z) || (code>=Key_0 && code<=Key_9))
3211 && type == QEvent::KeyPress && !e.isAccepted() )
3212 QApplication::beep(); // emulate PM behavior
3213 return e.isAccepted();
3214}
3215
3216
3217//
3218// Paint event translation
3219//
3220bool QETWidget::translatePaintEvent( const QMSG & )
3221{
3222 HPS displayPS = qt_display_ps();
3223
3224#if !defined (QT_PM_NO_WIDGETMASK)
3225 // Since we don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN bits (see
3226 // qwidget_pm.cpp), we have to validate areas that intersect with our
3227 // children and siblings, taking their clip regions into account.
3228 validateObstacles();
3229#endif
3230
3231 HRGN hrgn = GpiCreateRegion( displayPS, 0, NULL );
3232 LONG rc = WinQueryUpdateRegion( winId(), hrgn );
3233 if ( rc == RGN_ERROR ) {
3234 GpiDestroyRegion( displayPS, hrgn );
3235 hps = 0;
3236 clearWState( WState_InPaintEvent );
3237 return FALSE;
3238 }
3239
3240 setWState( WState_InPaintEvent );
3241 RECTL rcl;
3242 hps = WinBeginPaint( winId(), 0, &rcl );
3243
3244 // convert to width and height
3245 rcl.xRight -= rcl.xLeft;
3246 rcl.yTop -= rcl.yBottom;
3247
3248 // it's possible that the update rectangle is empty
3249 if ( !rcl.xRight || !rcl.yTop ) {
3250 WinEndPaint( hps );
3251 GpiDestroyRegion( displayPS, hrgn );
3252 hps = 0;
3253 clearWState( WState_InPaintEvent );
3254 return TRUE;
3255 }
3256
3257#if !defined (QT_PM_NO_WIDGETMASK)
3258 if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
3259 // Correct the update region by intersecting it with the clip
3260 // region (PM doesn't do that itself). It is necessary
3261 // to have a correct QRegion in QPaintEvent.
3262 HRGN hcrgn = GpiCreateRegion( displayPS, 0, NULL );
3263 WinQueryClipRegion( winId(), hcrgn );
3264 GpiCombineRegion( displayPS, hrgn, hrgn, hcrgn, CRGN_AND );
3265 GpiDestroyRegion( displayPS, hcrgn );
3266 }
3267#endif
3268
3269 // flip y coordinate
3270 rcl.yBottom = height() - (rcl.yBottom + rcl.yTop);
3271
3272 // erase background
3273#if !defined (DEBUG_REPAINTRESIZE)
3274 bool erase = !( testWFlags( WRepaintNoErase ) );
3275#else
3276 // Some oldish Qt widgets think that if they specify WRepaintNoErase but
3277 // not WResizeNoErase, the background should still be erased for them
3278 // in *repaint* events. The code below is left to debug these widgets
3279 // (to ensure this is the exact cause of repaint problems)
3280 bool erase = testWFlags( WRepaintNoErase | WResizeNoErase ) != WRepaintNoErase | WResizeNoErase;
3281#endif
3282 if ( erase )
3283 this->erase( rcl.xLeft, rcl.yBottom,
3284 rcl.xRight, rcl.yTop );
3285
3286#if defined (DEBUG_REPAINTRESIZE)
3287 qDebug( "WM_PAINT: [%s/%s/%08X] %ld,%ld; %ld,%ld erase: %d",
3288 name(), className(), widget_flags,
3289 rcl.xLeft, rcl.yBottom, rcl.xRight, rcl.yTop, erase );
3290#endif
3291
3292 // create a region that will take ownership of hrgn
3293 QRegion rgn( hrgn, height() );
3294
3295 QPaintEvent e( rgn, QRect( rcl.xLeft, rcl.yBottom, rcl.xRight, rcl.yTop ),
3296 erase );
3297 QApplication::sendSpontaneousEvent( this, (QEvent*) &e );
3298
3299 WinEndPaint( hps );
3300 hps = 0;
3301 clearWState( WState_InPaintEvent );
3302 return TRUE;
3303}
3304
3305//
3306// Window move and resize (configure) events
3307//
3308
3309bool QETWidget::translateConfigEvent( const QMSG &qmsg )
3310{
3311 if ( !testWState(WState_Created) ) // in QWidget::create()
3312 return TRUE;
3313
3314 WId fId = winFId();
3315 ULONG fStyle = WinQueryWindowULong( fId, QWL_STYLE );
3316 if ( testWState( WState_ConfigPending ) ) {
3317 // it's possible that we're trying to set the frame size smaller
3318 // than it possible for WC_FRAME in QWidget::internalSetGeometry().
3319 // here we correct this (crect there is set before WinSetWindowPos()
3320 // that sends WM_SIZE).
3321 QSize newSize( SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
3322 if ( qmsg.msg == WM_SIZE && size() != newSize ) {
3323 crect.setSize( newSize );
3324 }
3325 return TRUE;
3326 }
3327 setWState( WState_ConfigPending ); // set config flag
3328 QRect cr = geometry();
3329 if ( qmsg.msg == WM_SIZE ) { // resize event
3330 QSize oldSize = size();
3331 QSize newSize( SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
3332 cr.setSize( newSize );
3333 crect = cr;
3334 if ( isTopLevel() ) { // update caption/icon text
3335 createTLExtra();
3336 QString txt;
3337 if ( (fStyle & WS_MAXIMIZED) && !!iconText() )
3338 txt = iconText();
3339 else
3340 if ( !caption().isNull() )
3341 txt = caption();
3342
3343 if ( !!txt ) {
3344 WinSetWindowText( fId, txt.local8Bit() );
3345 }
3346 }
3347 if ( oldSize != newSize) {
3348#if !defined (QT_PM_NO_WIDGETMASK)
3349 // Spontaneous (external to Qt) WM_SIZE messages should occur only
3350 // on top-level widgets. If we get them for a non top-level widget,
3351 // the result will most likely be incorrect because widget masks will
3352 // not be properly processed (i.e. in the way it is done in
3353 // QWidget::internalSetGeometry() when the geometry is changed from
3354 // within Qt). So far, I see no need to support this (who will ever
3355 // need to move a non top-level window of a foreign process?).
3356 Q_ASSERT( isTopLevel() );
3357#endif
3358 if ( isVisible() ) {
3359 QResizeEvent e( newSize, oldSize );
3360 QApplication::sendSpontaneousEvent( this, &e );
3361 if ( !testWFlags( WStaticContents ) )
3362 repaint( !testWFlags(WResizeNoErase) );
3363#if !defined (QT_PM_NO_WIDGETMASK)
3364 // Flush WM_PAINT messages here to update window contents
3365 // instantly while tracking the resize frame (normally these
3366 // messages are delivered after resizing is stopped for some
3367 // time). It makes resizing a bit slower but gives a better look
3368 // (no invalid window contents can be seen during resize).
3369 // The alternative could be to erase the background only
3370 // (similarly to Win32), but we need to do it for every
3371 // non-toplevel window, which can be also time-consuming
3372 WinUpdateWindow( winId() );
3373#endif
3374 } else {
3375 QResizeEvent *e = new QResizeEvent( newSize, oldSize );
3376 QApplication::postEvent( this, e );
3377 }
3378 }
3379 } else if ( qmsg.msg == WM_MOVE ) { // move event
3380 QPoint oldPos = geometry().topLeft();
3381 SWP swp;
3382 if ( isTopLevel() ) {
3383 WinQueryWindowPos( fId, &swp );
3384 // flip y coordinate
3385 swp.y = QApplication::desktop()->height() - ( swp.y + swp.cy );
3386 QTLWExtra *top = topData();
3387 swp.x += top->fleft;
3388 swp.y += top->ftop;
3389 } else {
3390 WinQueryWindowPos( winId(), &swp );
3391 // flip y coordinate
3392 swp.y = parentWidget()->height() - ( swp.y + swp.cy );
3393 }
3394 QPoint newCPos( swp.x, swp.y );
3395 if ( newCPos != oldPos ) {
3396 cr.moveTopLeft( newCPos );
3397 crect = cr;
3398 if ( isVisible() ) {
3399 QMoveEvent e( newCPos, oldPos ); // cpos (client position)
3400 QApplication::sendSpontaneousEvent( this, &e );
3401 } else {
3402 QMoveEvent * e = new QMoveEvent( newCPos, oldPos );
3403 QApplication::postEvent( this, e );
3404 }
3405 }
3406 }
3407 clearWState( WState_ConfigPending ); // clear config flag
3408 return TRUE;
3409}
3410
3411
3412//
3413// Close window event translation.
3414//
3415// This class is a friend of QApplication because it needs to emit the
3416// lastWindowClosed() signal when the last top level widget is closed.
3417//
3418
3419bool QETWidget::translateCloseEvent( const QMSG & )
3420{
3421 return close(FALSE);
3422}
3423
3424void QApplication::setCursorFlashTime( int msecs )
3425{
3426 WinSetSysValue( HWND_DESKTOP, SV_CURSORRATE, msecs / 2 );
3427 cursor_flash_time = msecs;
3428}
3429
3430int QApplication::cursorFlashTime()
3431{
3432 int blink = (int) WinQuerySysValue( HWND_DESKTOP, SV_CURSORRATE );
3433 if ( !blink )
3434 return cursor_flash_time;
3435 if (blink > 0)
3436 return 2*blink;
3437 return 0;
3438}
3439
3440void QApplication::setDoubleClickInterval( int ms )
3441{
3442 WinSetSysValue( HWND_DESKTOP, SV_DBLCLKTIME, ms );
3443 mouse_double_click_time = ms;
3444}
3445
3446
3447int QApplication::doubleClickInterval()
3448{
3449 int ms = (int) WinQuerySysValue( HWND_DESKTOP, SV_DBLCLKTIME );
3450 if ( ms != 0 )
3451 return ms;
3452 return mouse_double_click_time;
3453}
3454
3455void QApplication::setWheelScrollLines( int n )
3456{
3457 wheel_scroll_lines = n;
3458}
3459
3460int QApplication::wheelScrollLines()
3461{
3462 return wheel_scroll_lines;
3463}
3464
3465void QApplication::setEffectEnabled( Qt::UIEffect effect, bool enable )
3466{
3467#ifndef QT_NO_EFFECTS
3468 switch (effect) {
3469 case UI_AnimateMenu:
3470 if ( enable ) fade_menu = FALSE;
3471 animate_menu = enable;
3472 break;
3473 case UI_FadeMenu:
3474 if ( enable )
3475 animate_menu = TRUE;
3476 fade_menu = enable;
3477 break;
3478 case UI_AnimateCombo:
3479 animate_combo = enable;
3480 break;
3481 case UI_AnimateTooltip:
3482 if ( enable ) fade_tooltip = FALSE;
3483 animate_tooltip = enable;
3484 break;
3485 case UI_FadeTooltip:
3486 if ( enable )
3487 animate_tooltip = TRUE;
3488 fade_tooltip = enable;
3489 break;
3490 case UI_AnimateToolBox:
3491 animate_toolbox = enable;
3492 break;
3493 default:
3494 animate_ui = enable;
3495 break;
3496 }
3497#endif
3498}
3499
3500bool QApplication::isEffectEnabled( Qt::UIEffect effect )
3501{
3502#ifndef QT_NO_EFFECTS
3503 if ( QColor::numBitPlanes() < 16 || !animate_ui )
3504 return FALSE;
3505
3506 switch( effect ) {
3507 case UI_AnimateMenu:
3508 return animate_menu;
3509 case UI_FadeMenu:
3510 return fade_menu;
3511 case UI_AnimateCombo:
3512 return animate_combo;
3513 case UI_AnimateTooltip:
3514 return animate_tooltip;
3515 case UI_FadeTooltip:
3516 return fade_tooltip;
3517 case UI_AnimateToolBox:
3518 return animate_toolbox;
3519 default:
3520 return animate_ui;
3521 }
3522#else
3523 return FALSE;
3524#endif
3525}
3526
3527void QApplication::flush()
3528{
3529}
3530
3531#if !defined (QT_NO_SESSIONMANAGER)
3532
3533bool qt_app_canQuit()
3534{
3535#if defined (DEBUG_SESSIONMANAGER)
3536 qDebug( "qt_app_canQuit(): sm_smActive=%d qt_about_to_destroy_wnd=%d "
3537 "sm_gracefulShutdown=%d sm_cancel=%d",
3538 sm_smActive, qt_about_to_destroy_wnd,
3539 sm_gracefulShutdown, sm_cancel );
3540#endif
3541
3542 BOOL answer = FALSE;
3543
3544 // We can get multiple WM_QUIT messages while the "session termination
3545 // procedure" (i.e. the QApplication::commitData() call) is still in
3546 // progress. Ignore them.
3547 if ( !sm_smActive ) {
3548 if ( sm_gracefulShutdown ) {
3549 // this is WM_QUIT after WM_SAVEAPPLICATION (either posted by the OS
3550 // or by ourselves), confirm the quit depending on what the user wants
3551 sm_quitSkipped = FALSE;
3552 answer = !sm_cancel;
3553 if ( sm_cancel ) {
3554 // the shutdown has been canceled, reset the flag to let the
3555 // graceful shutdown happen again later
3556 sm_gracefulShutdown = FALSE;
3557 }
3558 } else {
3559 // sm_gracefulShutdown is FALSE, so allowsInteraction() and friends
3560 // will return FALSE during commitData() (assuming that WM_QUIT w/o
3561 // WM_SAVEAPPLICATION is an emergency termination)
3562 sm_smActive = TRUE;
3563 sm_blockUserInput = TRUE; // prevent user-interaction outside interaction windows
3564 sm_cancel = FALSE;
3565 if ( qt_session_manager_self )
3566 qApp->commitData( *qt_session_manager_self );
3567 sm_smActive = FALSE;
3568 answer = TRUE; // ignore sm_cancel
3569 }
3570 } else {
3571 // if this is a WM_QUIT received during WM_SAVEAPPLICATION handling,
3572 // remember we've skipped (refused) it
3573 if ( sm_gracefulShutdown )
3574 sm_quitSkipped = TRUE;
3575 }
3576
3577#if defined (DEBUG_SESSIONMANAGER)
3578 qDebug( "qt_app_canQuit(): answer=%ld", answer );
3579#endif
3580
3581 return answer;
3582}
3583
3584bool QSessionManager::allowsInteraction()
3585{
3586 // Allow interation only when the system is being normally shutdown
3587 // and informs us using WM_SAVEAPPLICATION. When we receive WM_QUIT directly
3588 // (so sm_gracefulShutdown is FALSE), interaction is disallowed.
3589 if ( sm_smActive && sm_gracefulShutdown ) {
3590 sm_blockUserInput = FALSE;
3591 return TRUE;
3592 }
3593
3594 return FALSE;
3595}
3596
3597bool QSessionManager::allowsErrorInteraction()
3598{
3599 // Allow interation only when the system is being normally shutdown
3600 // and informs us using WM_SAVEAPPLICATION. When we receive WM_QUIT directly
3601 // (so sm_gracefulShutdown is FALSE), interaction is disallowed.
3602 if ( sm_smActive && sm_gracefulShutdown ) {
3603 sm_blockUserInput = FALSE;
3604 return TRUE;
3605 }
3606
3607 return FALSE;
3608}
3609
3610void QSessionManager::release()
3611{
3612 if ( sm_smActive && sm_gracefulShutdown )
3613 sm_blockUserInput = TRUE;
3614}
3615
3616void QSessionManager::cancel()
3617{
3618 if ( sm_smActive && sm_gracefulShutdown )
3619 sm_cancel = TRUE;
3620}
3621
3622#endif
Note: See TracBrowser for help on using the repository browser.