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

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

Kernel: Added the Qt-wide OS/2 system exception handler (see ticket:33 for details). It may be disabled by defining QT_PM_NO_SYSEXCEPTIONS when building Qt.

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