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

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

Transferred Qt for OS/2 version 3.3.1-rc5 sources from the CVS

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