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

Last change on this file since 61 was 61, checked in by dmik, 20 years ago

Implemented QRegion(..., QRegion::Eclipse) and QRegion(QPointArray &,...) constructors.
Improved Qt<->GPI region coordinates translation (it's now implicit), QRegion::handle() takes a height of the target devise as an argument (defaults to 0).

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