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

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

Fixed [PM misbehavior]: MouseButtonDblClick messages were delivered to a widget even if it didn't receive the preceeding MouseButtonRelease; as a result, QWorkplace and QTitleBar sysmenu handlers didn't allow to click an MDI widget using a double click on a sysmenu icon.

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