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

Last change on this file since 170 was 170, checked in by dmik, 18 years ago

Kernel: Fixed DBCS input/output support (thanks again to Ko Myung-Hun).

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