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

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

Implemented QWidget::setMask() functionality.

  • Property svn:keywords set to Id
File size: 119.6 KB
Line 
1/****************************************************************************
2** $Id: qapplication_pm.cpp 64 2006-03-12 13:26:37Z dmik $
3**
4** Implementation of OS/2 startup routines and event handling
5**
6** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 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 to by a mouse pointer.
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 a mouse pointer.
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#if defined (QT_PM_NO_WIDGETMASK)
1440 // flush WM_PAINT messages here to update window contents
1441 // instantly while tracking the resize frame (normally these
1442 // messages are delivered after the user has stopped resizing
1443 // for some time). this slows down resizing slightly but gives a
1444 // better look (no invalid window contents can be seen during
1445 // resize). the alternative could be to erase the background only,
1446 // but we need to do it for every non-toplevel window, which can
1447 // also be time-consuming (WM_ERASEBACKGROUND is sent to WC_FRAME
1448 // clients only, so we would have to do all calculations ourselves).
1449 WinUpdateWindow( widget->winId() );
1450#else
1451 // We flush WM_PAINT messages in QETWidget::translateConfigEvent().
1452#endif
1453 RETURN( FALSE );
1454 break;
1455 case WM_CALCVALIDRECTS:
1456 // we must always return this value here to cause PM to reposition
1457 // our children accordingly (othwerwise we would have to do it
1458 // ourselves to keep them top-left aligned).
1459 RETURN( CVR_ALIGNLEFT | CVR_ALIGNTOP );
1460 break;
1461
1462 case WM_MOVE: // move window
1463 case WM_SIZE: // resize window
1464 result = widget->translateConfigEvent( qmsg );
1465 break;
1466
1467 case WM_ACTIVATE:
1468#if 0
1469 qDebug( "WM_ACTIVATE: [%s] %d", widget->name(), SHORT1FROMMP(mp1) );
1470#endif
1471 qApp->pmFocus( widget, SHORT1FROMMP(mp1) );
1472 break;
1473
1474 case WM_SETFOCUS:
1475#if 0
1476 qDebug( "WM_SETFOCUS: [%s] %s [%s]", widget->name(),
1477 SHORT1FROMMP(mp2) ? "<=" : "=>",
1478 QWidget::find( (HWND)mp1 ) ? QWidget::find( (HWND)mp1 )->name()
1479 : "{foreign}" );
1480#endif
1481 result = FALSE;
1482 if ( !SHORT1FROMMP(mp2) ) {
1483 // we're losing focus
1484 if ( !QWidget::find( (HWND)mp1 ) ) {
1485 if ( QApplication::activePopupWidget() ) {
1486 // Another application was activated while our popups are open,
1487 // then close all popups. In case some popup refuses to close,
1488 // we give up after 1024 attempts (to avoid an infinite loop).
1489 int maxiter = 1024;
1490 QWidget *popup;
1491 while ( (popup=QApplication::activePopupWidget()) && maxiter-- )
1492 popup->close();
1493 }
1494 if (
1495 // non-Qt ownees of our WC_FRAME window (such as
1496 // FID_SYSMENU) should not cause the focus to be lost.
1497 WinQueryWindow( (HWND)mp1, QW_OWNER ) ==
1498 widget->topLevelWidget()->winFId()
1499 )
1500 break;
1501 if ( !widget->isTopLevel() )
1502 qApp->pmFocus( widget, SHORT1FROMMP(mp2) );
1503 }
1504 }
1505 break;
1506
1507/// @todo (dmik) remove?
1508//#ifndef Q_OS_TEMP
1509// case WM_MOUSEACTIVATE:
1510// {
1511// const QWidget *tlw = widget->topLevelWidget();
1512// // Do not change activation if the clicked widget is inside a floating dock window
1513// if ( tlw->inherits( "QDockWindow" ) && qApp->activeWindow()
1514// && !qApp->activeWindow()->inherits("QDockWindow") )
1515// RETURN(MA_NOACTIVATE);
1516// }
1517// result = FALSE;
1518// break;
1519//#endif
1520
1521 case WM_SHOW:
1522 if ( !SHORT1FROMMP(mp1) && autoCaptureWnd == widget->winId() )
1523 releaseAutoCapture();
1524 result = FALSE;
1525 break;
1526/// @todo (dmik) remove later
1527// case WM_SHOWWINDOW:
1528//#ifndef Q_OS_TEMP
1529// if ( lParam == SW_PARENTOPENING ) {
1530// if ( widget->testWState(Qt::WState_ForceHide) )
1531// RETURN(0);
1532// }
1533//#endif
1534// if (!wParam && autoCaptureWnd == widget->winId())
1535// releaseAutoCapture();
1536// result = FALSE;
1537// break;
1538
1539 case WM_REALIZEPALETTE: // realize own palette
1540 if ( QColor::hPal() ) {
1541 HPS hps = WinGetPS( widget->winId() );
1542 GpiSelectPalette( hps, QColor::hPal() );
1543 ULONG cclr;
1544 WinRealizePalette( widget->winId(), hps, &cclr );
1545 WinReleasePS( hps );
1546 // on OS/2, the value returned by WinRealizePalette() does not
1547 // necessarily reflect the number of colors that have been
1548 // remapped. therefore, we cannot rely on it and must always
1549 // invalidate the window.
1550 WinInvalidateRect( widget->winId(), NULL, TRUE );
1551 RETURN( 0 );
1552 }
1553 break;
1554
1555 case WM_CLOSE: // close window
1556 widget->translateCloseEvent( qmsg );
1557 RETURN(0); // always handled
1558
1559/// @todo (dmik) it seems we don't need this
1560// case WM_DESTROY: // destroy window
1561// if ( hwnd == curWin ) {
1562// QEvent leave( QEvent::Leave );
1563// QApplication::sendEvent( widget, &leave );
1564// curWin = 0;
1565// }
1566// // We are blown away when our parent reparents, so we have to
1567// // recreate the handle
1568// if (widget->testWState(Qt::WState_Created))
1569// ((QETWidget*)widget)->reparentWorkaround();
1570// if ( widget == popupButtonFocus )
1571// popupButtonFocus = 0;
1572// result = FALSE;
1573// break;
1574
1575 case WM_CONTEXTMENU:
1576 if ( SHORT2FROMMP(mp2) ) {
1577 // keyboard event
1578 QWidget *fw = qApp->focusWidget();
1579 if ( fw ) {
1580 QContextMenuEvent e(
1581 QContextMenuEvent::Keyboard,
1582 QPoint( 5, 5 ),
1583 fw->mapToGlobal( QPoint( 5, 5 ) ),
1584 0
1585 );
1586 result = qt_sendSpontaneousEvent( fw, &e );
1587 rc = (MRESULT) result;
1588 }
1589 } else {
1590 // mouse event
1591 result = widget->translateMouseEvent( qmsg );
1592 rc = (MRESULT) result;
1593 }
1594 break;
1595
1596/// @todo (dmik) later
1597// case WM_IME_STARTCOMPOSITION:
1598// result = QInputContext::startComposition();
1599// break;
1600// case WM_IME_ENDCOMPOSITION:
1601// result = QInputContext::endComposition();
1602// break;
1603// case WM_IME_COMPOSITION:
1604// result = QInputContext::composition( lParam );
1605// break;
1606
1607#ifndef QT_NO_CLIPBOARD
1608 case WM_DRAWCLIPBOARD:
1609 case WM_RENDERFMT:
1610 case WM_RENDERALLFMTS:
1611 case WM_DESTROYCLIPBOARD:
1612 if ( qt_clipboard ) {
1613 QCustomEvent e( QEvent::Clipboard, &qmsg );
1614 qt_sendSpontaneousEvent( qt_clipboard, &e );
1615 RETURN(0);
1616 }
1617 result = FALSE;
1618 break;
1619#endif
1620
1621/// @todo (dmik) later
1622//#if defined(QT_ACCESSIBILITY_SUPPORT)
1623// case WM_GETOBJECT:
1624// {
1625// // Ignoring all requests while starting up
1626// if ( qApp->startingUp() || !qApp->loopLevel() || lParam != OBJID_CLIENT ) {
1627// result = FALSE;
1628// break;
1629// }
1630//
1631// typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN );
1632// static PtrLresultFromObject ptrLresultFromObject = 0;
1633// static bool oleaccChecked = FALSE;
1634//
1635// if ( !oleaccChecked ) {
1636// oleaccChecked = TRUE;
1637// ptrLresultFromObject = (PtrLresultFromObject)QLibrary::resolve( "oleacc.dll", "LresultFromObject" );
1638// }
1639// if ( ptrLresultFromObject ) {
1640// QAccessibleInterface *acc = 0;
1641// QAccessible::queryAccessibleInterface( widget, &acc );
1642// if ( !acc ) {
1643// result = FALSE;
1644// break;
1645// }
1646//
1647// QCustomEvent e( QEvent::Accessibility, acc );
1648// QApplication::sendEvent( widget, &e );
1649//
1650// // and get an instance of the IAccessibile implementation
1651// IAccessible *iface = qt_createWindowsAccessible( acc );
1652// acc->release();
1653// LRESULT res = ptrLresultFromObject( IID_IAccessible, wParam, iface ); // ref == 2
1654// iface->Release(); // the client will release the object again, and then it will destroy itself
1655//
1656// if ( res > 0 )
1657// RETURN(res);
1658// }
1659// }
1660// result = FALSE;
1661// break;
1662//#endif
1663
1664//@@TODO (dmik): remove. functionality is implemented in WM_SETFOCUS above.
1665// case WM_KILLFOCUS:
1666// if ( !QWidget::find( (HWND)wParam ) ) { // we don't get focus, so unset it now
1667// if ( !widget->hasFocus() ) // work around Windows bug after minimizing/restoring
1668// widget = (QETWidget*)qApp->focusWidget();
1669// HWND focus = ::GetFocus();
1670// if ( !widget || (focus && ::IsChild( widget->winId(), focus )) ) {
1671// result = FALSE;
1672// } else {
1673// widget->clearFocus();
1674// result = TRUE;
1675// }
1676// } else {
1677// result = FALSE;
1678// }
1679// break;
1680
1681//@@TODO (dmik): later
1682// case WM_THEMECHANGED:
1683// if ( widget->testWFlags( Qt::WType_Desktop ) || !qApp || qApp->closingDown()
1684// || qApp->type() == QApplication::Tty )
1685// break;
1686//
1687// if ( widget->testWState(Qt::WState_Polished) )
1688// qApp->style().unPolish(widget);
1689//
1690// if ( widget->testWState(Qt::WState_Polished) )
1691// qApp->style().polish(widget);
1692// widget->repolishStyle( qApp->style() );
1693// if ( widget->isVisible() )
1694// widget->update();
1695// break;
1696//
1697//#ifndef Q_OS_TEMP
1698// case WM_INPUTLANGCHANGE: {
1699// char info[7];
1700// if ( !GetLocaleInfoA( MAKELCID(lParam, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, info, 6 ) ) {
1701// inputcharset = CP_ACP;
1702// } else {
1703// inputcharset = QString( info ).toInt();
1704// }
1705// break;
1706// }
1707//#else
1708// case WM_COMMAND:
1709// result = (wParam == 0x1);
1710// if ( result )
1711// QApplication::postEvent( widget, new QEvent( QEvent::OkRequest ) );
1712// break;
1713// case WM_HELP:
1714// QApplication::postEvent( widget, new QEvent( QEvent::HelpRequest ) );
1715// result = TRUE;
1716// break;
1717//#endif
1718
1719 case WM_U_MOUSELEAVE:
1720 // We receive a mouse leave for curWin, meaning
1721 // the mouse was moved outside our widgets
1722 if ( widget->winId() == curWin && (HWND) mp1 == curWin ) {
1723 bool dispatch = !widget->hasMouse();
1724 // hasMouse is updated when dispatching enter/leave,
1725 // so test if it is actually up-to-date
1726 if ( !dispatch ) {
1727 QRect geom = widget->geometry();
1728 if ( widget->parentWidget() && !widget->isTopLevel() ) {
1729 QPoint gp = widget->parentWidget()->mapToGlobal( widget->pos() );
1730 geom.setX( gp.x() );
1731 geom.setY( gp.y() );
1732 }
1733 QPoint cpos = QCursor::pos();
1734 dispatch = !geom.contains( cpos );
1735 }
1736 if ( dispatch ) {
1737 qt_dispatchEnterLeave( 0, QWidget::find( (WId)curWin ) );
1738 curWin = 0;
1739 }
1740 }
1741 break;
1742
1743//@@TODO (dmik): remove. functionality is implemented in WM_SETFOCUS above.
1744// case WM_CANCELMODE:
1745// if ( qApp->focusWidget() ) {
1746// QFocusEvent::setReason( QFocusEvent::ActiveWindow );
1747// QFocusEvent e( QEvent::FocusOut );
1748// QApplication::sendEvent( qApp->focusWidget(), &e );
1749// QFocusEvent::resetReason();
1750// }
1751// break;
1752
1753 default:
1754 result = FALSE; // event was not processed
1755 break;
1756 }
1757 }
1758
1759 if ( evt_type != QEvent::None ) { // simple event
1760 QEvent e( evt_type );
1761 result = qt_sendSpontaneousEvent( widget, &e );
1762 }
1763 if ( result )
1764 RETURN( rc );
1765
1766do_default:
1767 RETURN( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
1768//@@TODO (dmik): remove
1769// RETURN( QInputContext::DefWindowProc(hwnd,message,wParam,lParam) )
1770}
1771
1772PFNWP QtOldFrameProc = 0;
1773
1774extern "C" MRESULT EXPENTRY QtFrameProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
1775{
1776 // message handling indicators: if result is true at the end of message
1777 // processing, no default window proc is called but rc is returned.
1778 bool result = FALSE;
1779 MRESULT rc = (MRESULT) FALSE;
1780 QETWidget *widget = 0;
1781 HWND hwndC = 0;
1782
1783 if ( !qApp ) // unstable app state
1784 goto do_default;
1785
1786 // make sure we show widgets (e.g. scrollbars) when the user resizes
1787 if ( inLoop && qApp->loopLevel() )
1788 qApp->sendPostedEvents( 0, QEvent::ShowWindowRequest );
1789
1790 inLoop = TRUE;
1791
1792 hwndC = WinWindowFromID( hwnd, FID_CLIENT );
1793 widget = (QETWidget*)QWidget::find( hwndC );
1794 if ( !widget ) // don't know this widget
1795 goto do_default;
1796
1797 switch ( msg ) {
1798 case WM_HITTEST: {
1799 if ( !WinIsWindowEnabled( hwnd ) ) {
1800 if (
1801 qApp->activePopupWidget() &&
1802 (WinQueryQueueStatus( HWND_DESKTOP ) & QS_MOUSEBUTTON)
1803 ) {
1804 // the user has clicked over the Qt window that is disabled
1805 // by some modal widget, therefore we close all popups. In
1806 // case some popup refuses to close, we give up after 1024
1807 // attempts (to avoid an infinite loop).
1808 int maxiter = 1024;
1809 QWidget *popup;
1810 while ( (popup=QApplication::activePopupWidget()) && maxiter-- )
1811 popup->close();
1812 }
1813#ifndef QT_NO_CURSOR
1814 else {
1815 QCursor *c = qt_grab_cursor();
1816 if ( !c )
1817 c = QApplication::overrideCursor();
1818 if ( c ) // application cursor defined
1819 WinSetPointer( HWND_DESKTOP, c->handle() );
1820 else
1821 WinSetPointer( HWND_DESKTOP, Qt::arrowCursor.handle() );
1822 }
1823#endif
1824 }
1825 break;
1826 }
1827
1828 case WM_ADJUSTWINDOWPOS: {
1829 SWP &swp = *(PSWP) mp1;
1830 if ( swp.fl & SWP_MAXIMIZE ) {
1831 QWExtra *x = widget->xtra();
1832 if ( x ) {
1833 result = TRUE;
1834 rc = QtOldFrameProc( hwnd, msg, mp1, mp2 );
1835 int maxw = QWIDGETSIZE_MAX, maxh = QWIDGETSIZE_MAX;
1836 QTLWExtra *top = widget->top();
1837 if ( x->maxw < QWIDGETSIZE_MAX )
1838 maxw = x->maxw + top->fleft + top->fright;
1839 if ( x->maxh < QWIDGETSIZE_MAX )
1840 maxh = x->maxh + top->ftop + top->fbottom;
1841 if ( maxw < QWIDGETSIZE_MAX ) swp.cx = maxw;
1842 if ( maxh < QWIDGETSIZE_MAX ) {
1843 swp.y = swp.y + swp.cy - maxh;
1844 swp.cy = maxh;
1845 }
1846 }
1847 }
1848 if ( swp.fl & (SWP_ACTIVATE | SWP_ZORDER) ) {
1849 // get the modal widget that made this window blocked
1850 QWidget *m =
1851 (QWidget*) WinQueryWindowULong( widget->winId(), QWL_QTMODAL );
1852 if( m ) {
1853 if ( swp.fl & SWP_ACTIVATE ) {
1854 QWidget *a = qt_modal_stack->first();
1855 if ( !a->isActiveWindow() )
1856 a->setActiveWindow();
1857 swp.fl &= ~SWP_ACTIVATE;
1858 }
1859 if ( swp.fl & SWP_ZORDER ) {
1860 QWidget *mp = m->parentWidget();
1861 if ( mp ) {
1862 mp = mp->topLevelWidget();
1863 if ( !mp->isDesktop() && mp != widget )
1864 m = mp;
1865 }
1866 HWND hm = m->winFId();
1867 if ( swp.hwndInsertBehind != hm ) {
1868 swp.hwndInsertBehind = hm;
1869 }
1870 }
1871 }
1872 }
1873 break;
1874 }
1875
1876 case WM_QUERYTRACKINFO: {
1877 QWExtra *x = widget->xtra();
1878 if ( x ) {
1879 result = TRUE;
1880 rc = QtOldFrameProc( hwnd, msg, mp1, mp2 );
1881 PTRACKINFO pti = (PTRACKINFO) mp2;
1882 int minw = 0, minh = 0;
1883 int maxw = QWIDGETSIZE_MAX, maxh = QWIDGETSIZE_MAX;
1884 QTLWExtra *top = widget->top();
1885 if ( x->minw > 0 )
1886 minw = x->minw + top->fleft + top->fright;
1887 if ( x->minh > 0 )
1888 minh = x->minh + top->ftop + top->fbottom;
1889 if ( x->maxw < QWIDGETSIZE_MAX )
1890 maxw = x->maxw + top->fleft + top->fright;
1891 if ( x->maxh < QWIDGETSIZE_MAX )
1892 maxh = x->maxh + top->ftop + top->fbottom;
1893 // obey system recommended minimum size (to emulate Qt/Win32)
1894 pti->ptlMinTrackSize.x = QMAX( minw, pti->ptlMinTrackSize.x );
1895 pti->ptlMinTrackSize.y = QMAX( minh, pti->ptlMinTrackSize.y );
1896 pti->ptlMaxTrackSize.x = maxw;
1897 pti->ptlMaxTrackSize.y = maxh;
1898 }
1899 break;
1900 }
1901
1902 case WM_TRACKFRAME: {
1903 if ( QApplication::activePopupWidget() ) {
1904 // The user starts to size/move the frame window, therefore
1905 // we close all popups. In case some popup refuses to close,
1906 // we give up after 1024 attempts (to avoid an infinite loop).
1907 int maxiter = 1024;
1908 QWidget *popup;
1909 while ( (popup=QApplication::activePopupWidget()) && maxiter-- )
1910 popup->close();
1911 }
1912 break;
1913 }
1914
1915 default:
1916 break;
1917 }
1918
1919 if ( result )
1920 RETURN( rc );
1921
1922do_default:
1923 RETURN( QtOldFrameProc( hwnd, msg, mp1, mp2 ) );
1924}
1925
1926/*****************************************************************************
1927 Modal widgets; We have implemented our own modal widget mechanism
1928 to get total control.
1929 A modal widget without a parent becomes application-modal.
1930 A modal widget with a parent becomes modal to its parent and grandparents..
1931
1932//@@TODO (dmik): the above comment is not correct (outdated?): for example,
1933// in accordance with the current Qt logic, a modal widget with a parent
1934// becomes modal to its (grand)parents upto the first of them that has the
1935// WGroupLeader flag, not necessarily to all...
1936
1937 qt_enter_modal()
1938 Enters modal state
1939 Arguments:
1940 QWidget *widget A modal widget
1941
1942 qt_leave_modal()
1943 Leaves modal state for a widget
1944 Arguments:
1945 QWidget *widget A modal widget
1946 *****************************************************************************/
1947
1948Q_EXPORT bool qt_modal_state()
1949{
1950 return app_do_modal;
1951}
1952
1953// helper for qt_dispatchBlocked().
1954// sends block events to the given widget and its children.
1955void qt_sendBlocked( QObject *obj, QWidget *modal, QEvent *e, bool override )
1956{
1957 if ( obj == modal ) {
1958 // don't touch modal itself and its children
1959 return;
1960 }
1961 bool blocked = e->type() == QEvent::WindowBlocked;
1962
1963 if ( obj->isWidgetType() ) {
1964 QWidget *w = (QWidget*) obj;
1965 if ( w->isTopLevel() ) {
1966 if ( w->testWFlags( Qt::WGroupLeader ) && !override ) {
1967 // stop sending on group leaders
1968 return;
1969 }
1970 QWidget *blockedBy =
1971 (QWidget*) WinQueryWindowULong( w->winId(), QWL_QTMODAL );
1972 if ( blocked ) {
1973 // stop sending on alreay blocked widgets
1974 if ( blockedBy )
1975 return;
1976 } else {
1977 // stop sending on widgets blocked by another modal
1978 if ( blockedBy != modal )
1979 return;
1980 }
1981 WinSetWindowULong( w->winId(), QWL_QTMODAL,
1982 blocked ? (ULONG) modal : 0 );
1983 WinEnableWindow( w->winFId(), !blocked );
1984 }
1985 }
1986 QApplication::sendEvent( obj, e );
1987
1988 // now send blocked to children
1989 if ( obj->children() ) {
1990 QObjectListIt it( *obj->children() );
1991 QObject *o;
1992 while( ( o = it.current() ) != 0 ) {
1993 ++it;
1994 qt_sendBlocked( o, modal, e, FALSE );
1995 }
1996 }
1997}
1998
1999// sends blocked/unblocked events to top-level widgets depending on the
2000// modal widget given and the WGroupLeader flag presence.
2001static void qt_dispatchBlocked( QWidget *modal, bool blocked )
2002{
2003 // we process those top-level windows that must be blocked
2004 // by the given modal -- this should correlate with the
2005 // qt_tryModalHelper() logic that is widget-centric (i.e. a try
2006 // to block a particular widget given the current set of
2007 // modals) rather than modal-centric (a try to block the current set
2008 // of widgets given a particular modal); currently it blocks events
2009 // for a top-level widget if the widget doesn't have (a parent with
2010 // with) the WGroupLeader flag or it has but (this parent) has a child
2011 // among the current set of modals. So, the modal-centric logic is
2012 // to block any top-level widget unless it has (a parent with) the
2013 // WGroupLeader flag and (this parent) is not (a child of) the modal's
2014 // group leader.
2015
2016 QEvent e( blocked ? QEvent::WindowBlocked : QEvent::WindowUnblocked );
2017
2018 // find the modal's group leader
2019 QWidget *mgl = modal->parentWidget();
2020 while ( mgl && !mgl->testWFlags( Qt::WGroupLeader ) )
2021 mgl = mgl->parentWidget();
2022 if ( mgl ) {
2023 mgl = mgl->topLevelWidget();
2024 if ( mgl->isDesktop() )
2025 mgl = 0;
2026 }
2027
2028 QWidgetList *list = QApplication::topLevelWidgets();
2029 for( QWidget *w = list->first(); w; w = list->next() ) {
2030 if (
2031 !w->isDesktop() && !w->isPopup() && !w->isHidden() &&
2032 !w->testWFlags( Qt::WGroupLeader ) &&
2033 (!w->parentWidget() || w->parentWidget()->isDesktop())
2034 ) {
2035 qt_sendBlocked( w, modal, &e, FALSE );
2036 }
2037 }
2038
2039 if ( mgl ) {
2040 // send blocked to modal's group leader
2041 qt_sendBlocked( mgl, modal, &e, TRUE );
2042 }
2043 // qt_tryModalHelper() also assumes that the toppest modal widget blocks
2044 // other modals, regardless of WGroupLeader flags in parents. do the same.
2045 // note: the given modal is not yet at the stack here.
2046 if ( qt_modal_stack ) {
2047 QWidget *m = qt_modal_stack->first();
2048 while ( m ) {
2049 qt_sendBlocked( m, modal, &e, TRUE );
2050 m = qt_modal_stack->next();
2051 }
2052 }
2053}
2054
2055Q_EXPORT void qt_enter_modal( QWidget *widget )
2056{
2057 if ( !qt_modal_stack ) { // create modal stack
2058 qt_modal_stack = new QWidgetList;
2059 Q_CHECK_PTR( qt_modal_stack );
2060 }
2061
2062 if ( qt_modal_stack->containsRef( widget ) )
2063 return; // already modal
2064
2065//@@TODO (dmik): Qt/Win32 sends WindowBlocked/WindowUnblocked events only
2066// to the direct parent of the modal widget. Why? We use qt_dispatchBlocked()
2067// to send them to all windows that do not get input when the given widget
2068// is modal; also we disable/enable that windows there, which is essential
2069// for modality support in Qt/OS2 (code in QtOldFrameProc() and qt_try_modal()
2070// functionality depend on it).
2071//
2072// if (widget->parentWidget()) {
2073// QEvent e(QEvent::WindowBlocked);
2074// QApplication::sendEvent(widget->parentWidget(), &e);
2075// WinEnableWindow( widget->parentWidget()->winFId(), FALSE );
2076// }
2077 qt_dispatchBlocked( widget, TRUE );
2078
2079 releaseAutoCapture();
2080 qt_dispatchEnterLeave( 0, QWidget::find((WId)curWin));
2081 qt_modal_stack->insert( 0, widget );
2082 app_do_modal = TRUE;
2083 curWin = 0;
2084 qt_button_down = 0;
2085 ignoreNextMouseReleaseEvent = FALSE;
2086}
2087
2088
2089Q_EXPORT void qt_leave_modal( QWidget *widget )
2090{
2091 if ( qt_modal_stack && qt_modal_stack->removeRef(widget) ) {
2092 if ( qt_modal_stack->isEmpty() ) {
2093 delete qt_modal_stack;
2094 qt_modal_stack = 0;
2095 QPoint p( QCursor::pos() );
2096 app_do_modal = FALSE; // necessary, we may get recursively into qt_try_modal below
2097 QWidget* w = QApplication::widgetAt( p.x(), p.y(), TRUE );
2098 qt_dispatchEnterLeave( w, QWidget::find( curWin ) ); // send synthetic enter event
2099 curWin = w? w->winId() : 0;
2100 }
2101 ignoreNextMouseReleaseEvent = TRUE;
2102
2103 qt_dispatchBlocked( widget, FALSE );
2104 }
2105 app_do_modal = qt_modal_stack != 0;
2106
2107//@@TODO (dmik): see the comments inside qt_enter_modal()
2108//
2109// if (widget->parentWidget()) {
2110// WinEnableWindow( widget->parentWidget()->winFId(), TRUE );
2111// QEvent e(QEvent::WindowUnblocked);
2112// QApplication::sendEvent(widget->parentWidget(), &e);
2113// }
2114}
2115
2116static bool qt_blocked_modal( QWidget *widget )
2117{
2118 if ( !app_do_modal )
2119 return FALSE;
2120 if ( qApp->activePopupWidget() )
2121 return FALSE;
2122 if ( widget->testWFlags(Qt::WStyle_Tool) ) // allow tool windows
2123 return FALSE;
2124
2125 QWidget *modal=0, *top=qt_modal_stack->getFirst();
2126
2127 widget = widget->topLevelWidget();
2128 if ( widget->testWFlags(Qt::WShowModal) ) // widget is modal
2129 modal = widget;
2130 if ( !top || modal == top ) // don't block event
2131 return FALSE;
2132 return TRUE;
2133}
2134
2135static bool qt_try_modal( QWidget *widget, QMSG *qmsg, int &ret )
2136{
2137 QWidget * top = 0;
2138
2139 if ( qt_tryModalHelper( widget, &top ) )
2140 return TRUE;
2141
2142 bool block_event = FALSE;
2143 ULONG type = qmsg->msg;
2144
2145 if ( type == WM_CLOSE ) {
2146 block_event = TRUE;
2147 }
2148
2149 return !block_event;
2150}
2151
2152
2153/*****************************************************************************
2154 Popup widget mechanism
2155
2156 openPopup()
2157 Adds a widget to the list of popup widgets
2158 Arguments:
2159 QWidget *widget The popup widget to be added
2160
2161 closePopup()
2162 Removes a widget from the list of popup widgets
2163 Arguments:
2164 QWidget *widget The popup widget to be removed
2165 *****************************************************************************/
2166
2167void QApplication::openPopup( QWidget *popup )
2168{
2169 if ( !popupWidgets ) { // create list
2170 popupWidgets = new QWidgetList;
2171 Q_CHECK_PTR( popupWidgets );
2172 }
2173 popupWidgets->append( popup ); // add to end of list
2174 if ( !popup->isEnabled() )
2175 return;
2176
2177 if ( popupWidgets->count() == 1 && !qt_nograb() )
2178 setAutoCapture( popup->winId() ); // grab mouse/keyboard
2179 // Popups are not focus-handled by the window system (the first
2180 // popup grabbed the keyboard), so we have to do that manually: A
2181 // new popup gets the focus
2182 QFocusEvent::setReason( QFocusEvent::Popup );
2183 if ( popup->focusWidget())
2184 popup->focusWidget()->setFocus();
2185 else
2186 popup->setFocus();
2187 QFocusEvent::resetReason();
2188}
2189
2190void QApplication::closePopup( QWidget *popup )
2191{
2192 if ( !popupWidgets )
2193 return;
2194 popupWidgets->removeRef( popup );
2195 POINTL curPos;
2196 WinQueryPointerPos( HWND_DESKTOP, &curPos );
2197 // flip y coordinate
2198 curPos.y = desktop()->height() - (curPos.y + 1);
2199 replayPopupMouseEvent = !popup->geometry().contains( QPoint(curPos.x, curPos.y) );
2200 if ( popupWidgets->count() == 0 ) { // this was the last popup
2201 popupCloseDownMode = TRUE; // control mouse events
2202 delete popupWidgets;
2203 popupWidgets = 0;
2204 if ( !popup->isEnabled() )
2205 return;
2206 if ( !qt_nograb() ) // grabbing not disabled
2207 releaseAutoCapture();
2208 if ( active_window ) {
2209 QFocusEvent::setReason( QFocusEvent::Popup );
2210 if ( active_window->focusWidget() )
2211 active_window->focusWidget()->setFocus();
2212 else
2213 active_window->setFocus();
2214 QFocusEvent::resetReason();
2215 }
2216 } else {
2217 // Popups are not focus-handled by the window system (the
2218 // first popup grabbed the keyboard), so we have to do that
2219 // manually: A popup was closed, so the previous popup gets
2220 // the focus.
2221 QFocusEvent::setReason( QFocusEvent::Popup );
2222 QWidget* aw = popupWidgets->getLast();
2223 if ( popupWidgets->count() == 1 )
2224 setAutoCapture( aw->winId() );
2225 if (aw->focusWidget())
2226 aw->focusWidget()->setFocus();
2227 else
2228 aw->setFocus();
2229 QFocusEvent::resetReason();
2230 }
2231}
2232
2233
2234
2235/*****************************************************************************
2236 Event translation; translates OS/2 PM events to Qt events
2237 *****************************************************************************/
2238
2239// State holder for LWIN/RWIN and ALTGr keys
2240// (ALTGr is also necessary since OS/2 doesn't report ALTGr as KC_ALT)
2241static int qt_extraKeyState = 0;
2242
2243// State holder for mouse buttons
2244static int qt_buttonState = 0;
2245
2246//
2247// Auto-capturing for mouse press and mouse release
2248//
2249
2250static void setAutoCapture( HWND h )
2251{
2252 if ( autoCaptureWnd )
2253 releaseAutoCapture();
2254 autoCaptureWnd = h;
2255
2256 if ( !qt_buttonState ) {
2257 // all buttons released, we don't actually capture the mouse
2258 // (see QWidget::translateMouseEvent())
2259 autoCaptureReleased = TRUE;
2260 } else {
2261 autoCaptureReleased = FALSE;
2262 WinSetCapture( HWND_DESKTOP, h );
2263 }
2264}
2265
2266static void releaseAutoCapture()
2267{
2268 if ( autoCaptureWnd ) {
2269 if ( !autoCaptureReleased ) {
2270 WinSetCapture( HWND_DESKTOP, 0 );
2271 autoCaptureReleased = TRUE;
2272 }
2273 autoCaptureWnd = 0;
2274 }
2275}
2276
2277
2278//
2279// Mouse event translation
2280//
2281
2282static ushort mouseTbl[] = {
2283 WM_MOUSEMOVE, QEvent::MouseMove, 0,
2284 WM_BUTTON1DOWN, QEvent::MouseButtonPress, Qt::LeftButton,
2285 WM_BUTTON1UP, QEvent::MouseButtonRelease, Qt::LeftButton,
2286 WM_BUTTON1DBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
2287 WM_BUTTON2DOWN, QEvent::MouseButtonPress, Qt::RightButton,
2288 WM_BUTTON2UP, QEvent::MouseButtonRelease, Qt::RightButton,
2289 WM_BUTTON2DBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
2290 WM_BUTTON3DOWN, QEvent::MouseButtonPress, Qt::MidButton,
2291 WM_BUTTON3UP, QEvent::MouseButtonRelease, Qt::MidButton,
2292 WM_BUTTON3DBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
2293//@@TODO (dmik): later (extra buttons)
2294// WM_XBUTTONDOWN, QEvent::MouseButtonPress, Qt::MidButton*2, //### Qt::XButton1/2
2295// WM_XBUTTONUP, QEvent::MouseButtonRelease, Qt::MidButton*2,
2296// WM_XBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton*2,
2297 WM_CONTEXTMENU, QEvent::ContextMenu, 0,
2298 0, 0, 0
2299};
2300
2301static int translateButtonState( USHORT s, int type, int button )
2302{
2303 if ( type == QEvent::MouseButtonPress )
2304 qt_buttonState |= ( button & Qt::MouseButtonMask );
2305 if ( type == QEvent::MouseButtonRelease )
2306 qt_buttonState &= ~( button & Qt::MouseButtonMask );
2307
2308 int bst = qt_buttonState;
2309 if ( type == QEvent::ContextMenu ) {
2310 if ( WinGetKeyState( HWND_DESKTOP, VK_SHIFT ) & 0x8000 )
2311 bst |= Qt::ShiftButton;
2312 if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 )
2313 bst |= Qt::AltButton;
2314 if ( WinGetKeyState( HWND_DESKTOP, VK_CTRL ) & 0x8000 )
2315 bst |= Qt::ControlButton;
2316 } else {
2317 if ( s & KC_SHIFT )
2318 bst |= Qt::ShiftButton;
2319 if ( (s & KC_ALT) )
2320 bst |= Qt::AltButton;
2321 if ( s & KC_CTRL )
2322 bst |= Qt::ControlButton;
2323 }
2324 if ( (qt_extraKeyState & Qt::AltButton) )
2325 bst |= Qt::AltButton;
2326 if ( qt_extraKeyState & Qt::MetaButton )
2327 bst |= Qt::MetaButton;
2328
2329 // Translate from OS/2-style "state after event"
2330 // to X-style "state before event"
2331 if ( type == QEvent::MouseButtonPress ||
2332 type == QEvent::MouseButtonDblClick )
2333 bst &= ~button;
2334 else if ( type == QEvent::MouseButtonRelease )
2335 bst |= button;
2336
2337 return bst;
2338}
2339
2340//@@TODO (dmik): later
2341//// In DnD, the mouse release event never appears, so the
2342//// mouse button state machine must be manually reset
2343///*! \internal */
2344//void QApplication::winMouseButtonUp()
2345//{
2346// qt_button_down = 0;
2347// releaseAutoCapture();
2348//}
2349
2350bool QETWidget::translateMouseEvent( const QMSG &qmsg )
2351{
2352#if 0
2353 static const char *msgNames[] = { // 11 items
2354 "WM_MOUSEMOVE",
2355 "WM_BUTTON1DOWN", "WM_BUTTON1UP", "WM_BUTTON1DBLCLK",
2356 "WM_BUTTON2DOWN", "WM_BUTTON2UP", "WM_BUTTON2DBLCLK",
2357 "WM_BUTTON3DOWN", "WM_BUTTON3UP", "WM_BUTTON3DBLCLK",
2358 "WM_???"
2359 };
2360 int msgIdx = qmsg.msg - WM_MOUSEMOVE;
2361 if (msgIdx < 0 || msgIdx > 9)
2362 msgIdx = 10;
2363 qDebug( "%s (%04lX): [%08lX/%p:%s/%s] %04hd,%04hd hit=%04hX fl=%04hX",
2364 msgNames[msgIdx], qmsg.msg, qmsg.hwnd, this, name(), className(),
2365 SHORT1FROMMP(qmsg.mp1), SHORT2FROMMP(qmsg.mp1),
2366 SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
2367#endif
2368
2369 static QPoint pos; // window pos (y flipped)
2370 static POINTL gpos = { -1, -1 }; // global pos (y flipped)
2371 QEvent::Type type; // event parameters
2372 int button;
2373 int state;
2374 int i;
2375
2376 // candidate for a double click event
2377 static HWND dblClickCandidateWin = 0;
2378
2379//@@TODO (dmik): later
2380// if ( sm_blockUserInput ) //block user interaction during session management
2381// return TRUE;
2382
2383 // Compress mouse move events
2384 if ( qmsg.msg == WM_MOUSEMOVE ) {
2385 QMSG mouseMsg;
2386 mouseMsg.msg = WM_NULL;
2387 while (
2388 WinPeekMsg( 0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
2389 WM_MOUSEMOVE, PM_NOREMOVE )
2390 ) {
2391 if ( mouseMsg.mp2 != qmsg.mp2 )
2392 break; // leave the message in the queue because
2393 // the key state has changed
2394 // Remove the mouse move message
2395 WinPeekMsg( 0, &mouseMsg, qmsg.hwnd, WM_MOUSEMOVE,
2396 WM_MOUSEMOVE, PM_REMOVE );
2397 }
2398 // Update the passed in QMSG structure with the
2399 // most recent one.
2400 if ( mouseMsg.msg != WM_NULL ) {
2401 PQMSG pqmsg = (PQMSG)&qmsg;
2402 pqmsg->mp1 = mouseMsg.mp1;
2403 pqmsg->mp2 = mouseMsg.mp2;
2404 pqmsg->time = mouseMsg.time;
2405 pqmsg->ptl.x = (short)SHORT1FROMMP(mouseMsg.mp1);
2406 pqmsg->ptl.y = (short)SHORT2FROMMP(mouseMsg.mp1);
2407 WinMapWindowPoints( pqmsg->hwnd, HWND_DESKTOP, &pqmsg->ptl, 1 );
2408 // flip y coordinate
2409 pqmsg->ptl.y = QApplication::desktop()->height() - (pqmsg->ptl.y + 1);
2410 }
2411 }
2412
2413 for ( i = 0; mouseTbl[i] && (ULONG)mouseTbl[i] != qmsg.msg; i += 3 )
2414 ;
2415 if ( !mouseTbl[i] )
2416 return FALSE;
2417
2418 type = (QEvent::Type)mouseTbl[++i]; // event type
2419 button = mouseTbl[++i]; // which button
2420//@@TODO (dmik): later (extra buttons)
2421// if ( button > Qt::MidButton ) {
2422// switch( GET_XBUTTON_WPARAM( msg.wParam ) ) {
2423// case XBUTTON1:
2424// button = Qt::MidButton*2; //### XButton1;
2425// break;
2426// case XBUTTON2:
2427// button = Qt::MidButton*4; //### XButton2;
2428// break;
2429// }
2430// }
2431 state = translateButtonState( SHORT2FROMMP(qmsg.mp2), type, button ); // button state
2432
2433 // It seems, that PM remembers only the WM_BUTTONxDOWN message (instead of
2434 // the WM_BUTTONxDOWN + WM_BUTTONxUP pair) to detect whether the next button
2435 // press should be converted to WM_BUTTONxDBLCLK or not. As a result, the
2436 // window gets WM_BUTTONxDBLCLK even if it didn't receive the preceeding
2437 // WM_BUTTONxUP (this happens if we issue WinSetCapture() on the first
2438 // WM_BUTTONxDOWN), which is obviously wrong and makes problems for QWorkspace
2439 // and QTitleBar system menu handlers that don't expect a double click after
2440 // they opened a popup menu. dblClickCandidateWin is reset to 0 (see a ***
2441 // remmark below) when WinSetCapture is issued that directs messages
2442 // to a window other than one received the first WM_BUTTONxDOWN,
2443 // so we can fix it here. Note that if there is more than one popup window,
2444 // WinSetCapture is issued only for the first of them, so this code doesn't
2445 // prevent MouseButtonDblClick from being delivered to a popup when another
2446 // popup gets closed on the first WM_BUTTONxDOWN (Qt/Win32 behaves in the
2447 // same way, so it's left for compatibility).
2448 if ( type == QEvent::MouseButtonPress ) {
2449 dblClickCandidateWin = qmsg.hwnd;
2450 } else if ( type == QEvent::MouseButtonDblClick ) {
2451 if ( dblClickCandidateWin != qmsg.hwnd )
2452 type = QEvent::MouseButtonPress;
2453 dblClickCandidateWin = 0;
2454 }
2455
2456 if ( type == QEvent::ContextMenu ) {
2457 QPoint g = QPoint( qmsg.ptl.x, qmsg.ptl.y );
2458 QContextMenuEvent e( QContextMenuEvent::Mouse, mapFromGlobal( g ), g, state );
2459 QApplication::sendSpontaneousEvent( this, &e );
2460 return TRUE;
2461 }
2462
2463 if ( type == QEvent::MouseMove ) {
2464 if ( !(state & MouseButtonMask) )
2465 qt_button_down = 0;
2466#ifndef QT_NO_CURSOR
2467 QCursor *c = qt_grab_cursor();
2468 if ( !c )
2469 c = QApplication::overrideCursor();
2470 if ( c ) // application cursor defined
2471 WinSetPointer( HWND_DESKTOP, c->handle() );
2472 else if ( isEnabled() ) // use widget cursor if widget is enabled
2473 WinSetPointer( HWND_DESKTOP, cursor().handle() );
2474 else {
2475 QWidget *parent = parentWidget();
2476 while ( parent && !parent->isEnabled() )
2477 parent = parent->parentWidget();
2478 if ( parent )
2479 WinSetPointer( HWND_DESKTOP, parent->cursor().handle() );
2480 }
2481#else
2482 // pass the msg to the default proc to let it change the pointer shape
2483 WinDefWindowProc( qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2 );
2484#endif
2485 if ( curWin != winId() ) { // new current window
2486//@@TODO (dmik): add CS_HITTEST to our window classes and handle WM_HITTEST,
2487// otherwise disabled windows will not get mouse events?
2488 qt_dispatchEnterLeave( this, QWidget::find(curWin) );
2489 curWin = winId();
2490 }
2491
2492 // *** PM posts a dummy WM_MOUSEMOVE message (with the same, uncahnged
2493 // pointer coordinates) after every WinSetCapture that actually changes
2494 // the capture target. I.e., if the argument of WinSetCapture is
2495 // NULLHANDLE, a window under the mouse pointer gets this message,
2496 // otherwise the specified window gets it unless it is already under the
2497 // pointer. We use this info to check whether the window can be a double
2498 // click candidate (see above).
2499 if ( qmsg.ptl.x == gpos.x && qmsg.ptl.y == gpos.y ) {
2500 if ( dblClickCandidateWin != qmsg.hwnd )
2501 dblClickCandidateWin = 0;
2502 return TRUE;
2503 }
2504
2505 gpos = qmsg.ptl;
2506
2507 if ( state == 0 && autoCaptureWnd == 0 && !hasMouseTracking() &&
2508 !QApplication::hasGlobalMouseTracking() )
2509 return TRUE; // no button
2510
2511 pos = mapFromGlobal( QPoint(gpos.x, gpos.y) );
2512 } else {
2513 if ( type == QEvent::MouseButtonPress && !isActiveWindow() )
2514 setActiveWindow();
2515
2516 gpos = qmsg.ptl;
2517 pos = mapFromGlobal( QPoint(gpos.x, gpos.y) );
2518
2519 if ( type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick ) { // mouse button pressed
2520 // Magic for masked widgets
2521 qt_button_down = findChildWidget( this, pos );
2522 if ( !qt_button_down || !qt_button_down->testWFlags(WMouseNoMask) )
2523 qt_button_down = this;
2524 }
2525 }
2526
2527 // detect special button states
2528 enum { Other, SinglePressed, AllReleased } btnState = Other;
2529 int bs = state & MouseButtonMask;
2530 if ( (type == QEvent::MouseButtonPress ||
2531 type == QEvent::MouseButtonDblClick) && bs == 0
2532 ) {
2533 btnState = SinglePressed;
2534 } else if ( type == QEvent::MouseButtonRelease && bs == button ) {
2535 btnState = AllReleased;
2536 }
2537
2538 if ( qApp->inPopupMode() ) { // in popup mode
2539 if ( !autoCaptureReleased && btnState == AllReleased ) {
2540 // in order to give non-Qt windows the opportunity to see mouse
2541 // messages while our popups are active we need to release the
2542 // mouse capture which is absolute in OS/2. we do it directly
2543 // (not through releaseAutoCapture()) in order to keep
2544 // autoCaptureWnd nonzero to keep forwarding mouse move events
2545 // (actually sent to one of Qt widgets) to the active popup.
2546 autoCaptureReleased = TRUE;
2547 WinSetCapture( HWND_DESKTOP, 0 );
2548 } else if ( autoCaptureReleased && btnState == SinglePressed ) {
2549 // set the mouse capture back if a button is pressed.
2550 if ( autoCaptureWnd ) {
2551 autoCaptureReleased = FALSE;
2552 WinSetCapture( HWND_DESKTOP, autoCaptureWnd );
2553 }
2554 }
2555
2556 replayPopupMouseEvent = FALSE;
2557 QWidget* activePopupWidget = qApp->activePopupWidget();
2558 QWidget *popup = activePopupWidget;
2559
2560 if ( popup != this ) {
2561 if ( testWFlags(WType_Popup) && rect().contains(pos) )
2562 popup = this;
2563 else // send to last popup
2564 pos = popup->mapFromGlobal( QPoint(gpos.x, gpos.y) );
2565 }
2566 QWidget *popupChild = findChildWidget( popup, pos );
2567 bool releaseAfter = FALSE;
2568 switch ( type ) {
2569 case QEvent::MouseButtonPress:
2570 case QEvent::MouseButtonDblClick:
2571 popupButtonFocus = popupChild;
2572 break;
2573 case QEvent::MouseButtonRelease:
2574 releaseAfter = TRUE;
2575 break;
2576 default:
2577 break; // nothing for mouse move
2578 }
2579
2580 if ( popupButtonFocus ) {
2581 QMouseEvent e( type,
2582 popupButtonFocus->mapFromGlobal(QPoint(gpos.x,gpos.y)),
2583 QPoint(gpos.x,gpos.y), button, state );
2584 QApplication::sendSpontaneousEvent( popupButtonFocus, &e );
2585 if ( releaseAfter ) {
2586 popupButtonFocus = 0;
2587 }
2588 } else if ( popupChild ) {
2589 QMouseEvent e( type,
2590 popupChild->mapFromGlobal(QPoint(gpos.x,gpos.y)),
2591 QPoint(gpos.x,gpos.y), button, state );
2592 QApplication::sendSpontaneousEvent( popupChild, &e );
2593 } else {
2594 QMouseEvent e( type, pos, QPoint(gpos.x,gpos.y), button, state );
2595 QApplication::sendSpontaneousEvent( popup, &e );
2596 }
2597
2598 if ( releaseAfter )
2599 qt_button_down = 0;
2600
2601 if ( type == QEvent::MouseButtonPress
2602 && qApp->activePopupWidget() != activePopupWidget
2603 && replayPopupMouseEvent ) {
2604 // the popup dissappeared. Replay the event
2605 QWidget* w = QApplication::widgetAt( gpos.x, gpos.y, TRUE );
2606 if ( w && !qt_blocked_modal( w ) ) {
2607 QPoint wpos = w->mapFromGlobal(QPoint(gpos.x, gpos.y));
2608 // flip y coordinate
2609 wpos.ry() = w->height() - (wpos.y() + 1);
2610 QMSG newQmsg = qmsg;
2611 newQmsg.hwnd = w->winId();
2612 newQmsg.mp1 = MPFROM2SHORT( wpos.x(), wpos.y() );
2613 ((QETWidget *) w)->translateMouseEvent( newQmsg );
2614 }
2615 }
2616 } else { // not popup mode
2617 if ( btnState == SinglePressed && QWidget::mouseGrabber() == 0 )
2618 setAutoCapture( winId() );
2619 else if ( btnState == AllReleased && QWidget::mouseGrabber() == 0 )
2620 releaseAutoCapture();
2621
2622 QWidget *widget = this;
2623 QWidget *w = QWidget::mouseGrabber();
2624 if ( !w )
2625 w = qt_button_down;
2626 if ( w && w != this ) {
2627 widget = w;
2628 pos = w->mapFromGlobal(QPoint(gpos.x, gpos.y));
2629 }
2630
2631 if ( type == QEvent::MouseButtonRelease &&
2632 (state & (~button) & ( MouseButtonMask )) == 0 ) {
2633 qt_button_down = 0;
2634 }
2635
2636 QMouseEvent e( type, pos, QPoint(gpos.x,gpos.y), button, state );
2637 QApplication::sendSpontaneousEvent( widget, &e );
2638
2639 if ( type != QEvent::MouseMove )
2640 pos.rx() = pos.ry() = -9999; // init for move compression
2641 }
2642 return TRUE;
2643}
2644
2645
2646//
2647// Keyboard event translation
2648//
2649
2650static const ushort KeyTbl[] = { // keyboard mapping table
2651 VK_ESC, Qt::Key_Escape, // misc keys
2652 VK_TAB, Qt::Key_Tab,
2653 VK_BACKTAB, Qt::Key_Backtab,
2654 VK_BACKSPACE, Qt::Key_Backspace,
2655 VK_ENTER, Qt::Key_Enter,
2656 VK_NEWLINE, Qt::Key_Return,
2657 VK_INSERT, Qt::Key_Insert,
2658 VK_DELETE, Qt::Key_Delete,
2659 VK_CLEAR, Qt::Key_Clear,
2660 VK_PAUSE, Qt::Key_Pause,
2661 VK_PRINTSCRN, Qt::Key_Print,
2662 VK_SPACE, Qt::Key_Space,
2663 VK_HOME, Qt::Key_Home, // cursor movement
2664 VK_END, Qt::Key_End,
2665 VK_LEFT, Qt::Key_Left,
2666 VK_UP, Qt::Key_Up,
2667 VK_RIGHT, Qt::Key_Right,
2668 VK_DOWN, Qt::Key_Down,
2669 VK_PAGEUP, Qt::Key_Prior,
2670 VK_PAGEDOWN, Qt::Key_Next,
2671 VK_SHIFT, Qt::Key_Shift, // modifiers
2672 VK_CTRL, Qt::Key_Control,
2673 VK_ALT, Qt::Key_Alt,
2674 VK_CAPSLOCK, Qt::Key_CapsLock,
2675 VK_NUMLOCK, Qt::Key_NumLock,
2676 VK_SCRLLOCK, Qt::Key_ScrollLock,
2677 0, 0
2678};
2679
2680// when the compatibility mode is FALSE Qt/OS2 uses the following rule
2681// to calculate QKeyEvent::key() codes when the the alpha-numeric key is
2682// pressed: key code is the ASCII (Latin 1) character code of that key as if
2683// there were no any keyboard modifiers (CTRL, SHIFT, ALT) pressed, with the
2684// exception that alpha characters are uppercased.
2685// when the compatibility mode is TRUE Qt/OS2 behaves mostly like Qt/Win32.
2686Q_EXPORT bool qt_kbd_compatibility = TRUE;
2687//@@TODO (dmik): currentlly, qt_kbd_compatibility is TRUE because
2688// qt_scan2Ascii function below is not well implemented yet (in particular,
2689// it uses the 850 code page that can be not available on some systems...)
2690
2691// cache table to store Qt::Key_... values for 256 hardware scancodes
2692// (even byte is for non-shifted keys, odd byte is for shifted ones).
2693// used to decrease the number of calls to KbdXlate.
2694static uchar ScanTbl[512] = { 0xFF };
2695
2696static uchar qt_scan2Ascii( uchar scan, bool shift )
2697{
2698 uchar ascii = 0;
2699 HFILE kbd;
2700 ULONG dummy;
2701 DosOpen( "KBD$", &kbd, &dummy, 0,
2702 FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
2703 OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL );
2704 // parameter packet
2705 struct CPID {
2706 USHORT idCodePage;
2707 USHORT reserved;
2708 } cpid = { 850, 0 };
2709 ULONG szCpid = sizeof(CPID);
2710 // data packet
2711 KBDTRANS kt;
2712 ULONG szKt = sizeof(KBDTRANS);
2713 // reset all kbd states and modifiers
2714 memset( &kt, 0, szKt );
2715 // reflect Shift state to distinguish between [ and { etc.
2716 if ( qt_kbd_compatibility && shift )
2717 kt.fsState = KBDSTF_RIGHTSHIFT;
2718 kt.chScan = scan;
2719 DosDevIOCtl( kbd, IOCTL_KEYBOARD, KBD_XLATESCAN,
2720 &cpid, szCpid, &szCpid, &kt, szKt, &szKt );
2721 // store in cache
2722 uint idx = scan << 1;
2723 if ( qt_kbd_compatibility && shift )
2724 idx++;
2725 ascii = ScanTbl[idx] = toupper( kt.chChar );
2726 DosClose( kbd );
2727 return ascii;
2728}
2729
2730// translates WM_CHAR to Qt::Key_..., ascii, state and text
2731void translateKeyCode(
2732 CHRMSG &chm, int &code, int &ascii, int &state, QString &text
2733) {
2734 if ( chm.fs & KC_SHIFT )
2735 state |= Qt::ShiftButton;
2736 if ( chm.fs & KC_CTRL )
2737 state |= Qt::ControlButton;
2738 if ( chm.fs & KC_ALT )
2739 state |= Qt::AltButton;
2740 if ( qt_extraKeyState & Qt::MetaButton )
2741 state |= Qt::MetaButton;
2742
2743 unsigned char ch = chm.chr;
2744
2745 if ( chm.fs & KC_VIRTUALKEY ) {
2746 if ( !chm.vkey ) {
2747 // The only known situation when KC_VIRTUALKEY is present but
2748 // vkey is zero is when Alt+Shift is pressed to switch the
2749 // keyboard layout state from latin to national and back.
2750 // It seems that this way the system informs applications about
2751 // layout changes: chm.chr is 0xF1 when the user switches
2752 // to the national layout (i.e. presses Alt + Left Shift)
2753 // and it is 0xF0 when he switches back (presses Alt + Right Shift).
2754 // We assume this and restore fs, vkey, scancode and chr accordingly.
2755 if ( chm.chr == 0xF0 || chm.chr == 0xF1 ) {
2756 chm.fs |= KC_ALT | KC_SHIFT;
2757 chm.vkey = VK_SHIFT;
2758 chm.scancode = chm.chr == 0xF1 ? 0x2A : 0x36;
2759 chm.chr = ch = 0;
2760 state |= Qt::AltButton | Qt::ShiftButton;
2761 // code will be assigned by the normal procedure below
2762 }
2763 }
2764 if ( chm.vkey >= VK_F1 && chm.vkey <= VK_F24 ) {
2765 // function keys
2766 code = Qt::Key_F1 + (chm.vkey - VK_F1);
2767 } else if ( chm.vkey == VK_ALTGRAF ) {
2768 code = Qt::Key_Alt;
2769 if ( !(chm.fs & KC_KEYUP) )
2770 qt_extraKeyState |= Qt::AltButton;
2771 else
2772 qt_extraKeyState &= ~Qt::AltButton;
2773 } else {
2774 // any other keys
2775 int i = 0;
2776 while ( KeyTbl[i] ) {
2777 if ( chm.vkey == (int)KeyTbl[i] ) {
2778 code = KeyTbl[i+1];
2779 break;
2780 }
2781 i += 2;
2782 }
2783 }
2784 } else {
2785 if ( qt_kbd_compatibility && ch && ch < 0x80 ) {
2786 code = toupper( ch );
2787 } else if ( !qt_kbd_compatibility && (chm.fs & KC_CHAR) && isalpha( ch ) ) {
2788 code = toupper( ch );
2789 } else {
2790 // detect some special keys that have a pseudo char code
2791 // in the high byte of chm.chr (probably this is less
2792 // device-dependent than scancode)
2793 switch ( chm.chr ) {
2794 case 0xEC00: // LWIN
2795 case 0xED00: // RWIN
2796 code = Qt::Key_Meta;
2797 if ( !(chm.fs & KC_KEYUP) )
2798 qt_extraKeyState |= Qt::MetaButton;
2799 else
2800 qt_extraKeyState &= ~Qt::MetaButton;
2801 break;
2802 case 0xEE00: // WINAPP (menu with arrow)
2803 code = Qt::Key_Menu;
2804 break;
2805 case 0x5600: // additional '\' (0x56 is actually its scancode)
2806 ch = state & Qt::ShiftButton ? '|' : '\\';
2807 if ( qt_kbd_compatibility ) code = ch;
2808 else code = '\\';
2809 break;
2810 default:
2811 if ( qt_kbd_compatibility ) break;
2812 // deduce Qt::Key... from scancode
2813 if ( ScanTbl[0] == 0xFF )
2814 memset( &ScanTbl, 0, sizeof(ScanTbl) );
2815 uint idx = chm.scancode << 1;
2816 if ( qt_kbd_compatibility && (state & Qt::ShiftButton) )
2817 idx++;
2818 code = ScanTbl[idx];
2819 if ( !code )
2820 // not found in cache
2821 code = qt_scan2Ascii( chm.scancode, (state & Qt::ShiftButton) );
2822 break;
2823 }
2824 }
2825 }
2826 // check extraState AFTER updating it
2827 if ( qt_extraKeyState & Qt::AltButton )
2828 state |= Qt::AltButton;
2829
2830 // detect numeric keypad keys
2831 if ( chm.vkey == VK_ENTER || chm.vkey == VK_NUMLOCK ) {
2832 // these always come from the numpad
2833 state |= Qt::Keypad;
2834 } else if (
2835 ((chm.vkey >= VK_PAGEUP && chm.vkey <= VK_DOWN) ||
2836 chm.vkey == VK_INSERT || chm.vkey == VK_DELETE)
2837 ) {
2838 if ( ch != 0xE0 ) {
2839 state |= Qt::Keypad;
2840 if ( ch ) {
2841 // override code to make it Qt::Key_0..Qt::Key_9 etc.
2842 code = toupper( ch );
2843 }
2844 } else {
2845 ch = 0;
2846 }
2847 }
2848 // detect other numpad keys. OS/2 doesn't assign virtual keys to them
2849 // so use scancodes (it can be device-dependent, is there a better way?)
2850 switch ( chm.scancode ) {
2851 case 0x4C: // 5
2852 // scancode is zero if Numlock is set
2853 if ( !code ) code = Qt::Key_Clear;
2854 state |= Qt::Keypad;
2855 break;
2856 case 0x37: // *
2857 // OS/2 assigns VK_PRINTSCRN to it when pressed with Shift, also
2858 // it sets chr to zero when it is released with Alt or Ctrl
2859 // leaving vkey as zero too, and does few other strange things --
2860 // override them all
2861 code = Qt::Key_Asterisk;
2862 state |= Qt::Keypad;
2863 break;
2864 case 0x5C: // /
2865 code = Qt::Key_Slash;
2866 // fall through
2867 case 0x4A: // -
2868 case 0x4E: // +
2869 // the code for the above two is obtained by KbdXlate above
2870 state |= Qt::Keypad;
2871 break;
2872 }
2873
2874 if ( (state & Qt::ControlButton) && !(state & Qt::Keypad) ) {
2875 if ( !(state & Qt::AltButton) ) {
2876 unsigned char cch = toupper( ch ), newCh = 0;
2877 // Ctrl + A..Z etc. produce ascii from 0x01 to 0x1F
2878 if ( cch >= 0x41 && cch <= 0x5F ) newCh = cch - 0x40;
2879 // the below emulates OS/2 functionality. It differs from
2880 // Win32 one.
2881 else if ( cch == 0x36 && !(state & Qt::Keypad) ) newCh = 0x1E;
2882 else if ( cch == 0x2D ) newCh = 0x1F;
2883 else if ( cch >= 0x7B && cch <= 0x7D ) newCh = cch - 0x60;
2884 if ( newCh )
2885 ch = newCh;
2886 }
2887 }
2888
2889 ascii = ch;
2890 if ( ascii > 0x7F ) ascii = 0;
2891 if ( ch )
2892//@@TODO (dmik): later: optimize by using UniUconvToUcs directly
2893 text = QString::fromLocal8Bit( (char*)&ch, 1 );
2894}
2895
2896//@@TODO (dmik): do we need to export this also? I don't see that it is used
2897// anywhere in Qt/Win32...
2898//Q_EXPORT int qt_translateKeyCode(int key)
2899//{
2900// return translateKeyCode(key);
2901//}
2902
2903struct KeyRec {
2904 KeyRec(unsigned char s, int c, int a, const QString& t) :
2905 scan(s), code(c), ascii(a), text(t) { }
2906 KeyRec() { }
2907 unsigned char scan;
2908 int code, ascii;
2909 QString text;
2910};
2911
2912static const int maxrecs=64; // User has LOTS of fingers...
2913static KeyRec key_rec[maxrecs];
2914static int nrecs=0;
2915
2916static KeyRec* find_key_rec( unsigned char scan, bool remove )
2917{
2918 KeyRec *result = 0;
2919 for (int i=0; i<nrecs; i++) {
2920 if (key_rec[i].scan == scan) {
2921 if (remove) {
2922 static KeyRec tmp;
2923 tmp = key_rec[i];
2924 while (i+1 < nrecs) {
2925 key_rec[i] = key_rec[i+1];
2926 i++;
2927 }
2928 nrecs--;
2929 result = &tmp;
2930 } else {
2931 result = &key_rec[i];
2932 }
2933 break;
2934 }
2935 }
2936 return result;
2937}
2938
2939static KeyRec* find_key_rec( int code, bool remove )
2940{
2941 KeyRec *result = 0;
2942 for (int i=0; i<nrecs; i++) {
2943 if (key_rec[i].code == code) {
2944 if (remove) {
2945 static KeyRec tmp;
2946 tmp = key_rec[i];
2947 while (i+1 < nrecs) {
2948 key_rec[i] = key_rec[i+1];
2949 i++;
2950 }
2951 nrecs--;
2952 result = &tmp;
2953 } else {
2954 result = &key_rec[i];
2955 }
2956 break;
2957 }
2958 }
2959 return result;
2960}
2961
2962static void store_key_rec(
2963 unsigned char scan, int code, int ascii, const QString& text
2964) {
2965 if ( nrecs == maxrecs ) {
2966#if defined(QT_CHECK_RANGE)
2967 qWarning( "Qt: Internal keyboard buffer overflow" );
2968#endif
2969 return;
2970 }
2971
2972 key_rec[nrecs++] = KeyRec( scan, code, ascii, text );
2973}
2974
2975bool QETWidget::translateKeyEvent( const QMSG &qmsg, bool grab )
2976{
2977 CHRMSG chm = *((PCHRMSG)(((char*)&qmsg) + sizeof(HWND) + sizeof(ULONG)));
2978
2979#if 0
2980 qDebug( "WM_CHAR: [%s] fs: %04X cRepeat: %03d scancode: %02X chr: %04X vkey: %04X %s",
2981 name(), chm.fs, chm.cRepeat, chm.scancode, chm.chr, chm.vkey, (grab ? "{grab}" : "") );
2982#endif
2983
2984 bool k0 = FALSE, k1 = FALSE;
2985 int code = 0, ascii = 0, state = 0;
2986 QString text;
2987
2988//@@TODO (dmik): later
2989// if ( sm_blockUserInput ) // block user interaction during session management
2990// return TRUE;
2991
2992 translateKeyCode( chm, code, ascii, state, text );
2993//@@TODO (dmik): currently WM_CHARs chars with zero virtual code or zero
2994// scancode are totally ignored. -- are they?
2995// if ( !code || !chm.scancode ) return FALSE;
2996
2997 // Invert state logic
2998 if ( code == Key_Alt )
2999 state = state ^ AltButton;
3000 else if ( code == Key_Control )
3001 state = state ^ ControlButton;
3002 else if ( code == Key_Shift )
3003 state = state ^ ShiftButton;
3004
3005 if ( !(chm.fs & KC_KEYUP) ) {
3006 // KEYDOWN
3007 KeyRec* rec = find_key_rec( chm.scancode, FALSE );
3008
3009 if ( state == Qt::AltButton ) {
3010 // Special handling of global PM hotkeys
3011 switch ( code ) {
3012 case Qt::Key_Space:
3013 if ( qt_show_system_menu( topLevelWidget() ) ) {
3014 // remove the Key_Alt from the buffer (otherwise we will
3015 // not get the next "Alt pressed" event because the
3016 // "Alt depressed" event, that must preceed it, well be
3017 // eaten by the system)
3018//@@TODO (dmik): do the same for other global keys (ALT+TAB, ALT+ESC, CTRL+ESC)
3019// by handling this situation when we obtain/loose focus)
3020 find_key_rec( Qt::Key_Alt, TRUE );
3021 }
3022 return TRUE;
3023 case Qt::Key_F4:
3024 // we handle this key combination ourselves because not
3025 // all top-level widgets have the system menu
3026 WinPostMsg( topLevelWidget()->winFId(), WM_CLOSE, 0, 0 );
3027 // see the comment above
3028 find_key_rec( Qt::Key_Alt, TRUE );
3029 return TRUE;
3030 default:
3031 break;
3032 }
3033 }
3034
3035 if ( rec ) {
3036 // it is already down (so it is auto-repeating)
3037 if ( rec->code < Key_Shift || rec->code > Key_ScrollLock ) {
3038 k0 = sendKeyEvent( QEvent::KeyRelease, rec->code, rec->ascii,
3039 state, grab, rec->text, TRUE);
3040 k1 = sendKeyEvent( QEvent::KeyPress, rec->code, rec->ascii,
3041 state, grab, rec->text, TRUE);
3042 }
3043 } else {
3044 // map shift+tab to shift+backtab, QAccel knows about it
3045 // and will handle it
3046 if ( code == Key_Tab && ( state & ShiftButton ) == ShiftButton )
3047 code = Key_BackTab;
3048 store_key_rec( chm.scancode, code, ascii, text );
3049 k0 = sendKeyEvent( QEvent::KeyPress, code, ascii,
3050 state, grab, text );
3051 }
3052 } else {
3053 // KEYUP
3054 KeyRec* rec = find_key_rec( chm.scancode, TRUE );
3055 if ( !rec ) {
3056 // Someone ate the key down event
3057 } else {
3058 k0 = sendKeyEvent( QEvent::KeyRelease, rec->code, rec->ascii,
3059 state, grab, rec->text);
3060
3061 // keyboard context menu event
3062 if ( rec->code == Key_Menu && !state )
3063 WinPostMsg( qmsg.hwnd, WM_CONTEXTMENU, 0, MPFROM2SHORT( 0, 1 ) );
3064 }
3065 }
3066
3067//@@TODO (dmik): remove
3068// qDebug("WM_CHAR: RESULT = %d", (k0 || k1));
3069 return k0 || k1;
3070}
3071
3072#ifndef QT_NO_WHEELEVENT
3073bool QETWidget::translateWheelEvent( const QMSG &qmsg )
3074{
3075 enum { WHEEL_DELTA = 120 };
3076
3077//@@TODO (dmik): later
3078// if ( sm_blockUserInput ) // block user interaction during session management
3079// return TRUE;
3080
3081 // consume duplicate wheel events sent by the AMouse driver to emulate
3082 // multiline scrolls. we need this since currently Qt (QScrollBar, for
3083 // instance) maintains the number of lines to scroll per wheel rotation
3084 // (including the special handling of CTRL and SHIFT modifiers) on its own
3085 // and doesn't have a setting to tell it to be aware of system settings
3086 // for the mouse wheel. if we had processed events as they are, we would
3087 // get a confusing behavior (too many lines scrolled etc.).
3088 {
3089 int devh = QApplication::desktop()->height();
3090 QMSG wheelMsg;
3091 while (
3092 WinPeekMsg( 0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_NOREMOVE )
3093 ) {
3094 // PM bug: ptl contains SHORT coordinates although fields are LONG
3095 wheelMsg.ptl.x = (short) wheelMsg.ptl.x;
3096 wheelMsg.ptl.y = (short) wheelMsg.ptl.y;
3097 // flip y coordinate
3098 wheelMsg.ptl.y = devh - (wheelMsg.ptl.y + 1);
3099 if (
3100 wheelMsg.mp1 != qmsg.mp1 ||
3101 wheelMsg.mp2 != qmsg.mp2 ||
3102 wheelMsg.ptl.x != qmsg.ptl.x ||
3103 wheelMsg.ptl.y != qmsg.ptl.y
3104 )
3105 break;
3106 WinPeekMsg( 0, &wheelMsg, qmsg.hwnd, qmsg.msg, qmsg.msg, PM_REMOVE );
3107 }
3108 }
3109
3110 int delta;
3111 USHORT cmd = SHORT2FROMMP(qmsg.mp2);
3112 switch ( cmd ) {
3113 case SB_LINEUP:
3114 case SB_PAGEUP:
3115 delta = WHEEL_DELTA;
3116 break;
3117 case SB_LINEDOWN:
3118 case SB_PAGEDOWN:
3119 delta = -WHEEL_DELTA;
3120 break;
3121 default:
3122 return FALSE;
3123 }
3124
3125 int state = 0;
3126 if ( WinGetKeyState( HWND_DESKTOP, VK_SHIFT ) & 0x8000 )
3127 state |= ShiftButton;
3128 if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 ||
3129 (qt_extraKeyState & Qt::AltButton)
3130 )
3131 state |= AltButton;
3132 if ( WinGetKeyState( HWND_DESKTOP, VK_CTRL ) & 0x8000 )
3133 state |= ControlButton;
3134 if ( qt_extraKeyState & Qt::MetaButton )
3135 state |= MetaButton;
3136
3137 Orientation orient;
3138 // Alt inverts scroll orientation (Qt/Win32 behavior)
3139 if ( state & AltButton )
3140 orient = qmsg.msg == WM_VSCROLL ? Horizontal : Vertical;
3141 else
3142 orient = qmsg.msg == WM_VSCROLL ? Vertical : Horizontal;
3143
3144 QPoint globalPos (qmsg.ptl.x, qmsg.ptl.y);
3145
3146 // if there is a widget under the mouse and it is not shadowed
3147 // by modality, we send the event to it first
3148 int ret = 0;
3149 QWidget* w = QApplication::widgetAt( globalPos, TRUE );
3150 if ( !w || !qt_try_modal( w, (QMSG*)&qmsg, ret ) )
3151 w = this;
3152
3153 // send the event to the widget or its ancestors
3154 {
3155 QWidget* popup = qApp->activePopupWidget();
3156 if ( popup && w->topLevelWidget() != popup )
3157 popup->close();
3158 QWheelEvent e( w->mapFromGlobal( globalPos ), globalPos, delta, state, orient );
3159 if ( QApplication::sendSpontaneousEvent( w, &e ) )
3160 return TRUE;
3161 }
3162
3163 // send the event to the widget that has the focus or its ancestors, if different
3164 if ( w != qApp->focusWidget() && ( w = qApp->focusWidget() ) ) {
3165 QWidget* popup = qApp->activePopupWidget();
3166 if ( popup && w->topLevelWidget() != popup )
3167 popup->close();
3168 QWheelEvent e( w->mapFromGlobal( globalPos ), globalPos, delta, state, orient );
3169 if ( QApplication::sendSpontaneousEvent( w, &e ) )
3170 return TRUE;
3171 }
3172 return FALSE;
3173}
3174#endif
3175
3176static bool isModifierKey(int code)
3177{
3178 return code >= Qt::Key_Shift && code <= Qt::Key_ScrollLock;
3179}
3180
3181bool QETWidget::sendKeyEvent( QEvent::Type type, int code, int ascii,
3182 int state, bool grab, const QString& text,
3183 bool autor )
3184{
3185 if ( type == QEvent::KeyPress && !grab ) {
3186 // send accel events if the keyboard is not grabbed
3187 QKeyEvent a( type, code, ascii, state, text, autor, QMAX(1, int(text.length())) );
3188 if ( qt_tryAccelEvent( this, &a ) )
3189 return TRUE;
3190 }
3191 if ( !isEnabled() )
3192 return FALSE;
3193 QKeyEvent e( type, code, ascii, state, text, autor, QMAX(1, int(text.length())) );
3194 QApplication::sendSpontaneousEvent( this, &e );
3195 if ( !isModifierKey(code) && state == Qt::AltButton
3196 && ((code>=Key_A && code<=Key_Z) || (code>=Key_0 && code<=Key_9))
3197 && type == QEvent::KeyPress && !e.isAccepted() )
3198 QApplication::beep(); // emulate PM behavior
3199 return e.isAccepted();
3200}
3201
3202
3203//
3204// Paint event translation
3205//
3206bool QETWidget::translatePaintEvent( const QMSG & )
3207{
3208 HPS displayPS = qt_display_ps();
3209
3210#if !defined (QT_PM_NO_WIDGETMASK)
3211 // Since we don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN bits (see
3212 // qwidget_pm.cpp), we have to validate areas that intersect with our
3213 // children and siblings, taking their clip regions into account.
3214 validateObstacles();
3215#endif
3216
3217 HRGN hrgn = GpiCreateRegion( displayPS, 0, NULL );
3218 LONG rc = WinQueryUpdateRegion( winId(), hrgn );
3219 if ( rc == RGN_ERROR ) {
3220 GpiDestroyRegion( displayPS, hrgn );
3221 hps = 0;
3222 clearWState( WState_InPaintEvent );
3223 return FALSE;
3224 }
3225
3226 setWState( WState_InPaintEvent );
3227 RECTL rcl;
3228 hps = WinBeginPaint( winId(), 0, &rcl );
3229
3230 // convert to width and height
3231 rcl.xRight -= rcl.xLeft;
3232 rcl.yTop -= rcl.yBottom;
3233
3234 // it's possible that the update rectangle is empty
3235 if ( !rcl.xRight || !rcl.yTop ) {
3236 WinEndPaint( hps );
3237 GpiDestroyRegion( displayPS, hrgn );
3238 hps = 0;
3239 clearWState( WState_InPaintEvent );
3240 return TRUE;
3241 }
3242
3243#if !defined (QT_PM_NO_WIDGETMASK)
3244 if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
3245 // Correct the update region by intersecting it with the clip
3246 // region (PM doesn't do that itself). It is necessary
3247 // to have a correct QRegion in QPaintEvent.
3248 HRGN hcrgn = GpiCreateRegion( displayPS, 0, NULL );
3249 WinQueryClipRegion( winId(), hcrgn );
3250 GpiCombineRegion( displayPS, hrgn, hrgn, hcrgn, CRGN_AND );
3251 GpiDestroyRegion( displayPS, hcrgn );
3252 }
3253#endif
3254
3255 // flip y coordinate
3256 rcl.yBottom = height() - (rcl.yBottom + rcl.yTop);
3257
3258 // erase background
3259#if !defined (DEBUG_REPAINTRESIZE)
3260 bool erase = !( testWFlags( WRepaintNoErase ) );
3261#else
3262 // Some oldish Qt widgets think that if they specify WRepaintNoErase but
3263 // not WResizeNoErase, the background should still be erased for them
3264 // in *repaint* events. The code below is left to debug these widgets
3265 // (to ensure this is the exact cause of repaint problems)
3266 bool erase = testWFlags( WRepaintNoErase | WResizeNoErase ) != WRepaintNoErase | WResizeNoErase;
3267#endif
3268 if ( erase )
3269 this->erase( rcl.xLeft, rcl.yBottom,
3270 rcl.xRight, rcl.yTop );
3271
3272#if defined (DEBUG_REPAINTRESIZE)
3273 qDebug( "WM_PAINT: [%s/%s/%08X] %ld,%ld; %ld,%ld erase: %d",
3274 name(), className(), widget_flags,
3275 rcl.xLeft, rcl.yBottom, rcl.xRight, rcl.yTop, erase );
3276#endif
3277
3278 // create a region that will take ownership of hrgn
3279 QRegion rgn( hrgn, height() );
3280
3281 QPaintEvent e( rgn, QRect( rcl.xLeft, rcl.yBottom, rcl.xRight, rcl.yTop ),
3282 erase );
3283 QApplication::sendSpontaneousEvent( this, (QEvent*) &e );
3284
3285 WinEndPaint( hps );
3286 hps = 0;
3287 clearWState( WState_InPaintEvent );
3288 return TRUE;
3289}
3290
3291//
3292// Window move and resize (configure) events
3293//
3294
3295bool QETWidget::translateConfigEvent( const QMSG &qmsg )
3296{
3297 if ( !testWState(WState_Created) ) // in QWidget::create()
3298 return TRUE;
3299
3300 WId fId = winFId();
3301 ULONG fStyle = WinQueryWindowULong( fId, QWL_STYLE );
3302 if ( testWState( WState_ConfigPending ) ) {
3303 // it's possible that we're trying to set the frame size smaller
3304 // than it possible for WC_FRAME in QWidget::internalSetGeometry().
3305 // here we correct this (crect there is set before WinSetWindowPos()
3306 // that sends WM_SIZE).
3307 QSize newSize( SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
3308 if ( qmsg.msg == WM_SIZE && size() != newSize ) {
3309 if ( !(fStyle & WS_MINIMIZED) )
3310 crect.setSize( newSize );
3311 }
3312 return TRUE;
3313 }
3314 setWState( WState_ConfigPending ); // set config flag
3315 QRect cr = geometry();
3316 if ( qmsg.msg == WM_SIZE ) { // resize event
3317 QSize oldSize = size();
3318 QSize newSize( SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
3319 cr.setSize( newSize );
3320 if ( !(fStyle & WS_MINIMIZED) )
3321 crect = cr;
3322 if ( isTopLevel() ) { // update caption/icon text
3323 createTLExtra();
3324 QString txt;
3325 if ( (fStyle & WS_MAXIMIZED) && !!iconText() )
3326 txt = iconText();
3327 else
3328 if ( !caption().isNull() )
3329 txt = caption();
3330
3331 if ( !!txt ) {
3332 WinSetWindowText( fId, txt.local8Bit() );
3333 }
3334 }
3335 if ( !(fStyle & WS_MINIMIZED) && oldSize != newSize) {
3336#if !defined (QT_PM_NO_WIDGETMASK)
3337 // Spontaneous (external to Qt) WM_SIZE messages should occur only
3338 // on top-level widgets. If we get them for a non top-level widget,
3339 // the result will most likely be incorrect because widget masks will
3340 // not be properly processed (i.e. in the way it is done in
3341 // QWidget::internalSetGeometry() when the geometry is changed from
3342 // within Qt). So far, I see no need to support this (who will ever
3343 // need to move a non top-level window of a foreign process?).
3344 Q_ASSERT( isTopLevel() );
3345#endif
3346 if ( isVisible() ) {
3347 QResizeEvent e( newSize, oldSize );
3348 QApplication::sendSpontaneousEvent( this, &e );
3349 if ( !testWFlags( WStaticContents ) )
3350 repaint( !testWFlags(WResizeNoErase) );
3351#if !defined (QT_PM_NO_WIDGETMASK)
3352 // Flush WM_PAINT messages here to update window contents
3353 // instantly while tracking the resize frame (normally these
3354 // messages are delivered after resizing is stopped for some
3355 // time). It makes resizing a bit slower but gives a better look
3356 // (no invalid window contents can be seen during resize).
3357 // The alternative could be to erase the background only
3358 // (similarly to Win32), but we need to do it for every
3359 // non-toplevel window, which can be also time-consuming
3360 WinUpdateWindow( winId() );
3361#endif
3362 } else {
3363 QResizeEvent *e = new QResizeEvent( newSize, oldSize );
3364 QApplication::postEvent( this, e );
3365 }
3366 }
3367 } else if ( qmsg.msg == WM_MOVE ) { // move event
3368 QPoint oldPos = geometry().topLeft();
3369 SWP swp;
3370 if ( isTopLevel() ) {
3371 WinQueryWindowPos( fId, &swp );
3372 // flip y coordinate
3373 swp.y = QApplication::desktop()->height() - ( swp.y + swp.cy );
3374 QTLWExtra *top = topData();
3375 swp.x += top->fleft;
3376 swp.y += top->ftop;
3377 } else {
3378 WinQueryWindowPos( winId(), &swp );
3379 // flip y coordinate
3380 swp.y = parentWidget()->height() - ( swp.y + swp.cy );
3381 }
3382 QPoint newCPos( swp.x, swp.y );
3383 if ( newCPos != oldPos ) {
3384 cr.moveTopLeft( newCPos );
3385 crect = cr;
3386 if ( isVisible() ) {
3387 QMoveEvent e( newCPos, oldPos ); // cpos (client position)
3388 QApplication::sendSpontaneousEvent( this, &e );
3389 } else {
3390 QMoveEvent * e = new QMoveEvent( newCPos, oldPos );
3391 QApplication::postEvent( this, e );
3392 }
3393 }
3394 }
3395 clearWState( WState_ConfigPending ); // clear config flag
3396 return TRUE;
3397}
3398
3399
3400//
3401// Close window event translation.
3402//
3403// This class is a friend of QApplication because it needs to emit the
3404// lastWindowClosed() signal when the last top level widget is closed.
3405//
3406
3407bool QETWidget::translateCloseEvent( const QMSG & )
3408{
3409 return close(FALSE);
3410}
3411
3412void QApplication::setCursorFlashTime( int msecs )
3413{
3414 WinSetSysValue( HWND_DESKTOP, SV_CURSORRATE, msecs / 2 );
3415 cursor_flash_time = msecs;
3416}
3417
3418int QApplication::cursorFlashTime()
3419{
3420 int blink = (int) WinQuerySysValue( HWND_DESKTOP, SV_CURSORRATE );
3421 if ( !blink )
3422 return cursor_flash_time;
3423 if (blink > 0)
3424 return 2*blink;
3425 return 0;
3426}
3427
3428void QApplication::setDoubleClickInterval( int ms )
3429{
3430 WinSetSysValue( HWND_DESKTOP, SV_DBLCLKTIME, ms );
3431 mouse_double_click_time = ms;
3432}
3433
3434
3435int QApplication::doubleClickInterval()
3436{
3437 int ms = (int) WinQuerySysValue( HWND_DESKTOP, SV_DBLCLKTIME );
3438 if ( ms != 0 )
3439 return ms;
3440 return mouse_double_click_time;
3441}
3442
3443void QApplication::setWheelScrollLines( int n )
3444{
3445 wheel_scroll_lines = n;
3446}
3447
3448int QApplication::wheelScrollLines()
3449{
3450 return wheel_scroll_lines;
3451}
3452
3453void QApplication::setEffectEnabled( Qt::UIEffect effect, bool enable )
3454{
3455#ifndef QT_NO_EFFECTS
3456 switch (effect) {
3457 case UI_AnimateMenu:
3458 if ( enable ) fade_menu = FALSE;
3459 animate_menu = enable;
3460 break;
3461 case UI_FadeMenu:
3462 if ( enable )
3463 animate_menu = TRUE;
3464 fade_menu = enable;
3465 break;
3466 case UI_AnimateCombo:
3467 animate_combo = enable;
3468 break;
3469 case UI_AnimateTooltip:
3470 if ( enable ) fade_tooltip = FALSE;
3471 animate_tooltip = enable;
3472 break;
3473 case UI_FadeTooltip:
3474 if ( enable )
3475 animate_tooltip = TRUE;
3476 fade_tooltip = enable;
3477 break;
3478 case UI_AnimateToolBox:
3479 animate_toolbox = enable;
3480 break;
3481 default:
3482 animate_ui = enable;
3483 break;
3484 }
3485#endif
3486}
3487
3488bool QApplication::isEffectEnabled( Qt::UIEffect effect )
3489{
3490#ifndef QT_NO_EFFECTS
3491 if ( QColor::numBitPlanes() < 16 || !animate_ui )
3492 return FALSE;
3493
3494 switch( effect ) {
3495 case UI_AnimateMenu:
3496 return animate_menu;
3497 case UI_FadeMenu:
3498 return fade_menu;
3499 case UI_AnimateCombo:
3500 return animate_combo;
3501 case UI_AnimateTooltip:
3502 return animate_tooltip;
3503 case UI_FadeTooltip:
3504 return fade_tooltip;
3505 case UI_AnimateToolBox:
3506 return animate_toolbox;
3507 default:
3508 return animate_ui;
3509 }
3510#else
3511 return FALSE;
3512#endif
3513}
3514
3515void QApplication::flush()
3516{
3517}
3518
3519//@@TODO (dmik): later
3520//bool QSessionManager::allowsInteraction()
3521//{
3522// sm_blockUserInput = FALSE;
3523// return TRUE;
3524//}
3525//
3526//bool QSessionManager::allowsErrorInteraction()
3527//{
3528// sm_blockUserInput = FALSE;
3529// return TRUE;
3530//}
3531//
3532//void QSessionManager::release()
3533//{
3534// if ( sm_smActive )
3535// sm_blockUserInput = TRUE;
3536//}
3537//
3538//void QSessionManager::cancel()
3539//{
3540// sm_cancel = TRUE;
3541//}
3542
Note: See TracBrowser for help on using the repository browser.