source: trunk/src/gui/kernel/qapplication_mac.mm@ 858

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 124.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/****************************************************************************
43**
44** Copyright (c) 2007-2008, Apple, Inc.
45**
46** All rights reserved.
47**
48** Redistribution and use in source and binary forms, with or without
49** modification, are permitted provided that the following conditions are met:
50**
51** * Redistributions of source code must retain the above copyright notice,
52** this list of conditions and the following disclaimer.
53**
54** * Redistributions in binary form must reproduce the above copyright notice,
55** this list of conditions and the following disclaimer in the documentation
56** and/or other materials provided with the distribution.
57**
58** * Neither the name of Apple, Inc. nor the names of its contributors
59** may be used to endorse or promote products derived from this software
60** without specific prior written permission.
61**
62** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
63** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
64** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
65** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
66** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
67** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
68** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
69** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
70** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
71** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
72** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73**
74****************************************************************************/
75
76#include <Cocoa/Cocoa.h>
77
78#include "qapplication.h"
79#include "qbitarray.h"
80#include "qclipboard.h"
81#include "qcursor.h"
82#include "qdatastream.h"
83#include "qdatetime.h"
84#include "qdesktopwidget.h"
85#include "qdockwidget.h"
86#include "qevent.h"
87#include "qhash.h"
88#include "qlayout.h"
89#include "qmenubar.h"
90#include "qmessagebox.h"
91#include "qmime.h"
92#include "qpixmapcache.h"
93#include "qpointer.h"
94#include "qsessionmanager.h"
95#include "qsettings.h"
96#include "qsocketnotifier.h"
97#include "qstyle.h"
98#include "qstylefactory.h"
99#include "qtextcodec.h"
100#include "qtoolbar.h"
101#include "qvariant.h"
102#include "qwidget.h"
103#include "qcolormap.h"
104#include "qdir.h"
105#include "qdebug.h"
106#include "qtimer.h"
107#include "qurl.h"
108#include "private/qmacinputcontext_p.h"
109#include "private/qpaintengine_mac_p.h"
110#include "private/qcursor_p.h"
111#include "private/qapplication_p.h"
112#include "private/qcolor_p.h"
113#include "private/qwidget_p.h"
114#include "private/qkeymapper_p.h"
115#include "private/qeventdispatcher_mac_p.h"
116#include "private/qeventdispatcher_unix_p.h"
117#include <private/qcocoamenuloader_mac_p.h>
118#include <private/qcocoaapplication_mac_p.h>
119#include <private/qcocoaapplicationdelegate_mac_p.h>
120#include <private/qt_cocoa_helpers_mac_p.h>
121#include <private/qcocoawindow_mac_p.h>
122#include <private/qpixmap_mac_p.h>
123#include <private/qdesktopwidget_mac_p.h>
124#include <private/qeventdispatcher_mac_p.h>
125#include <qvarlengtharray.h>
126
127#ifndef QT_NO_ACCESSIBILITY
128# include "qaccessible.h"
129#endif
130
131#ifndef QT_NO_THREAD
132# include "qmutex.h"
133#endif
134
135#include <unistd.h>
136#include <string.h>
137#include <sys/time.h>
138#include <sys/select.h>
139
140/*****************************************************************************
141 QApplication debug facilities
142 *****************************************************************************/
143//#define DEBUG_EVENTS //like EventDebug but more specific to Qt
144//#define DEBUG_DROPPED_EVENTS
145//#define DEBUG_MOUSE_MAPS
146//#define DEBUG_MODAL_EVENTS
147//#define DEBUG_PLATFORM_SETTINGS
148
149#define QMAC_SPEAK_TO_ME
150#ifdef QMAC_SPEAK_TO_ME
151#include "qregexp.h"
152#endif
153
154#ifndef kThemeBrushAlternatePrimaryHighlightColor
155#define kThemeBrushAlternatePrimaryHighlightColor -5
156#endif
157
158#define kCMDeviceUnregisteredNotification CFSTR("CMDeviceUnregisteredNotification")
159#define kCMDefaultDeviceNotification CFSTR("CMDefaultDeviceNotification")
160#define kCMDeviceProfilesNotification CFSTR("CMDeviceProfilesNotification")
161#define kCMDefaultDeviceProfileNotification CFSTR("CMDefaultDeviceProfileNotification")
162
163QT_BEGIN_NAMESPACE
164
165//for qt_mac.h
166QPaintDevice *qt_mac_safe_pdev = 0;
167QList<QMacWindowChangeEvent*> *QMacWindowChangeEvent::change_events = 0;
168
169/*****************************************************************************
170 Internal variables and functions
171 *****************************************************************************/
172static struct {
173 bool use_qt_time_limit;
174 QPointer<QWidget> last_widget;
175 int last_x, last_y;
176 int last_modifiers, last_button;
177 EventTime last_time;
178} qt_mac_dblclick = { false, 0, -1, -1, 0, 0, -2 };
179
180static bool app_do_modal = false; // modal mode
181extern QWidgetList *qt_modal_stack; // stack of modal widgets
182extern bool qt_tab_all_widgets; // from qapplication.cpp
183bool qt_mac_app_fullscreen = false;
184bool qt_scrollbar_jump_to_pos = false;
185static bool qt_mac_collapse_on_dblclick = true;
186extern int qt_antialiasing_threshold; // from qapplication.cpp
187QWidget * qt_button_down; // widget got last button-down
188QPointer<QWidget> qt_last_mouse_receiver;
189#ifndef QT_MAC_USE_COCOA
190static bool qt_button_down_in_content; // whether the button_down was in the content area.
191static bool qt_mac_previous_press_in_popup_mode = false;
192static bool qt_mac_no_click_through_mode = false;
193static int tablet_button_state = 0;
194#endif
195QPointer<QWidget> qt_mouseover;
196#if defined(QT_DEBUG)
197static bool appNoGrab = false; // mouse/keyboard grabbing
198#endif
199#ifndef QT_MAC_USE_COCOA
200static EventHandlerRef app_proc_handler = 0;
201static EventHandlerUPP app_proc_handlerUPP = 0;
202#endif
203static AEEventHandlerUPP app_proc_ae_handlerUPP = NULL;
204static EventHandlerRef tablet_proximity_handler = 0;
205static EventHandlerUPP tablet_proximity_UPP = 0;
206bool QApplicationPrivate::native_modal_dialog_active;
207
208Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
209
210/*****************************************************************************
211 External functions
212 *****************************************************************************/
213extern void qt_mac_beep(); //qsound_mac.mm
214extern Qt::KeyboardModifiers qt_mac_get_modifiers(int keys); //qkeymapper_mac.cpp
215extern bool qt_mac_can_clickThrough(const QWidget *); //qwidget_mac.cpp
216extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp
217extern OSWindowRef qt_mac_window_for(const QWidget*); //qwidget_mac.cpp
218extern QWidget *qt_mac_find_window(OSWindowRef); //qwidget_mac.cpp
219extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.cpp
220extern bool qt_mac_is_macsheet(const QWidget *); //qwidget_mac.cpp
221extern QString qt_mac_from_pascal_string(const Str255); //qglobal.cpp
222extern void qt_mac_command_set_enabled(MenuRef, UInt32, bool); //qmenu_mac.cpp
223extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); // qapplication.cpp
224
225// Forward Decls
226void onApplicationWindowChangedActivation( QWidget*widget, bool activated );
227void onApplicationChangedActivation( bool activated );
228
229static void qt_mac_read_fontsmoothing_settings()
230{
231 qt_applefontsmoothing_enabled = true;
232 int w = 10, h = 10;
233 QImage image(w, h, QImage::Format_RGB32);
234 image.fill(0xffffffff);
235 QPainter p(&image);
236 p.drawText(0, h, "X\\");
237 p.end();
238
239 const int *bits = (const int *) ((const QImage &) image).bits();
240 int bpl = image.bytesPerLine() / 4;
241 for (int y=0; y<w; ++y) {
242 for (int x=0; x<h; ++x) {
243 int r = qRed(bits[x]);
244 int g = qGreen(bits[x]);
245 int b = qBlue(bits[x]);
246 if (r != g || r != b) {
247 qt_applefontsmoothing_enabled = true;
248 return;
249 }
250 }
251 bits += bpl;
252 }
253 qt_applefontsmoothing_enabled = false;
254}
255
256Q_GUI_EXPORT bool qt_mac_execute_apple_script(const char *script, long script_len, AEDesc *ret) {
257 OSStatus err;
258 AEDesc scriptTextDesc;
259 ComponentInstance theComponent = 0;
260 OSAID scriptID = kOSANullScript, resultID = kOSANullScript;
261
262 // set up locals to a known state
263 AECreateDesc(typeNull, 0, 0, &scriptTextDesc);
264 scriptID = kOSANullScript;
265 resultID = kOSANullScript;
266
267 // open the scripting component
268 theComponent = OpenDefaultComponent(kOSAComponentType, typeAppleScript);
269 if (!theComponent) {
270 err = paramErr;
271 goto bail;
272 }
273
274 // put the script text into an aedesc
275 err = AECreateDesc(typeUTF8Text, script, script_len, &scriptTextDesc);
276 if (err != noErr)
277 goto bail;
278
279 // compile the script
280 err = OSACompile(theComponent, &scriptTextDesc, kOSAModeNull, &scriptID);
281 if (err != noErr)
282 goto bail;
283
284 // run the script
285 err = OSAExecute(theComponent, scriptID, kOSANullScript, kOSAModeNull, &resultID);
286
287 // collect the results - if any
288 if (ret) {
289 AECreateDesc(typeNull, 0, 0, ret);
290 if (err == errOSAScriptError)
291 OSAScriptError(theComponent, kOSAErrorMessage, typeChar, ret);
292 else if (err == noErr && resultID != kOSANullScript)
293 OSADisplay(theComponent, resultID, typeChar, kOSAModeNull, ret);
294 }
295bail:
296 AEDisposeDesc(&scriptTextDesc);
297 if (scriptID != kOSANullScript)
298 OSADispose(theComponent, scriptID);
299 if (resultID != kOSANullScript)
300 OSADispose(theComponent, resultID);
301 if (theComponent)
302 CloseComponent(theComponent);
303 return err == noErr;
304}
305
306Q_GUI_EXPORT bool qt_mac_execute_apple_script(const char *script, AEDesc *ret)
307{
308 return qt_mac_execute_apple_script(script, qstrlen(script), ret);
309}
310
311Q_GUI_EXPORT bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret)
312{
313 const QByteArray l = script.toUtf8(); return qt_mac_execute_apple_script(l.constData(), l.size(), ret);
314}
315
316/* Resolution change magic */
317void qt_mac_display_change_callbk(CGDirectDisplayID, CGDisplayChangeSummaryFlags flags, void *)
318{
319#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
320 const bool resized = flags & kCGDisplayDesktopShapeChangedFlag;
321#else
322 Q_UNUSED(flags);
323 const bool resized = true;
324#endif
325 if (resized && qApp) {
326 if (QDesktopWidget *dw = qApp->desktop()) {
327 QResizeEvent *re = new QResizeEvent(dw->size(), dw->size());
328 QApplication::postEvent(dw, re);
329 QCoreGraphicsPaintEngine::cleanUpMacColorSpaces();
330 }
331 }
332}
333
334#ifdef DEBUG_PLATFORM_SETTINGS
335static void qt_mac_debug_palette(const QPalette &pal, const QPalette &pal2, const QString &where)
336{
337 const char *const groups[] = {"Active", "Disabled", "Inactive" };
338 const char *const roles[] = { "WindowText", "Button", "Light", "Midlight", "Dark", "Mid",
339 "Text", "BrightText", "ButtonText", "Base", "Window", "Shadow",
340 "Highlight", "HighlightedText", "Link", "LinkVisited" };
341 if (!where.isNull())
342 qDebug("qt-internal: %s", where.toLatin1().constData());
343 for(int grp = 0; grp < QPalette::NColorGroups; grp++) {
344 for(int role = 0; role < QPalette::NColorRoles; role++) {
345 QBrush b = pal.brush((QPalette::ColorGroup)grp, (QPalette::ColorRole)role);
346 QPixmap pm = b.texture();
347 qDebug(" %s::%s %d::%d::%d [%p]%s", groups[grp], roles[role], b.color().red(),
348 b.color().green(), b.color().blue(), pm.isNull() ? 0 : &pm,
349 pal2.brush((QPalette::ColorGroup)grp, (QPalette::ColorRole)role) != b ? " (*)" : "");
350 }
351 }
352
353}
354#else
355#define qt_mac_debug_palette(x, y, z)
356#endif
357
358//raise a notification
359#ifndef QT_MAC_USE_COCOA
360static NMRec qt_mac_notification = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
361#endif
362void qt_mac_send_notification()
363{
364#ifndef QT_MAC_USE_COCOA
365 //send it
366 qt_mac_notification.nmMark = 1; //non-zero magic number
367 qt_mac_notification.qType = nmType;
368 NMInstall(&qt_mac_notification);
369#else
370 QMacCocoaAutoReleasePool pool;
371 [[NSApplication sharedApplication] requestUserAttention:NSInformationalRequest];
372#endif
373}
374
375void qt_mac_cancel_notification()
376{
377#ifndef QT_MAC_USE_COCOA
378 NMRemove(&qt_mac_notification);
379#else
380 QMacCocoaAutoReleasePool pool;
381 [[NSApplication sharedApplication] cancelUserAttentionRequest:NSInformationalRequest];
382#endif
383}
384
385#ifndef QT_MAC_USE_COCOA
386//find widget (and part) at a given point
387static short qt_mac_window_at(int x, int y, QWidget **w=0)
388{
389 Point p;
390 p.h = x;
391 p.v = y;
392 OSWindowRef wp;
393 WindowPartCode wpc;
394 OSStatus err = FindWindowOfClass(&p, kAllWindowClasses, &wp, &wpc);
395 if(err != noErr) {
396 if(w)
397 (*w) = 0;
398 return wpc;
399 }
400 if(w) {
401 if(wp) {
402 *w = qt_mac_find_window(wp);
403#if 0
404 if(!*w)
405 qWarning("QApplication: qt_mac_window_at: Couldn't find %d",(int)wp);
406#endif
407 } else {
408 *w = 0;
409 }
410 }
411 return wpc;
412}
413
414#endif
415
416void qt_mac_set_app_icon(const QPixmap &pixmap)
417{
418#ifndef QT_MAC_USE_COCOA
419 if(pixmap.isNull()) {
420 RestoreApplicationDockTileImage();
421 } else {
422 CGImageRef img = (CGImageRef)pixmap.macCGHandle();
423 SetApplicationDockTileImage(img);
424 CGImageRelease(img);
425 }
426#else
427 QMacCocoaAutoReleasePool pool;
428 NSImage *image = NULL;
429 if (pixmap.isNull()) {
430 // Get Application icon from bundle
431 image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; // released below
432 } else {
433 image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap));
434 }
435
436 [NSApp setApplicationIconImage:image];
437 [image release];
438#endif
439}
440
441Q_GUI_EXPORT void qt_mac_set_press_and_hold_context(bool b)
442{
443 Q_UNUSED(b);
444 qWarning("qt_mac_set_press_and_hold_context: This functionality is no longer available");
445}
446
447bool qt_nograb() // application no-grab option
448{
449#if defined(QT_DEBUG)
450 return appNoGrab;
451#else
452 return false;
453#endif
454}
455
456void qt_mac_update_os_settings()
457{
458 if (!qApp)
459 return;
460 if (!QApplication::startingUp()) {
461 static bool needToPolish = true;
462 if (needToPolish) {
463 QApplication::style()->polish(qApp);
464 needToPolish = false;
465 }
466 }
467 //focus mode
468 /* First worked as of 10.2.3 */
469 QSettings appleSettings(QLatin1String("apple.com"));
470 QVariant appleValue = appleSettings.value(QLatin1String("AppleKeyboardUIMode"), 0);
471 qt_tab_all_widgets = (appleValue.toInt() & 0x2);
472 //paging mode
473 /* First worked as of 10.2.3 */
474 appleValue = appleSettings.value(QLatin1String("AppleScrollerPagingBehavior"), false);
475 qt_scrollbar_jump_to_pos = appleValue.toBool();
476 //collapse
477 /* First worked as of 10.3.3 */
478 appleValue = appleSettings.value(QLatin1String("AppleMiniaturizeOnDoubleClick"), true);
479 qt_mac_collapse_on_dblclick = appleValue.toBool();
480
481 // Anti-aliasing threshold
482 appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold"));
483 if (appleValue.isValid())
484 qt_antialiasing_threshold = appleValue.toInt();
485
486#ifdef DEBUG_PLATFORM_SETTINGS
487 qDebug("qt_mac_update_os_settings *********************************************************************");
488#endif
489 { // setup the global palette
490 QColor qc;
491 (void) QApplication::style(); // trigger creation of application style and system palettes
492 QPalette pal = *QApplicationPrivate::sys_pal;
493
494 pal.setBrush( QPalette::Active, QPalette::Highlight, qcolorForTheme(kThemeBrushPrimaryHighlightColor) );
495 pal.setBrush( QPalette::Inactive, QPalette::Highlight, qcolorForTheme(kThemeBrushSecondaryHighlightColor) );
496
497 pal.setBrush( QPalette::Disabled, QPalette::Highlight, qcolorForTheme(kThemeBrushSecondaryHighlightColor) );
498 pal.setBrush( QPalette::Active, QPalette::Shadow, qcolorForTheme(kThemeBrushButtonActiveDarkShadow) );
499
500 pal.setBrush( QPalette::Inactive, QPalette::Shadow, qcolorForTheme(kThemeBrushButtonInactiveDarkShadow) );
501 pal.setBrush( QPalette::Disabled, QPalette::Shadow, qcolorForTheme(kThemeBrushButtonInactiveDarkShadow) );
502
503 qc = qcolorForThemeTextColor(kThemeTextColorDialogActive);
504 pal.setColor(QPalette::Active, QPalette::Text, qc);
505 pal.setColor(QPalette::Active, QPalette::WindowText, qc);
506 pal.setColor(QPalette::Active, QPalette::HighlightedText, qc);
507
508 qc = qcolorForThemeTextColor(kThemeTextColorDialogInactive);
509 pal.setColor(QPalette::Inactive, QPalette::Text, qc);
510 pal.setColor(QPalette::Inactive, QPalette::WindowText, qc);
511 pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc);
512 pal.setColor(QPalette::Disabled, QPalette::Text, qc);
513 pal.setColor(QPalette::Disabled, QPalette::WindowText, qc);
514 pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc);
515 pal.setBrush(QPalette::ToolTipBase, QColor(255, 255, 199));
516
517 if (!QApplicationPrivate::sys_pal || *QApplicationPrivate::sys_pal != pal) {
518 QApplicationPrivate::setSystemPalette(pal);
519 QApplication::setPalette(pal);
520 }
521#ifdef DEBUG_PLATFORM_SETTINGS
522 qt_mac_debug_palette(pal, QApplication::palette(), "Global Palette");
523#endif
524 }
525
526 QFont fnt = qfontForThemeFont(kThemeApplicationFont);
527#ifdef DEBUG_PLATFORM_SETTINGS
528 qDebug("qt-internal: Font for Application [%s::%d::%d::%d]",
529 fnt.family().toLatin1().constData(), fnt.pointSize(), fnt.bold(), fnt.italic());
530#endif
531 if (!QApplicationPrivate::sys_font || *QApplicationPrivate::sys_font != fnt)
532 QApplicationPrivate::setSystemFont(fnt);
533
534 { //setup the fonts
535 struct FontMap {
536 FontMap(const char *qc, short fk) : qt_class(qc), font_key(fk) { }
537 const char *const qt_class;
538 short font_key;
539 } mac_widget_fonts[] = {
540 FontMap("QPushButton", kThemePushButtonFont),
541 FontMap("QListView", kThemeViewsFont),
542 FontMap("QListBox", kThemeViewsFont),
543 FontMap("QTitleBar", kThemeWindowTitleFont),
544 FontMap("QMenuBar", kThemeMenuTitleFont),
545 FontMap("QMenu", kThemeMenuItemFont),
546 FontMap("QComboMenuItem", kThemeSystemFont),
547 FontMap("QHeaderView", kThemeSmallSystemFont),
548 FontMap("Q3Header", kThemeSmallSystemFont),
549 FontMap("QTipLabel", kThemeSmallSystemFont),
550 FontMap("QLabel", kThemeSystemFont),
551 FontMap("QToolButton", kThemeSmallSystemFont),
552 FontMap("QMenuItem", kThemeMenuItemCmdKeyFont), // It doesn't exist, but its unique.
553 FontMap("QComboLineEdit", kThemeViewsFont), // It doesn't exist, but its unique.
554 FontMap("QSmallFont", kThemeSmallSystemFont), // It doesn't exist, but its unique.
555 FontMap("QMiniFont", kThemeMiniSystemFont), // It doesn't exist, but its unique.
556 FontMap(0, 0) };
557 for(int i = 0; mac_widget_fonts[i].qt_class; i++) {
558 QFont fnt = qfontForThemeFont(mac_widget_fonts[i].font_key);
559 bool set_font = true;
560 FontHash *hash = qt_app_fonts_hash();
561 if (!hash->isEmpty()) {
562 FontHash::const_iterator it
563 = hash->constFind(mac_widget_fonts[i].qt_class);
564 if (it != hash->constEnd())
565 set_font = (fnt != *it);
566 }
567 if (set_font) {
568 QApplication::setFont(fnt, mac_widget_fonts[i].qt_class);
569#ifdef DEBUG_PLATFORM_SETTINGS
570 qDebug("qt-internal: Font for %s [%s::%d::%d::%d]", mac_widget_fonts[i].qt_class,
571 fnt.family().toLatin1().constData(), fnt.pointSize(), fnt.bold(), fnt.italic());
572#endif
573 }
574 }
575 }
576 QApplicationPrivate::initializeWidgetPaletteHash();
577#ifdef DEBUG_PLATFORM_SETTINGS
578 qDebug("qt_mac_update_os_settings END !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
579#endif
580}
581
582void QApplicationPrivate::initializeWidgetPaletteHash()
583{
584 { //setup the palette
585 struct PaletteMap {
586 inline PaletteMap(const char *qc, ThemeBrush a, ThemeBrush i) :
587 qt_class(qc), active(a), inactive(i) { }
588 const char *const qt_class;
589 ThemeBrush active, inactive;
590 } mac_widget_colors[] = {
591 PaletteMap("QToolButton", kThemeTextColorBevelButtonActive, kThemeTextColorBevelButtonInactive),
592 PaletteMap("QAbstractButton", kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive),
593 PaletteMap("QHeaderView", kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive),
594 PaletteMap("Q3Header", kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive),
595 PaletteMap("QComboBox", kThemeTextColorPopupButtonActive, kThemeTextColorPopupButtonInactive),
596 PaletteMap("QAbstractItemView", kThemeTextColorListView, kThemeTextColorDialogInactive),
597 PaletteMap("QMessageBoxLabel", kThemeTextColorAlertActive, kThemeTextColorAlertInactive),
598 PaletteMap("QTabBar", kThemeTextColorTabFrontActive, kThemeTextColorTabFrontInactive),
599 PaletteMap("QLabel", kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive),
600 PaletteMap("QGroupBox", kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive),
601 PaletteMap("QMenu", kThemeTextColorPopupLabelActive, kThemeTextColorPopupLabelInactive),
602 PaletteMap("QTextEdit", 0, 0),
603 PaletteMap("QTextControl", 0, 0),
604 PaletteMap("QLineEdit", 0, 0),
605 PaletteMap(0, 0, 0) };
606 QColor qc;
607 for(int i = 0; mac_widget_colors[i].qt_class; i++) {
608 QPalette pal;
609 if (mac_widget_colors[i].active != 0) {
610 qc = qcolorForThemeTextColor(mac_widget_colors[i].active);
611 pal.setColor(QPalette::Active, QPalette::Text, qc);
612 pal.setColor(QPalette::Active, QPalette::WindowText, qc);
613 pal.setColor(QPalette::Active, QPalette::HighlightedText, qc);
614 qc = qcolorForThemeTextColor(mac_widget_colors[i].inactive);
615 pal.setColor(QPalette::Inactive, QPalette::Text, qc);
616 pal.setColor(QPalette::Disabled, QPalette::Text, qc);
617 pal.setColor(QPalette::Inactive, QPalette::WindowText, qc);
618 pal.setColor(QPalette::Disabled, QPalette::WindowText, qc);
619 pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc);
620 pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc);
621 }
622 if (!strcmp(mac_widget_colors[i].qt_class, "QMenu")) {
623 qc = qcolorForThemeTextColor(kThemeTextColorMenuItemActive);
624 pal.setBrush(QPalette::ButtonText, qc);
625 qc = qcolorForThemeTextColor(kThemeTextColorMenuItemSelected);
626 pal.setBrush(QPalette::HighlightedText, qc);
627 qc = qcolorForThemeTextColor(kThemeTextColorMenuItemDisabled);
628 pal.setBrush(QPalette::Disabled, QPalette::Text, qc);
629 } else if (!strcmp(mac_widget_colors[i].qt_class, "QAbstractButton")
630 || !strcmp(mac_widget_colors[i].qt_class, "QHeaderView")
631 || !strcmp(mac_widget_colors[i].qt_class, "Q3Header")) { //special
632 pal.setColor(QPalette::Disabled, QPalette::ButtonText,
633 pal.color(QPalette::Disabled, QPalette::Text));
634 pal.setColor(QPalette::Inactive, QPalette::ButtonText,
635 pal.color(QPalette::Inactive, QPalette::Text));
636 pal.setColor(QPalette::Active, QPalette::ButtonText,
637 pal.color(QPalette::Active, QPalette::Text));
638 } else if (!strcmp(mac_widget_colors[i].qt_class, "QAbstractItemView")) {
639 pal.setBrush(QPalette::Active, QPalette::Highlight,
640 qcolorForTheme(kThemeBrushAlternatePrimaryHighlightColor));
641 qc = qcolorForThemeTextColor(kThemeTextColorMenuItemSelected);
642 pal.setBrush(QPalette::Active, QPalette::HighlightedText, qc);
643#if 1
644 pal.setBrush(QPalette::Inactive, QPalette::Text,
645 pal.brush(QPalette::Active, QPalette::Text));
646 pal.setBrush(QPalette::Inactive, QPalette::HighlightedText,
647 pal.brush(QPalette::Active, QPalette::Text));
648#endif
649 } else if (!strcmp(mac_widget_colors[i].qt_class, "QTextEdit")
650 || !strcmp(mac_widget_colors[i].qt_class, "QTextControl")) {
651 pal.setBrush(QPalette::Inactive, QPalette::Text,
652 pal.brush(QPalette::Active, QPalette::Text));
653 pal.setBrush(QPalette::Inactive, QPalette::HighlightedText,
654 pal.brush(QPalette::Active, QPalette::Text));
655 } else if (!strcmp(mac_widget_colors[i].qt_class, "QLineEdit")) {
656 pal.setBrush(QPalette::Disabled, QPalette::Base,
657 pal.brush(QPalette::Active, QPalette::Base));
658 }
659
660 bool set_palette = true;
661 PaletteHash *phash = qt_app_palettes_hash();
662 if (!phash->isEmpty()) {
663 PaletteHash::const_iterator it
664 = phash->constFind(mac_widget_colors[i].qt_class);
665 if (it != phash->constEnd())
666 set_palette = (pal != *it);
667 }
668 if (set_palette) {
669 QApplication::setPalette(pal, mac_widget_colors[i].qt_class);
670#ifdef DEBUG_PLATFORM_SETTINGS
671 qt_mac_debug_palette(pal, QApplication::palette(), QLatin1String("Palette for ") + QString::fromLatin1(mac_widget_colors[i].qt_class));
672#endif
673 }
674 }
675 }
676}
677
678static void qt_mac_event_release(EventRef &event)
679{
680 ReleaseEvent(event);
681 event = 0;
682}
683#ifndef QT_MAC_USE_COCOA
684static void qt_mac_event_release(QWidget *w, EventRef &event)
685{
686 if (event) {
687 QWidget *widget = 0;
688 if (GetEventParameter(event, kEventParamQWidget, typeQWidget, 0, sizeof(widget), 0, &widget) == noErr
689 && w == widget) {
690 if (IsEventInQueue(GetMainEventQueue(), event))
691 RemoveEventFromQueue(GetMainEventQueue(), event);
692 qt_mac_event_release(event);
693 }
694 }
695}
696
697static bool qt_mac_event_remove(EventRef &event)
698{
699 if (event) {
700 if (IsEventInQueue(GetMainEventQueue(), event))
701 RemoveEventFromQueue(GetMainEventQueue(), event);
702 qt_mac_event_release(event);
703 return true;
704 }
705 return false;
706}
707#endif
708
709/* sheets */
710#ifndef QT_MAC_USE_COCOA
711static EventRef request_showsheet_pending = 0;
712#endif
713void qt_event_request_showsheet(QWidget *w)
714{
715 Q_ASSERT(qt_mac_is_macsheet(w));
716#ifdef QT_MAC_USE_COCOA
717 [NSApp beginSheet:qt_mac_window_for(w) modalForWindow:qt_mac_window_for(w->parentWidget())
718 modalDelegate:nil didEndSelector:nil contextInfo:0];
719#else
720 qt_mac_event_remove(request_showsheet_pending);
721 CreateEvent(0, kEventClassQt, kEventQtRequestShowSheet, GetCurrentEventTime(),
722 kEventAttributeUserEvent, &request_showsheet_pending);
723 SetEventParameter(request_showsheet_pending, kEventParamQWidget, typeQWidget, sizeof(w), &w);
724 PostEventToQueue(GetMainEventQueue(), request_showsheet_pending, kEventPriorityStandard);
725#endif
726}
727
728static void qt_post_window_change_event(QWidget *widget)
729{
730 qt_widget_private(widget)->needWindowChange = true;
731 QEvent *glWindowChangeEvent = new QEvent(QEvent::MacGLWindowChange);
732 QApplication::postEvent(widget, glWindowChangeEvent);
733}
734
735/*
736 Posts updates to all child and grandchild OpenGL widgets for the given widget.
737*/
738static void qt_mac_update_child_gl_widgets(QWidget *widget)
739{
740 // Update all OpenGL child widgets for the given widget.
741 QList<QWidgetPrivate::GlWidgetInfo> &glWidgets = qt_widget_private(widget)->glWidgets;
742 QList<QWidgetPrivate::GlWidgetInfo>::iterator end = glWidgets.end();
743 QList<QWidgetPrivate::GlWidgetInfo>::iterator it = glWidgets.begin();
744
745 for (;it != end; ++it) {
746 qt_post_window_change_event(it->widget);
747 }
748}
749
750/*
751 Sends updates to all child and grandchild gl widgets that have updates pending.
752*/
753void qt_mac_send_posted_gl_updates(QWidget *widget)
754{
755 QList<QWidgetPrivate::GlWidgetInfo> &glWidgets = qt_widget_private(widget)->glWidgets;
756 QList<QWidgetPrivate::GlWidgetInfo>::iterator end = glWidgets.end();
757 QList<QWidgetPrivate::GlWidgetInfo>::iterator it = glWidgets.begin();
758
759 for (;it != end; ++it) {
760 QWidget *glWidget = it->widget;
761 if (qt_widget_private(glWidget)->needWindowChange) {
762 QEvent glChangeEvent(QEvent::MacGLWindowChange);
763 QApplication::sendEvent(glWidget, &glChangeEvent);
764 }
765 }
766}
767
768/*
769 Posts updates to all OpenGL widgets within the window that the given widget intersects.
770*/
771static void qt_mac_update_intersected_gl_widgets(QWidget *widget)
772{
773#ifndef QT_MAC_USE_COCOA
774 QList<QWidgetPrivate::GlWidgetInfo> &glWidgets = qt_widget_private(widget->window())->glWidgets;
775 if (glWidgets.isEmpty())
776 return;
777
778 // Exit if the window has not been created yet (mapToGlobal/size will force create it)
779 if (widget->testAttribute(Qt::WA_WState_Created) == false || HIViewGetWindow(qt_mac_nativeview_for(widget)) == 0)
780 return;
781
782 const QRect globalWidgetRect = QRect(widget->mapToGlobal(QPoint(0, 0)), widget->size());
783
784 QList<QWidgetPrivate::GlWidgetInfo>::iterator end = glWidgets.end();
785 QList<QWidgetPrivate::GlWidgetInfo>::iterator it = glWidgets.begin();
786
787 for (;it != end; ++it){
788 QWidget *glWidget = it->widget;
789 const QRect globalGlWidgetRect = QRect(glWidget->mapToGlobal(QPoint(0, 0)), glWidget->size());
790 if (globalWidgetRect.intersects(globalGlWidgetRect)) {
791 qt_post_window_change_event(glWidget);
792 it->lastUpdateWidget = widget;
793 } else if (it->lastUpdateWidget == widget) {
794 // Update the gl wigets that the widget intersected the last time around,
795 // and that we are not intersecting now. This prevents paint errors when the
796 // intersecting widget leaves a gl widget.
797 qt_post_window_change_event(glWidget);
798 it->lastUpdateWidget = 0;
799 }
800 }
801#else
802 Q_UNUSED(widget);
803#endif
804}
805
806/*
807 Posts a kEventQtRequestWindowChange event to the main Carbon event queue.
808*/
809static EventRef request_window_change_pending = 0;
810Q_GUI_EXPORT void qt_event_request_window_change()
811{
812 if(request_window_change_pending)
813 return;
814
815 CreateEvent(0, kEventClassQt, kEventQtRequestWindowChange, GetCurrentEventTime(),
816 kEventAttributeUserEvent, &request_window_change_pending);
817 PostEventToQueue(GetMainEventQueue(), request_window_change_pending, kEventPriorityHigh);
818}
819
820/* window changing. This is a hack around Apple's missing functionality, pending the toolbox
821 team fix. --Sam */
822Q_GUI_EXPORT void qt_event_request_window_change(QWidget *widget)
823{
824 if (!widget)
825 return;
826
827 // Post a kEventQtRequestWindowChange event. This event is semi-public,
828 // don't remove this line!
829 qt_event_request_window_change();
830
831 // Post update request on gl widgets unconditionally.
832 if (qt_widget_private(widget)->isGLWidget == true) {
833 qt_post_window_change_event(widget);
834 return;
835 }
836
837 qt_mac_update_child_gl_widgets(widget);
838 qt_mac_update_intersected_gl_widgets(widget);
839}
840
841/* activation */
842static struct {
843 QPointer<QWidget> widget;
844 EventRef event;
845 EventLoopTimerRef timer;
846 EventLoopTimerUPP timerUPP;
847} request_activate_pending = { 0, 0, 0, 0 };
848bool qt_event_remove_activate()
849{
850 if (request_activate_pending.timer) {
851 RemoveEventLoopTimer(request_activate_pending.timer);
852 request_activate_pending.timer = 0;
853 }
854 if (request_activate_pending.event)
855 qt_mac_event_release(request_activate_pending.event);
856 return true;
857}
858
859void qt_event_activate_timer_callbk(EventLoopTimerRef r, void *)
860{
861 EventLoopTimerRef otc = request_activate_pending.timer;
862 qt_event_remove_activate();
863 if (r == otc && !request_activate_pending.widget.isNull()) {
864 const QWidget *tlw = request_activate_pending.widget->window();
865 Qt::WindowType wt = tlw->windowType();
866 if (tlw->isVisible()
867 && ((wt != Qt::Desktop && wt != Qt::Popup && wt != Qt::Tool) || tlw->isModal())) {
868 CreateEvent(0, kEventClassQt, kEventQtRequestActivate, GetCurrentEventTime(),
869 kEventAttributeUserEvent, &request_activate_pending.event);
870 PostEventToQueue(GetMainEventQueue(), request_activate_pending.event, kEventPriorityHigh);
871 }
872 }
873}
874
875void qt_event_request_activate(QWidget *w)
876{
877 if (w == request_activate_pending.widget)
878 return;
879
880 /* We put these into a timer because due to order of events being sent we need to be sure this
881 comes from inside of the event loop */
882 qt_event_remove_activate();
883 if (!request_activate_pending.timerUPP)
884 request_activate_pending.timerUPP = NewEventLoopTimerUPP(qt_event_activate_timer_callbk);
885 request_activate_pending.widget = w;
886 InstallEventLoopTimer(GetMainEventLoop(), 0, 0, request_activate_pending.timerUPP, 0, &request_activate_pending.timer);
887}
888
889
890/* menubars */
891#ifndef QT_MAC_USE_COCOA
892static EventRef request_menubarupdate_pending = 0;
893#endif
894void qt_event_request_menubarupdate()
895{
896#ifndef QT_MAC_USE_COCOA
897 if (request_menubarupdate_pending) {
898 if (IsEventInQueue(GetMainEventQueue(), request_menubarupdate_pending))
899 return;
900#ifdef DEBUG_DROPPED_EVENTS
901 qDebug("%s:%d Whoa, we dropped an event on the floor!", __FILE__, __LINE__);
902#endif
903 }
904
905 CreateEvent(0, kEventClassQt, kEventQtRequestMenubarUpdate, GetCurrentEventTime(),
906 kEventAttributeUserEvent, &request_menubarupdate_pending);
907 PostEventToQueue(GetMainEventQueue(), request_menubarupdate_pending, kEventPriorityHigh);
908#else
909 // Just call this. The request has the benefit that we don't call this multiple times, but
910 // we can optimize this.
911 QMenuBar::macUpdateMenuBar();
912#endif
913}
914
915#ifndef QT_MAC_USE_COCOA
916//context menu
917static EventRef request_context_pending = 0;
918static void qt_event_request_context(QWidget *w=0, EventRef *where=0)
919{
920 if (!where)
921 where = &request_context_pending;
922 if (*where)
923 return;
924 CreateEvent(0, kEventClassQt, kEventQtRequestContext, GetCurrentEventTime(),
925 kEventAttributeUserEvent, where);
926 if (w)
927 SetEventParameter(*where, kEventParamQWidget, typeQWidget, sizeof(w), &w);
928 PostEventToQueue(GetMainEventQueue(), *where, kEventPriorityStandard);
929}
930#endif
931
932void QApplicationPrivate::createEventDispatcher()
933{
934 Q_Q(QApplication);
935 if (q->type() != QApplication::Tty)
936 eventDispatcher = new QEventDispatcherMac(q);
937 else
938 eventDispatcher = new QEventDispatcherUNIX(q);
939}
940
941/* clipboard */
942void qt_event_send_clipboard_changed()
943{
944#ifndef QT_MAC_USE_COCOA
945 AppleEvent ae;
946 if (AECreateAppleEvent(kEventClassQt, typeAEClipboardChanged, 0, kAutoGenerateReturnID, kAnyTransactionID, &ae) != noErr)
947 qDebug("Can't happen!!");
948 AppleEvent reply;
949 AESend(&ae, &reply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, 0, 0);
950#endif
951}
952
953/* app menu */
954static QMenu *qt_mac_dock_menu = 0;
955Q_GUI_EXPORT void qt_mac_set_dock_menu(QMenu *menu)
956{
957 qt_mac_dock_menu = menu;
958#ifdef QT_MAC_USE_COCOA
959 [NSApp setDockMenu:menu->macMenu()];
960#else
961 SetApplicationDockTileMenu(menu->macMenu());
962#endif
963}
964
965/* events that hold pointers to widgets, must be cleaned up like this */
966void qt_mac_event_release(QWidget *w)
967{
968 if (w) {
969#ifndef QT_MAC_USE_COCOA
970 qt_mac_event_release(w, request_showsheet_pending);
971 qt_mac_event_release(w, request_context_pending);
972#endif
973 if (w == qt_mac_dock_menu) {
974 qt_mac_dock_menu = 0;
975#ifndef QT_MAC_USE_COCOA
976 SetApplicationDockTileMenu(0);
977#else
978 [NSApp setDockMenu:0];
979#endif
980 }
981 }
982}
983
984struct QMacAppleEventTypeSpec {
985 AEEventClass mac_class;
986 AEEventID mac_id;
987} app_apple_events[] = {
988 { kCoreEventClass, kAEQuitApplication },
989 { kCoreEventClass, kAEOpenDocuments },
990 { kInternetEventClass, kAEGetURL },
991};
992
993#ifndef QT_MAC_USE_COCOA
994
995#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
996enum
997{
998 kEventMouseScroll = 11,
999 kEventParamMouseWheelSmoothVerticalDelta = 'saxy',
1000 kEventParamMouseWheelSmoothHorizontalDelta = 'saxx',
1001};
1002#endif
1003
1004/* watched events */
1005static EventTypeSpec app_events[] = {
1006 { kEventClassQt, kEventQtRequestWindowChange },
1007 { kEventClassQt, kEventQtRequestShowSheet },
1008 { kEventClassQt, kEventQtRequestContext },
1009 { kEventClassQt, kEventQtRequestActivate },
1010 { kEventClassQt, kEventQtRequestMenubarUpdate },
1011
1012 { kEventClassWindow, kEventWindowActivated },
1013 { kEventClassWindow, kEventWindowDeactivated },
1014
1015 { kEventClassMouse, kEventMouseScroll },
1016 { kEventClassMouse, kEventMouseWheelMoved },
1017 { kEventClassMouse, kEventMouseDown },
1018 { kEventClassMouse, kEventMouseUp },
1019 { kEventClassMouse, kEventMouseDragged },
1020 { kEventClassMouse, kEventMouseMoved },
1021
1022 { kEventClassTablet, kEventTabletProximity },
1023
1024 { kEventClassApplication, kEventAppActivated },
1025 { kEventClassApplication, kEventAppDeactivated },
1026 { kEventClassApplication, kEventAppAvailableWindowBoundsChanged },
1027
1028 // { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
1029 { kEventClassKeyboard, kEventRawKeyModifiersChanged },
1030 { kEventClassKeyboard, kEventRawKeyRepeat },
1031 { kEventClassKeyboard, kEventRawKeyUp },
1032 { kEventClassKeyboard, kEventRawKeyDown },
1033
1034 { kEventClassCommand, kEventCommandProcess },
1035
1036 { kEventClassAppleEvent, kEventAppleEvent },
1037
1038 { kAppearanceEventClass, kAEAppearanceChanged }
1039};
1040
1041void qt_init_app_proc_handler()
1042{
1043 InstallEventHandler(GetApplicationEventTarget(), app_proc_handlerUPP,
1044 GetEventTypeCount(app_events), app_events, (void *)qApp,
1045 &app_proc_handler);
1046}
1047#endif // QT_MAC_USE_COCOA
1048
1049static void qt_init_tablet_proximity_handler()
1050{
1051 EventTypeSpec tabletProximityEvent = { kEventClassTablet, kEventTabletProximity };
1052 InstallEventHandler(GetEventMonitorTarget(), tablet_proximity_UPP,
1053 1, &tabletProximityEvent, qApp, &tablet_proximity_handler);
1054}
1055
1056static void qt_release_tablet_proximity_handler()
1057{
1058 RemoveEventHandler(tablet_proximity_handler);
1059}
1060
1061QString QApplicationPrivate::appName() const
1062{
1063 static QString applName;
1064 if (applName.isEmpty()) {
1065 applName = QCoreApplicationPrivate::macMenuBarName();
1066 ProcessSerialNumber psn;
1067 if (applName.isEmpty() && qt_is_gui_used && GetCurrentProcess(&psn) == noErr) {
1068 QCFString cfstr;
1069 CopyProcessName(&psn, &cfstr);
1070 applName = cfstr;
1071 }
1072 }
1073 return applName;
1074}
1075
1076void qt_release_app_proc_handler()
1077{
1078#ifndef QT_MAC_USE_COCOA
1079 if (app_proc_handler) {
1080 RemoveEventHandler(app_proc_handler);
1081 app_proc_handler = 0;
1082 }
1083#endif
1084}
1085
1086void qt_color_profile_changed(CFNotificationCenterRef, void *, CFStringRef, const void *,
1087 CFDictionaryRef)
1088{
1089 QCoreGraphicsPaintEngine::cleanUpMacColorSpaces();
1090}
1091/* platform specific implementations */
1092void qt_init(QApplicationPrivate *priv, int)
1093{
1094 if (qt_is_gui_used) {
1095 CGDisplayRegisterReconfigurationCallback(qt_mac_display_change_callbk, 0);
1096 CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter();
1097 CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed,
1098 kCMDeviceUnregisteredNotification, 0,
1099 CFNotificationSuspensionBehaviorDeliverImmediately);
1100 CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed,
1101 kCMDefaultDeviceNotification, 0,
1102 CFNotificationSuspensionBehaviorDeliverImmediately);
1103 CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed,
1104 kCMDeviceProfilesNotification, 0,
1105 CFNotificationSuspensionBehaviorDeliverImmediately);
1106 CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed,
1107 kCMDefaultDeviceProfileNotification, 0,
1108 CFNotificationSuspensionBehaviorDeliverImmediately);
1109 ProcessSerialNumber psn;
1110 if (GetCurrentProcess(&psn) == noErr) {
1111 // Jambi needs to transform itself since most people aren't "used"
1112 // to putting things in bundles, but other people may actually not
1113 // want to tranform the process (running as a helper or something)
1114 // so don't do that for them. This means checking both LSUIElement
1115 // and LSBackgroundOnly. If you set them both... well, you
1116 // shouldn't do that.
1117
1118 bool forceTransform = true;
1119 CFTypeRef value = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(),
1120 CFSTR("LSUIElement"));
1121 if (value) {
1122 CFTypeID valueType = CFGetTypeID(value);
1123 // Officially it's supposed to be a string, a boolean makes sense, so we'll check.
1124 // A number less so, but OK.
1125 if (valueType == CFStringGetTypeID())
1126 forceTransform = !(QCFString::toQString(static_cast<CFStringRef>(value)).toInt());
1127 else if (valueType == CFBooleanGetTypeID())
1128 forceTransform = !CFBooleanGetValue(static_cast<CFBooleanRef>(value));
1129 else if (valueType == CFNumberGetTypeID()) {
1130 int valueAsInt;
1131 CFNumberGetValue(static_cast<CFNumberRef>(value), kCFNumberIntType, &valueAsInt);
1132 forceTransform = !valueAsInt;
1133 }
1134 }
1135
1136 if (forceTransform) {
1137 value = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(),
1138 CFSTR("LSBackgroundOnly"));
1139 if (value) {
1140 CFTypeID valueType = CFGetTypeID(value);
1141 if (valueType == CFBooleanGetTypeID())
1142 forceTransform = !CFBooleanGetValue(static_cast<CFBooleanRef>(value));
1143 else if (valueType == CFStringGetTypeID())
1144 forceTransform = !(QCFString::toQString(static_cast<CFStringRef>(value)).toInt());
1145 else if (valueType == CFNumberGetTypeID()) {
1146 int valueAsInt;
1147 CFNumberGetValue(static_cast<CFNumberRef>(value), kCFNumberIntType, &valueAsInt);
1148 forceTransform = !valueAsInt;
1149 }
1150 }
1151 }
1152
1153
1154 if (forceTransform) {
1155 TransformProcessType(&psn, kProcessTransformToForegroundApplication);
1156 }
1157 }
1158 }
1159
1160 char **argv = priv->argv;
1161
1162 // Get command line params
1163 if (int argc = priv->argc) {
1164 int i, j = 1;
1165 QString passed_psn;
1166 for(i=1; i < argc; i++) {
1167 if (argv[i] && *argv[i] != '-') {
1168 argv[j++] = argv[i];
1169 continue;
1170 }
1171 QByteArray arg(argv[i]);
1172#if defined(QT_DEBUG)
1173 if (arg == "-nograb")
1174 appNoGrab = !appNoGrab;
1175 else
1176#endif // QT_DEBUG
1177 if (arg.left(5) == "-psn_") {
1178 passed_psn = QString::fromLatin1(arg.mid(6));
1179 } else {
1180 argv[j++] = argv[i];
1181 }
1182 }
1183 if (j < priv->argc) {
1184 priv->argv[j] = 0;
1185 priv->argc = j;
1186 }
1187
1188 //special hack to change working directory (for an app bundle) when running from finder
1189 if (!passed_psn.isNull() && QDir::currentPath() == QLatin1String("/")) {
1190 QCFType<CFURLRef> bundleURL(CFBundleCopyBundleURL(CFBundleGetMainBundle()));
1191 QString qbundlePath = QCFString(CFURLCopyFileSystemPath(bundleURL,
1192 kCFURLPOSIXPathStyle));
1193 if (qbundlePath.endsWith(QLatin1String(".app")))
1194 QDir::setCurrent(qbundlePath.section(QLatin1Char('/'), 0, -2));
1195 }
1196 }
1197
1198 QMacPasteboardMime::initialize();
1199
1200 qApp->setObjectName(priv->appName());
1201 if (qt_is_gui_used) {
1202 QColormap::initialize();
1203 QFont::initialize();
1204 QCursorData::initialize();
1205 QCoreGraphicsPaintEngine::initialize();
1206#ifndef QT_NO_ACCESSIBILITY
1207 QAccessible::initialize();
1208#endif
1209 QMacInputContext::initialize();
1210 QApplicationPrivate::inputContext = new QMacInputContext;
1211
1212 if (QApplication::desktopSettingsAware())
1213 qt_mac_update_os_settings();
1214#ifndef QT_MAC_USE_COCOA
1215 if (!app_proc_handler) {
1216 app_proc_handlerUPP = NewEventHandlerUPP(QApplicationPrivate::globalEventProcessor);
1217 qt_init_app_proc_handler();
1218 }
1219
1220#endif
1221 if (!app_proc_ae_handlerUPP && !QApplication::testAttribute(Qt::AA_MacPluginApplication)) {
1222 app_proc_ae_handlerUPP = AEEventHandlerUPP(QApplicationPrivate::globalAppleEventProcessor);
1223 for(uint i = 0; i < sizeof(app_apple_events) / sizeof(QMacAppleEventTypeSpec); ++i) {
1224 // Install apple event handler, but avoid overwriting an already
1225 // existing handler (it means a 3rd party application has installed one):
1226 SRefCon refCon = 0;
1227 AEEventHandlerUPP current_handler = NULL;
1228 AEGetEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id, &current_handler, &refCon, false);
1229 if (!current_handler)
1230 AEInstallEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id,
1231 app_proc_ae_handlerUPP, SRefCon(qApp), false);
1232 }
1233 }
1234
1235 if (QApplicationPrivate::app_style) {
1236 QEvent ev(QEvent::Style);
1237 qt_sendSpontaneousEvent(QApplicationPrivate::app_style, &ev);
1238 }
1239 }
1240 if (QApplication::desktopSettingsAware())
1241 QApplicationPrivate::qt_mac_apply_settings();
1242
1243 // Cocoa application delegate
1244#ifdef QT_MAC_USE_COCOA
1245 NSApplication *cocoaApp = [QNSApplication sharedApplication];
1246 QMacCocoaAutoReleasePool pool;
1247 NSObject *oldDelegate = [cocoaApp delegate];
1248 QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate];
1249 Q_ASSERT(newDelegate);
1250 [newDelegate setQtPrivate:priv];
1251 // Only do things that make sense to do once, otherwise we crash.
1252 if (oldDelegate != newDelegate && !QApplication::testAttribute(Qt::AA_MacPluginApplication)) {
1253 [newDelegate setReflectionDelegate:oldDelegate];
1254 [cocoaApp setDelegate:newDelegate];
1255
1256 QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader = [[QT_MANGLE_NAMESPACE(QCocoaMenuLoader) alloc] init];
1257 if ([NSBundle loadNibNamed:@"qt_menu" owner:qtMenuLoader] == false) {
1258 qFatal("Qt internal error: qt_menu.nib could not be loaded. The .nib file"
1259 " should be placed in QtGui.framework/Versions/Current/Resources/ "
1260 " or in the resources directory of your application bundle.");
1261 }
1262
1263 [cocoaApp setMenu:[qtMenuLoader menu]];
1264 [newDelegate setMenuLoader:qtMenuLoader];
1265 [qtMenuLoader release];
1266 }
1267#endif
1268 // Register for Carbon tablet proximity events on the event monitor target.
1269 // This means that we should receive proximity events even when we aren't the active application.
1270 if (!tablet_proximity_handler) {
1271 tablet_proximity_UPP = NewEventHandlerUPP(QApplicationPrivate::tabletProximityCallback);
1272 qt_init_tablet_proximity_handler();
1273 }
1274 priv->native_modal_dialog_active = false;
1275
1276 qt_mac_read_fontsmoothing_settings();
1277}
1278
1279void qt_release_apple_event_handler()
1280{
1281 if(app_proc_ae_handlerUPP) {
1282 for(uint i = 0; i < sizeof(app_apple_events) / sizeof(QMacAppleEventTypeSpec); ++i)
1283 AERemoveEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id,
1284 app_proc_ae_handlerUPP, true);
1285 DisposeAEEventHandlerUPP(app_proc_ae_handlerUPP);
1286 app_proc_ae_handlerUPP = 0;
1287 }
1288}
1289
1290/*****************************************************************************
1291 qt_cleanup() - cleans up when the application is finished
1292 *****************************************************************************/
1293
1294void qt_cleanup()
1295{
1296 CGDisplayRemoveReconfigurationCallback(qt_mac_display_change_callbk, 0);
1297 CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter();
1298 CFNotificationCenterRemoveObserver(center, qApp, kCMDeviceUnregisteredNotification, 0);
1299 CFNotificationCenterRemoveObserver(center, qApp, kCMDefaultDeviceNotification, 0);
1300 CFNotificationCenterRemoveObserver(center, qApp, kCMDeviceProfilesNotification, 0);
1301 CFNotificationCenterRemoveObserver(center, qApp, kCMDefaultDeviceProfileNotification, 0);
1302
1303#ifndef QT_MAC_USE_COCOA
1304 qt_release_app_proc_handler();
1305 if (app_proc_handlerUPP) {
1306 DisposeEventHandlerUPP(app_proc_handlerUPP);
1307 app_proc_handlerUPP = 0;
1308 }
1309#endif
1310 qt_release_apple_event_handler();
1311 qt_release_tablet_proximity_handler();
1312 if (tablet_proximity_UPP)
1313 DisposeEventHandlerUPP(tablet_proximity_UPP);
1314
1315 QPixmapCache::clear();
1316 if (qt_is_gui_used) {
1317#ifndef QT_NO_ACCESSIBILITY
1318 QAccessible::cleanup();
1319#endif
1320 QMacInputContext::cleanup();
1321 QCursorData::cleanup();
1322 QFont::cleanup();
1323 QColormap::cleanup();
1324 if (qt_mac_safe_pdev) {
1325 delete qt_mac_safe_pdev;
1326 qt_mac_safe_pdev = 0;
1327 }
1328 extern void qt_mac_unregister_widget(); // qapplication_mac.cpp
1329 qt_mac_unregister_widget();
1330 }
1331}
1332
1333/*****************************************************************************
1334 Platform specific global and internal functions
1335 *****************************************************************************/
1336void qt_updated_rootinfo()
1337{
1338}
1339
1340bool qt_wstate_iconified(WId)
1341{
1342 return false;
1343}
1344
1345/*****************************************************************************
1346 Platform specific QApplication members
1347 *****************************************************************************/
1348extern QWidget * mac_mouse_grabber;
1349extern QWidget * mac_keyboard_grabber;
1350
1351#ifdef QT3_SUPPORT
1352void QApplication::setMainWidget(QWidget *mainWidget)
1353{
1354 QApplicationPrivate::main_widget = mainWidget;
1355 if (QApplicationPrivate::main_widget && windowIcon().isNull()
1356 && QApplicationPrivate::main_widget->testAttribute(Qt::WA_SetWindowIcon))
1357 setWindowIcon(QApplicationPrivate::main_widget->windowIcon());
1358}
1359#endif
1360#ifndef QT_NO_CURSOR
1361
1362/*****************************************************************************
1363 QApplication cursor stack
1364 *****************************************************************************/
1365#ifdef QT_MAC_USE_COCOA
1366void QApplicationPrivate::disableUsageOfCursorRects(bool disable)
1367{
1368 // In Cocoa there are two competing ways of setting the cursor; either
1369 // by using cursor rects (see qcocoaview_mac.mm), or by pushing/popping
1370 // the cursor manually. When we use override cursors, it makes most sense
1371 // to use the latter. But then we need to tell cocoa to stop using the
1372 // first approach so it doesn't change the cursor back when hovering over
1373 // a cursor rect:
1374 QWidgetList topLevels = qApp->topLevelWidgets();
1375 for (int i=0; i<topLevels.size(); ++i) {
1376 if (NSWindow *window = qt_mac_window_for(topLevels.at(i)))
1377 disable ? [window disableCursorRects] : [window enableCursorRects];
1378 }
1379}
1380
1381void QApplicationPrivate::updateOverrideCursor()
1382{
1383 // Sometimes Cocoa forgets that we have set a Cursor
1384 // manually. In those cases, remind it again:
1385 if (QCursor *override = qApp->overrideCursor())
1386 [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(*override)) set];
1387}
1388#endif
1389
1390void QApplication::setOverrideCursor(const QCursor &cursor)
1391{
1392 qApp->d_func()->cursor_list.prepend(cursor);
1393
1394#ifdef QT_MAC_USE_COCOA
1395 QMacCocoaAutoReleasePool pool;
1396 if (qApp->d_func()->cursor_list.size() == 1)
1397 qApp->d_func()->disableUsageOfCursorRects(true);
1398 [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) push];
1399#else
1400 if (qApp && qApp->activeWindow())
1401 qt_mac_set_cursor(&qApp->d_func()->cursor_list.first(), QCursor::pos());
1402#endif
1403}
1404
1405void QApplication::restoreOverrideCursor()
1406{
1407 if (qApp->d_func()->cursor_list.isEmpty())
1408 return;
1409 qApp->d_func()->cursor_list.removeFirst();
1410
1411#ifdef QT_MAC_USE_COCOA
1412 QMacCocoaAutoReleasePool pool;
1413 [NSCursor pop];
1414 if (qApp->d_func()->cursor_list.isEmpty())
1415 qApp->d_func()->disableUsageOfCursorRects(false);
1416#else
1417 if (qApp && qApp->activeWindow()) {
1418 const QCursor def(Qt::ArrowCursor);
1419 qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first(), QCursor::pos());
1420 }
1421#endif
1422}
1423#endif // QT_NO_CURSOR
1424
1425QWidget *QApplication::topLevelAt(const QPoint &p)
1426{
1427#ifndef QT_MAC_USE_COCOA
1428 QWidget *widget;
1429 qt_mac_window_at(p.x(), p.y(), &widget);
1430 return widget;
1431#else
1432 NSInteger windowCount;
1433 NSCountWindows(&windowCount);
1434 if (windowCount <= 0)
1435 return 0; // There's no window to find!
1436 QMacCocoaAutoReleasePool pool;
1437 NSPoint cocoaPoint = flipPoint(p);
1438 QVarLengthArray<NSInteger> windowList(windowCount);
1439 NSWindowList(windowCount, windowList.data());
1440 for (int i = 0; i < windowCount; ++i) {
1441 NSWindow *window = [NSApp windowWithWindowNumber:windowList[i]];
1442 if (window && NSPointInRect(cocoaPoint, [window frame])) {
1443 QWidget *candidateWindow = [window QT_MANGLE_NAMESPACE(qt_qwidget)];
1444 // Check to see if there's a hole in the window where the mask is.
1445 // If there is, we should just continue to see if there is a window below.
1446 if (candidateWindow && !candidateWindow->mask().isEmpty()) {
1447 QPoint localPoint = candidateWindow->mapFromGlobal(p);
1448 if (!candidateWindow->mask().contains(localPoint)) {
1449 continue;
1450 }
1451 }
1452 return candidateWindow;
1453 }
1454 }
1455 return 0; // Couldn't find a window at this point
1456#endif
1457}
1458
1459/*****************************************************************************
1460 Main event loop
1461 *****************************************************************************/
1462
1463bool QApplicationPrivate::modalState()
1464{
1465 return app_do_modal;
1466}
1467
1468#ifdef QT_MAC_USE_COCOA
1469#endif
1470
1471void QApplicationPrivate::enterModal_sys(QWidget *widget)
1472{
1473#ifdef DEBUG_MODAL_EVENTS
1474 Q_ASSERT(widget);
1475 qDebug("Entering modal state with %s::%s::%p (%d)", widget->metaObject()->className(), widget->objectName().toLocal8Bit().constData(),
1476 widget, qt_modal_stack ? (int)qt_modal_stack->count() : -1);
1477#endif
1478 if (!qt_modal_stack)
1479 qt_modal_stack = new QWidgetList;
1480
1481 dispatchEnterLeave(0, qt_mouseover);
1482 qt_mouseover = 0;
1483
1484 qt_modal_stack->insert(0, widget);
1485 if (!app_do_modal)
1486 qt_event_request_menubarupdate();
1487 app_do_modal = true;
1488 qt_button_down = 0;
1489
1490#ifdef QT_MAC_USE_COCOA
1491 if (!qt_mac_is_macsheet(widget))
1492 QEventDispatcherMacPrivate::beginModalSession(widget);
1493#endif
1494}
1495
1496void QApplicationPrivate::leaveModal_sys(QWidget *widget)
1497{
1498 if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
1499#ifdef DEBUG_MODAL_EVENTS
1500 qDebug("Leaving modal state with %s::%s::%p (%d)", widget->metaObject()->className(), widget->objectName().toLocal8Bit().constData(),
1501 widget, qt_modal_stack->count());
1502#endif
1503 if (qt_modal_stack->isEmpty()) {
1504 delete qt_modal_stack;
1505 qt_modal_stack = 0;
1506 QPoint p(QCursor::pos());
1507 app_do_modal = false;
1508 QWidget* w = 0;
1509 if (QWidget *grabber = QWidget::mouseGrabber())
1510 w = grabber;
1511 else
1512 w = QApplication::widgetAt(p.x(), p.y());
1513 dispatchEnterLeave(w, qt_mouseover); // send synthetic enter event
1514 qt_mouseover = w;
1515 }
1516#ifdef QT_MAC_USE_COCOA
1517 if (!qt_mac_is_macsheet(widget))
1518 QEventDispatcherMacPrivate::endModalSession(widget);
1519#endif
1520 }
1521#ifdef DEBUG_MODAL_EVENTS
1522 else qDebug("Failure to remove %s::%s::%p -- %p", widget->metaObject()->className(), widget->objectName().toLocal8Bit().constData(), widget, qt_modal_stack);
1523#endif
1524 app_do_modal = (qt_modal_stack != 0);
1525 if (!app_do_modal)
1526 qt_event_request_menubarupdate();
1527}
1528
1529QWidget *QApplicationPrivate::tryModalHelper_sys(QWidget *top)
1530{
1531#ifndef QT_MAC_USE_COCOA
1532 if(top && qt_mac_is_macsheet(top) && !IsWindowVisible(qt_mac_window_for(top))) {
1533 if(OSWindowRef wp = GetFrontWindowOfClass(kSheetWindowClass, true)) {
1534 if(QWidget *sheet = qt_mac_find_window(wp))
1535 top = sheet;
1536 }
1537 }
1538#endif
1539 return top;
1540}
1541
1542#ifndef QT_MAC_USE_COCOA
1543static bool qt_try_modal(QWidget *widget, EventRef event)
1544{
1545 QWidget * top = 0;
1546
1547 if (QApplicationPrivate::tryModalHelper(widget, &top))
1548 return true;
1549
1550 // INVARIANT: widget is modally shaddowed within its
1551 // window, and should therefore not handle the event.
1552 // However, if the window is not active, the event
1553 // might suggest that we should bring it to front:
1554
1555 bool block_event = false;
1556
1557 if (event) {
1558 switch (GetEventClass(event)) {
1559 case kEventClassMouse:
1560 case kEventClassKeyboard:
1561 block_event = true;
1562 break;
1563 }
1564 }
1565
1566 QWidget *activeWidget = QApplication::activeWindow();
1567 if ((!activeWidget || QApplicationPrivate::isBlockedByModal(activeWidget)) &&
1568 top->isWindow() && block_event && !QApplicationPrivate::native_modal_dialog_active)
1569 top->raise();
1570
1571#ifdef DEBUG_MODAL_EVENTS
1572 qDebug("%s:%d -- final decision! (%s)", __FILE__, __LINE__, block_event ? "false" : "true");
1573#endif
1574 return !block_event;
1575}
1576#endif
1577
1578OSStatus QApplicationPrivate::tabletProximityCallback(EventHandlerCallRef, EventRef carbonEvent,
1579 void *)
1580{
1581 OSType eventClass = GetEventClass(carbonEvent);
1582 UInt32 eventKind = GetEventKind(carbonEvent);
1583 if (eventClass != kEventClassTablet || eventKind != kEventTabletProximity)
1584 return eventNotHandledErr;
1585
1586 // Get the current point of the device and its unique ID.
1587 ::TabletProximityRec proxRec;
1588 GetEventParameter(carbonEvent, kEventParamTabletProximityRec, typeTabletProximityRec, 0,
1589 sizeof(proxRec), 0, &proxRec);
1590 qt_dispatchTabletProximityEvent(proxRec);
1591 return noErr;
1592}
1593
1594OSStatus
1595QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event, void *data)
1596{
1597#ifndef QT_MAC_USE_COCOA
1598 QApplication *app = (QApplication *)data;
1599 QScopedLoopLevelCounter loopLevelCounter(app->d_func()->threadData);
1600 long result;
1601 if (app->filterEvent(&event, &result))
1602 return result;
1603 if(app->macEventFilter(er, event)) //someone else ate it
1604 return noErr;
1605 QPointer<QWidget> widget;
1606
1607 /*We assume all events are handled and in
1608 the code below we set it to false when we know we didn't handle it, this
1609 will let rogue events through (shouldn't really happen, but better safe
1610 than sorry) */
1611 bool handled_event=true;
1612 UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event);
1613 switch(eclass)
1614 {
1615 case kEventClassQt:
1616 if(ekind == kEventQtRequestShowSheet) {
1617 request_showsheet_pending = 0;
1618 QWidget *widget = 0;
1619 GetEventParameter(event, kEventParamQWidget, typeQWidget, 0,
1620 sizeof(widget), 0, &widget);
1621 if(widget) {
1622 if (widget->macEvent(er, event))
1623 return noErr;
1624 WindowPtr window = qt_mac_window_for(widget);
1625 bool just_show = !qt_mac_is_macsheet(widget);
1626 if(!just_show) {
1627 OSStatus err = ShowSheetWindow(window, qt_mac_window_for(widget->parentWidget()));
1628 if(err != noErr)
1629 qWarning("Qt: QWidget: Unable to show as sheet %s::%s [%ld]", widget->metaObject()->className(),
1630 widget->objectName().toLocal8Bit().constData(), long(err));
1631 just_show = true;
1632 }
1633 if(just_show) //at least the window will be visible, but the sheet flag doesn't work sadly (probalby too many sheets)
1634 ShowHide(window, true);
1635 }
1636 } else if(ekind == kEventQtRequestWindowChange) {
1637 qt_mac_event_release(request_window_change_pending);
1638 } else if(ekind == kEventQtRequestMenubarUpdate) {
1639 qt_mac_event_release(request_menubarupdate_pending);
1640 QMenuBar::macUpdateMenuBar();
1641 } else if(ekind == kEventQtRequestActivate) {
1642 qt_mac_event_release(request_activate_pending.event);
1643 if(request_activate_pending.widget) {
1644 QWidget *tlw = request_activate_pending.widget->window();
1645 if (tlw->macEvent(er, event))
1646 return noErr;
1647 request_activate_pending.widget = 0;
1648 tlw->activateWindow();
1649 SelectWindow(qt_mac_window_for(tlw));
1650 }
1651 } else if(ekind == kEventQtRequestContext) {
1652 bool send = false;
1653 if ((send = (event == request_context_pending)))
1654 qt_mac_event_release(request_context_pending);
1655 if(send) {
1656 //figure out which widget to send it to
1657 QPoint where = QCursor::pos();
1658 QWidget *widget = 0;
1659 GetEventParameter(event, kEventParamQWidget, typeQWidget, 0,
1660 sizeof(widget), 0, &widget);
1661 if(!widget) {
1662 if(qt_button_down)
1663 widget = qt_button_down;
1664 else
1665 widget = QApplication::widgetAt(where.x(), where.y());
1666 }
1667 if(widget && !isBlockedByModal(widget)) {
1668 if (widget->macEvent(er, event))
1669 return noErr;
1670 QPoint plocal(widget->mapFromGlobal(where));
1671 const Qt::KeyboardModifiers keyboardModifiers = qt_mac_get_modifiers(GetCurrentEventKeyModifiers());
1672 QContextMenuEvent qme(QContextMenuEvent::Mouse, plocal, where, keyboardModifiers);
1673 QApplication::sendEvent(widget, &qme);
1674 if(qme.isAccepted()) { //once this happens the events before are pitched
1675 qt_button_down = 0;
1676 qt_mac_dblclick.last_widget = 0;
1677 }
1678 } else {
1679 handled_event = false;
1680 }
1681 }
1682 } else {
1683 handled_event = false;
1684 }
1685 break;
1686 case kEventClassTablet:
1687 switch (ekind) {
1688 case kEventTabletProximity:
1689 // Get the current point of the device and its unique ID.
1690 ::TabletProximityRec proxRec;
1691 GetEventParameter(event, kEventParamTabletProximityRec, typeTabletProximityRec, 0,
1692 sizeof(proxRec), 0, &proxRec);
1693 qt_dispatchTabletProximityEvent(proxRec);
1694 }
1695 break;
1696 case kEventClassMouse:
1697 {
1698 static const int kEventParamQAppSeenMouseEvent = 'QASM';
1699 // Check if we've seen the event, if we have we shouldn't process
1700 // it again as it may lead to spurious "double events"
1701 bool seenEvent;
1702 if (GetEventParameter(event, kEventParamQAppSeenMouseEvent,
1703 typeBoolean, 0, sizeof(bool), 0, &seenEvent) == noErr) {
1704 if (seenEvent)
1705 return eventNotHandledErr;
1706 }
1707 seenEvent = true;
1708 SetEventParameter(event, kEventParamQAppSeenMouseEvent, typeBoolean,
1709 sizeof(bool), &seenEvent);
1710
1711 Point where;
1712 bool inNonClientArea = false;
1713 GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0,
1714 sizeof(where), 0, &where);
1715#if defined(DEBUG_MOUSE_MAPS)
1716 const char *edesc = 0;
1717 switch(ekind) {
1718 case kEventMouseDown: edesc = "MouseButtonPress"; break;
1719 case kEventMouseUp: edesc = "MouseButtonRelease"; break;
1720 case kEventMouseDragged: case kEventMouseMoved: edesc = "MouseMove"; break;
1721 case kEventMouseScroll: edesc = "MouseWheelScroll"; break;
1722 case kEventMouseWheelMoved: edesc = "MouseWheelMove"; break;
1723 }
1724 if(ekind == kEventMouseDown || ekind == kEventMouseUp)
1725 qDebug("Handling mouse: %s", edesc);
1726#endif
1727 QEvent::Type etype = QEvent::None;
1728 Qt::KeyboardModifiers modifiers;
1729 {
1730 UInt32 mac_modifiers = 0;
1731 GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, 0,
1732 sizeof(mac_modifiers), 0, &mac_modifiers);
1733 modifiers = qt_mac_get_modifiers(mac_modifiers);
1734 }
1735 Qt::MouseButtons buttons;
1736 {
1737 UInt32 mac_buttons = 0;
1738 GetEventParameter(event, kEventParamMouseChord, typeUInt32, 0,
1739 sizeof(mac_buttons), 0, &mac_buttons);
1740 if (ekind != kEventMouseWheelMoved)
1741 buttons = qt_mac_get_buttons(mac_buttons);
1742 else
1743 buttons = QApplication::mouseButtons();
1744 }
1745
1746 int wheel_deltaX = 0;
1747 int wheel_deltaY = 0;
1748 static EventRef compatibilityEvent = 0;
1749
1750 if (ekind == kEventMouseScroll) {
1751 // kEventMouseScroll is the new way of dealing with mouse wheel
1752 // events (kEventMouseWheelMoved was the old). kEventMouseScroll results
1753 // in much smoother scrolling when using Mighty Mouse or TrackPad. For
1754 // compatibility with older applications, carbon will also send us
1755 // kEventMouseWheelMoved events if we dont eat this event
1756 // (actually two events; one for horizontal and one for vertical).
1757 // As a results of this, and to make sure we dont't receive duplicate events,
1758 // we try to detect when this happend by checking the 'compatibilityEvent'.
1759 // Since delta is delivered as pixels rather than degrees, we need to
1760 // convert from pixels to degrees in a sensible manner.
1761 // It looks like 1/4 degrees per pixel behaves most native.
1762 // (NB: Qt expects the unit for delta to be 8 per degree):
1763 const int pixelsToDegrees = 2;
1764 SInt32 mdelt = 0;
1765 GetEventParameter(event, kEventParamMouseWheelSmoothHorizontalDelta, typeSInt32, 0,
1766 sizeof(mdelt), 0, &mdelt);
1767 wheel_deltaX = mdelt * pixelsToDegrees;
1768 mdelt = 0;
1769 GetEventParameter(event, kEventParamMouseWheelSmoothVerticalDelta, typeSInt32, 0,
1770 sizeof(mdelt), 0, &mdelt);
1771 wheel_deltaY = mdelt * pixelsToDegrees;
1772 GetEventParameter(event, kEventParamEventRef, typeEventRef, 0,
1773 sizeof(compatibilityEvent), 0, &compatibilityEvent);
1774 } else if (ekind == kEventMouseWheelMoved) {
1775 if (event != compatibilityEvent) {
1776 compatibilityEvent = 0;
1777 int mdelt = 0;
1778 GetEventParameter(event, kEventParamMouseWheelDelta, typeSInt32, 0,
1779 sizeof(mdelt), 0, &mdelt);
1780 EventMouseWheelAxis axis;
1781 GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, 0,
1782 sizeof(axis), 0, &axis);
1783
1784 // Remove acceleration, and use either -120 or 120 as delta:
1785 if (axis == kEventMouseWheelAxisX)
1786 wheel_deltaX = qBound(-120, int(mdelt * 10000), 120);
1787 else
1788 wheel_deltaY = qBound(-120, int(mdelt * 10000), 120);
1789 }
1790 }
1791
1792 Qt::MouseButton button = Qt::NoButton;
1793 if(ekind == kEventMouseDown || ekind == kEventMouseUp) {
1794 EventMouseButton mac_button = 0;
1795 GetEventParameter(event, kEventParamMouseButton, typeMouseButton, 0,
1796 sizeof(mac_button), 0, &mac_button);
1797 button = qt_mac_get_button(mac_button);
1798 }
1799
1800 switch(ekind) {
1801 case kEventMouseDown:
1802 etype = QEvent::MouseButtonPress;
1803 break;
1804 case kEventMouseUp:
1805 etype = QEvent::MouseButtonRelease;
1806 break;
1807 case kEventMouseDragged:
1808 case kEventMouseMoved:
1809 etype = QEvent::MouseMove;
1810 break;
1811 }
1812
1813 const bool inPopupMode = app->d_func()->inPopupMode();
1814
1815 // A click outside a popup closes the popup. Make sure
1816 // that no events are generated for the release part of that click.
1817 // (The press goes to the popup and closes it.)
1818 if (etype == QEvent::MouseButtonPress) {
1819 qt_mac_previous_press_in_popup_mode = inPopupMode;
1820 } else if (qt_mac_previous_press_in_popup_mode && !inPopupMode && etype == QEvent::MouseButtonRelease) {
1821 qt_mac_previous_press_in_popup_mode = false;
1822 handled_event = true;
1823#if defined(DEBUG_MOUSE_MAPS)
1824 qDebug("Bail out early due to qt_mac_previous_press_in_popup_mode");
1825#endif
1826 break; // break from case kEventClassMouse
1827 }
1828
1829 //figure out which widget to send it to
1830 if(inPopupMode) {
1831 QWidget *popup = qApp->activePopupWidget();
1832 if (qt_button_down && qt_button_down->window() == popup) {
1833 widget = qt_button_down;
1834 } else {
1835 QPoint pos = popup->mapFromGlobal(QPoint(where.h, where.v));
1836 widget = popup->childAt(pos);
1837 }
1838 if(!widget)
1839 widget = popup;
1840 } else {
1841 if(mac_mouse_grabber) {
1842 widget = mac_mouse_grabber;
1843 } else if (qt_button_down) {
1844 widget = qt_button_down;
1845 } else {
1846 {
1847 WindowPtr window = 0;
1848 if(GetEventParameter(event, kEventParamWindowRef, typeWindowRef, 0,
1849 sizeof(window), 0, &window) != noErr)
1850 FindWindowOfClass(&where, kAllWindowClasses, &window, 0);
1851 if(window) {
1852 HIViewRef hiview;
1853 if(HIViewGetViewForMouseEvent(HIViewGetRoot(window), event, &hiview) == noErr) {
1854 widget = QWidget::find((WId)hiview);
1855 if (widget) {
1856 // Make sure we didn't pass over a widget with a "fake hole" in it.
1857 QWidget *otherWidget = QApplication::widgetAt(where.h, where.v);
1858 if (otherWidget && otherWidget->testAttribute(Qt::WA_MouseNoMask))
1859 widget = otherWidget;
1860 }
1861 }
1862 }
1863 }
1864 if(!widget) //fallback
1865 widget = QApplication::widgetAt(where.h, where.v);
1866 if(ekind == kEventMouseUp && widget) {
1867 short part = qt_mac_window_at(where.h, where.v);
1868 if(part == inDrag) {
1869 UInt32 count = 0;
1870 GetEventParameter(event, kEventParamClickCount, typeUInt32, NULL,
1871 sizeof(count), NULL, &count);
1872 if(count == 2 && qt_mac_collapse_on_dblclick) {
1873 if (widget->macEvent(er, event))
1874 return noErr;
1875 widget->setWindowState(widget->windowState() | Qt::WindowMinimized);
1876 //we send a hide to be like X11/Windows
1877 QEvent e(QEvent::Hide);
1878 QApplication::sendSpontaneousEvent(widget, &e);
1879 break;
1880 }
1881 }
1882 }
1883 }
1884 }
1885 if (widget && widget->macEvent(er, event))
1886 return noErr;
1887 WindowPartCode wpc = qt_mac_window_at(where.h, where.v, 0);
1888 if (wpc == inProxyIcon && modifiers == Qt::ControlModifier && buttons != Qt::NoButton) {
1889 QIconDragEvent e;
1890 QApplication::sendSpontaneousEvent(widget, &e);
1891 if (e.isAccepted()) {
1892 return noErr; // IconDrag ate it.
1893 }
1894 }
1895 if (inPopupMode == false
1896 && (qt_button_down == 0 || qt_button_down_in_content == false)
1897 && (wpc != inContent && wpc != inStructure)) {
1898 inNonClientArea = true;
1899 switch (etype) {
1900 case QEvent::MouseButtonPress: {
1901 UInt32 count = 0;
1902 GetEventParameter(event, kEventParamClickCount, typeUInt32, 0,
1903 sizeof(count), 0, &count);
1904 if(count % 2 || count == 0) {
1905 etype = QEvent::NonClientAreaMouseButtonPress;
1906 } else {
1907 etype = QEvent::NonClientAreaMouseButtonDblClick;
1908 }} break;
1909 case QEvent::MouseButtonRelease:
1910 etype = QEvent::NonClientAreaMouseButtonRelease;
1911 break;
1912 case QEvent::MouseMove:
1913 if (widget == 0 || widget->hasMouseTracking())
1914 etype = QEvent::NonClientAreaMouseMove;
1915 break;
1916 default:
1917 break;
1918 }
1919 }
1920
1921 if(qt_mac_find_window((FrontWindow()))) { //set the cursor up
1922 QCursor cursor(Qt::ArrowCursor);
1923 QWidget *cursor_widget = widget;
1924 if(cursor_widget && cursor_widget == qt_button_down && ekind == kEventMouseUp)
1925 cursor_widget = QApplication::widgetAt(where.h, where.v);
1926 if(cursor_widget) { //only over the app, do we set a cursor..
1927 if(!qApp->d_func()->cursor_list.isEmpty()) {
1928 cursor = qApp->d_func()->cursor_list.first();
1929 } else {
1930 for(; cursor_widget; cursor_widget = cursor_widget->parentWidget()) {
1931 QWExtra *extra = cursor_widget->d_func()->extraData();
1932 if(extra && extra->curs && cursor_widget->isEnabled()) {
1933 cursor = *extra->curs;
1934 break;
1935 }
1936 }
1937 }
1938 }
1939 qt_mac_set_cursor(&cursor, QPoint(where.h, where.v));
1940 }
1941
1942 //This mouse button state stuff looks like this on purpose
1943 //although it looks hacky it is VERY intentional..
1944 if(widget && app_do_modal && !qt_try_modal(widget, event)) {
1945 if(ekind == kEventMouseDown && qt_mac_is_macsheet(QApplication::activeModalWidget()))
1946 QApplication::activeModalWidget()->parentWidget()->activateWindow(); //sheets have a parent
1947 handled_event = false;
1948#if defined(DEBUG_MOUSE_MAPS)
1949 qDebug("Bail out early due to qt_try_modal");
1950#endif
1951 break;
1952 }
1953
1954 UInt32 tabletEventType = 0;
1955 GetEventParameter(event, kEventParamTabletEventType, typeUInt32, 0,
1956 sizeof(tabletEventType), 0, &tabletEventType);
1957 if (tabletEventType == kEventTabletPoint) {
1958 TabletPointRec tabletPointRec;
1959 GetEventParameter(event, kEventParamTabletPointRec, typeTabletPointRec, 0,
1960 sizeof(tabletPointRec), 0, &tabletPointRec);
1961 QEvent::Type t = QEvent::TabletMove; //default
1962 int new_tablet_button_state = tabletPointRec.buttons ? 1 : 0;
1963 if (new_tablet_button_state != tablet_button_state)
1964 if (new_tablet_button_state)
1965 t = QEvent::TabletPress;
1966 else
1967 t = QEvent::TabletRelease;
1968 tablet_button_state = new_tablet_button_state;
1969
1970 QMacTabletHash *tabletHash = qt_mac_tablet_hash();
1971 if (!tabletHash->contains(tabletPointRec.deviceID) && t != QEvent::TabletRelease) {
1972 // Never discard TabletRelease events as they may be delivered *after* TabletLeaveProximity events
1973 qWarning("handleTabletEvent: This tablet device is unknown"
1974 " (received no proximity event for it). Discarding event.");
1975 return false;
1976 }
1977 QTabletDeviceData &deviceData = tabletHash->operator[](tabletPointRec.deviceID);
1978 if (t == QEvent::TabletPress) {
1979 deviceData.widgetToGetPress = widget;
1980 } else if (t == QEvent::TabletRelease && deviceData.widgetToGetPress) {
1981 widget = deviceData.widgetToGetPress;
1982 deviceData.widgetToGetPress = 0;
1983 }
1984
1985 if (widget) {
1986 int tiltX = ((int)tabletPointRec.tiltX)/(32767/64); // 32K -> 60
1987 int tiltY = ((int)tabletPointRec.tiltY)/(-32767/64); // 32K -> 60
1988 HIPoint hiPoint;
1989 GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, 0, sizeof(HIPoint), 0, &hiPoint);
1990 QPointF hiRes(hiPoint.x, hiPoint.y);
1991 QPoint global(where.h, where.v);
1992
1993
1994
1995 QPoint local(widget->mapFromGlobal(global));
1996 int z = 0;
1997 qreal rotation = 0.0;
1998 qreal tp = 0.0;
1999 // Again from the Wacom.h header
2000
2001 if (deviceData.capabilityMask & 0x0200) // Z-axis
2002 z = tabletPointRec.absZ;
2003
2004 if (deviceData.capabilityMask & 0x0800) // Tangential pressure
2005 tp = tabletPointRec.tangentialPressure / 32767.0;
2006
2007 if (deviceData.capabilityMask & 0x2000) // Rotation
2008 rotation = qreal(tabletPointRec.rotation) / 64.0;
2009
2010 QTabletEvent e(t, local, global, hiRes, deviceData.tabletDeviceType,
2011 deviceData.tabletPointerType,
2012 qreal(tabletPointRec.pressure / qreal(0xffff)), tiltX, tiltY,
2013 tp, rotation, z, modifiers, deviceData.tabletUniqueID);
2014 QApplication::sendSpontaneousEvent(widget, &e);
2015 if (e.isAccepted()) {
2016 if (t == QEvent::TabletPress) {
2017 qt_button_down = widget;
2018 } else if (t == QEvent::TabletRelease) {
2019 qt_button_down = 0;
2020 }
2021#if defined(DEBUG_MOUSE_MAPS)
2022 qDebug("Bail out early due to tablet acceptance");
2023#endif
2024 break;
2025 }
2026 }
2027 }
2028
2029 if(ekind == kEventMouseDown) {
2030 qt_mac_no_click_through_mode = false;
2031 const short windowPart = qt_mac_window_at(where.h, where.v, 0);
2032 // Menubar almost always wins.
2033 if (!inPopupMode && windowPart == inMenuBar) {
2034 MenuSelect(where); //allow menu tracking
2035 return noErr;
2036 }
2037
2038 if (widget && !(GetCurrentKeyModifiers() & cmdKey)) {
2039 extern bool qt_isGenuineQWidget(const QWidget *); // qwidget_mac.cpp
2040 QWidget *window = widget->window();
2041 bool genuineQtWidget = qt_isGenuineQWidget(widget); // the widget, not the window.
2042 window->raise();
2043
2044 bool needActivate = (window->windowType() != Qt::Desktop)
2045 && (window->windowType() != Qt::Popup)
2046 && !qt_mac_is_macsheet(window);
2047 if (needActivate && (!window->isModal() && qobject_cast<QDockWidget *>(window)))
2048 needActivate = false;
2049
2050 if (genuineQtWidget && needActivate)
2051 needActivate = !window->isActiveWindow()
2052 || !IsWindowActive(qt_mac_window_for(window));
2053
2054 if (needActivate) {
2055 window->activateWindow();
2056 if (!qt_mac_can_clickThrough(widget)) {
2057 qt_mac_no_click_through_mode = true;
2058 handled_event = false;
2059#if defined(DEBUG_MOUSE_MAPS)
2060 qDebug("Bail out early due to qt_mac_canClickThrough %s::%s", widget->metaObject()->className(),
2061 widget->objectName().toLocal8Bit().constData());
2062#endif
2063 break;
2064 }
2065 }
2066 }
2067
2068 if(qt_mac_dblclick.last_widget &&
2069 qt_mac_dblclick.last_x != -1 && qt_mac_dblclick.last_y != -1 &&
2070 QRect(qt_mac_dblclick.last_x-2, qt_mac_dblclick.last_y-2, 4, 4).contains(QPoint(where.h, where.v))) {
2071 if(qt_mac_dblclick.use_qt_time_limit) {
2072 EventTime now = GetEventTime(event);
2073 if(qt_mac_dblclick.last_time != -2 && qt_mac_dblclick.last_widget == widget &&
2074 now - qt_mac_dblclick.last_time <= ((double)QApplicationPrivate::mouse_double_click_time)/1000 &&
2075 qt_mac_dblclick.last_button == button)
2076 etype = QEvent::MouseButtonDblClick;
2077 } else {
2078 UInt32 count = 0;
2079 GetEventParameter(event, kEventParamClickCount, typeUInt32, 0,
2080 sizeof(count), 0, &count);
2081 if(!(count % 2) && qt_mac_dblclick.last_modifiers == modifiers &&
2082 qt_mac_dblclick.last_widget == widget && qt_mac_dblclick.last_button == button)
2083 etype = QEvent::MouseButtonDblClick;
2084 }
2085 if(etype == QEvent::MouseButtonDblClick)
2086 qt_mac_dblclick.last_widget = 0;
2087 }
2088 if(etype != QEvent::MouseButtonDblClick) {
2089 qt_mac_dblclick.last_x = where.h;
2090 qt_mac_dblclick.last_y = where.v;
2091 } else {
2092 qt_mac_dblclick.last_x = qt_mac_dblclick.last_y = -1;
2093 }
2094 } else if(qt_mac_no_click_through_mode) {
2095 if(ekind == kEventMouseUp)
2096 qt_mac_no_click_through_mode = false;
2097 handled_event = false;
2098#if defined(DEBUG_MOUSE_MAPS)
2099 qDebug("Bail out early due to qt_mac_no_click_through_mode");
2100#endif
2101 break;
2102 }
2103
2104 QPointer<QWidget> leaveAfterRelease = 0;
2105 switch(ekind) {
2106 case kEventMouseUp:
2107 if (!buttons) {
2108 if (!inPopupMode && !QWidget::mouseGrabber())
2109 leaveAfterRelease = qt_button_down;
2110 qt_button_down = 0;
2111 }
2112 break;
2113 case kEventMouseDown: {
2114 if (!qt_button_down)
2115 qt_button_down = widget;
2116 WindowPartCode wpc = qt_mac_window_at(where.h, where.v, 0);
2117 qt_button_down_in_content = (wpc == inContent || wpc == inStructure);
2118 break; }
2119 }
2120
2121 // Check if we should send enter/leave events:
2122 switch(ekind) {
2123 case kEventMouseDragged:
2124 case kEventMouseMoved:
2125 case kEventMouseUp:
2126 case kEventMouseDown: {
2127 // If we are in popup mode, widget will point to the current popup no matter
2128 // where the mouse cursor is. In that case find out if the mouse cursor is
2129 // really over the popup in order to send correct enter / leave envents.
2130 QWidget * const enterLeaveWidget = (inPopupMode || ekind == kEventMouseUp) ?
2131 QApplication::widgetAt(where.h, where.v) : static_cast<QWidget*>(widget);
2132
2133 if ((QWidget *) qt_mouseover != enterLeaveWidget || inNonClientArea) {
2134#ifdef DEBUG_MOUSE_MAPS
2135 qDebug("Entering: %p - %s (%s), Leaving %s (%s)", (QWidget*)enterLeaveWidget,
2136 enterLeaveWidget ? enterLeaveWidget->metaObject()->className() : "none",
2137 enterLeaveWidget ? enterLeaveWidget->objectName().toLocal8Bit().constData() : "",
2138 qt_mouseover ? qt_mouseover->metaObject()->className() : "none",
2139 qt_mouseover ? qt_mouseover->objectName().toLocal8Bit().constData() : "");
2140#endif
2141
2142 QWidget * const mouseGrabber = QWidget::mouseGrabber();
2143
2144 if (inPopupMode) {
2145 QWidget *enter = enterLeaveWidget;
2146 QWidget *leave = qt_mouseover;
2147 if (mouseGrabber) {
2148 QWidget * const popupWidget = qApp->activePopupWidget();
2149 if (leave == popupWidget)
2150 enter = mouseGrabber;
2151 if (enter == popupWidget)
2152 leave = mouseGrabber;
2153 if ((enter == mouseGrabber && leave == popupWidget)
2154 || (leave == mouseGrabber && enter == popupWidget)) {
2155 QApplicationPrivate::dispatchEnterLeave(enter, leave);
2156 qt_mouseover = enter;
2157 }
2158 } else {
2159 QApplicationPrivate::dispatchEnterLeave(enter, leave);
2160 qt_mouseover = enter;
2161 }
2162 } else if ((!qt_button_down || !qt_mouseover) && !mouseGrabber && !leaveAfterRelease) {
2163 QApplicationPrivate::dispatchEnterLeave(enterLeaveWidget, qt_mouseover);
2164 qt_mouseover = enterLeaveWidget;
2165 }
2166 }
2167 break; }
2168 }
2169
2170 if(widget) {
2171 QPoint p(where.h, where.v);
2172 QPoint plocal(widget->mapFromGlobal(p));
2173 if(etype == QEvent::MouseButtonPress) {
2174 qt_mac_dblclick.last_widget = widget;
2175 qt_mac_dblclick.last_modifiers = modifiers;
2176 qt_mac_dblclick.last_button = button;
2177 qt_mac_dblclick.last_time = GetEventTime(event);
2178 }
2179
2180 if (wheel_deltaX || wheel_deltaY) {
2181#ifndef QT_NO_WHEELEVENT
2182 if (wheel_deltaX) {
2183 QWheelEvent qwe(plocal, p, wheel_deltaX, buttons, modifiers, Qt::Horizontal);
2184 QApplication::sendSpontaneousEvent(widget, &qwe);
2185 if (!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) {
2186 QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p,
2187 wheel_deltaX, buttons, modifiers, Qt::Horizontal);
2188 QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
2189 if (!qwe2.isAccepted())
2190 handled_event = false;
2191 }
2192 }
2193 if (wheel_deltaY) {
2194 QWheelEvent qwe(plocal, p, wheel_deltaY, buttons, modifiers, Qt::Vertical);
2195 QApplication::sendSpontaneousEvent(widget, &qwe);
2196 if (!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) {
2197 QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p,
2198 wheel_deltaY, buttons, modifiers, Qt::Vertical);
2199 QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
2200 if (!qwe2.isAccepted())
2201 handled_event = false;
2202 }
2203 }
2204#endif // QT_NO_WHEELEVENT
2205 } else {
2206#ifdef QMAC_SPEAK_TO_ME
2207 const int speak_keys = Qt::AltModifier | Qt::ShiftModifier;
2208 if(etype == QMouseEvent::MouseButtonDblClick && ((modifiers & speak_keys) == speak_keys)) {
2209 QVariant v = widget->property("displayText");
2210 if(!v.isValid()) v = widget->property("text");
2211 if(!v.isValid()) v = widget->property("windowTitle");
2212 if(v.isValid()) {
2213 QString s = v.toString();
2214 s.replace(QRegExp(QString::fromLatin1("(\\&|\\<[^\\>]*\\>)")), QLatin1String(""));
2215 SpeechChannel ch;
2216 NewSpeechChannel(0, &ch);
2217 SpeakText(ch, s.toLatin1().constData(), s.length());
2218 DisposeSpeechChannel(ch);
2219 }
2220 }
2221#endif
2222 Qt::MouseButton buttonToSend = button;
2223 static bool lastButtonTranslated = false;
2224 if(ekind == kEventMouseDown &&
2225 button == Qt::LeftButton && (modifiers & Qt::MetaModifier)) {
2226 buttonToSend = Qt::RightButton;
2227 lastButtonTranslated = true;
2228 } else if(ekind == kEventMouseUp && lastButtonTranslated) {
2229 buttonToSend = Qt::RightButton;
2230 lastButtonTranslated = false;
2231 }
2232 QMouseEvent qme(etype, plocal, p, buttonToSend, buttons, modifiers);
2233 QApplication::sendSpontaneousEvent(widget, &qme);
2234 if(!qme.isAccepted() || inNonClientArea)
2235 handled_event = false;
2236 }
2237
2238 if (leaveAfterRelease) {
2239 QWidget *enter = QApplication::widgetAt(where.h, where.v);
2240 QApplicationPrivate::dispatchEnterLeave(enter, leaveAfterRelease);
2241 qt_mouseover = enter;
2242 leaveAfterRelease = 0;
2243 }
2244
2245 if(ekind == kEventMouseDown &&
2246 ((button == Qt::RightButton) ||
2247 (button == Qt::LeftButton && (modifiers & Qt::MetaModifier))))
2248 qt_event_request_context();
2249
2250#ifdef DEBUG_MOUSE_MAPS
2251 const char *event_desc = edesc;
2252 if(etype == QEvent::MouseButtonDblClick)
2253 event_desc = "Double Click";
2254 else if(etype == QEvent::NonClientAreaMouseButtonPress)
2255 event_desc = "NonClientMousePress";
2256 else if(etype == QEvent::NonClientAreaMouseButtonRelease)
2257 event_desc = "NonClientMouseRelease";
2258 else if(etype == QEvent::NonClientAreaMouseMove)
2259 event_desc = "NonClientMouseMove";
2260 else if(etype == QEvent::NonClientAreaMouseButtonDblClick)
2261 event_desc = "NonClientMouseDblClick";
2262 qDebug("%d %d (%d %d) - Would send (%s) event to %p %s %s (%d 0x%08x 0x%08x %d)", p.x(), p.y(),
2263 plocal.x(), plocal.y(), event_desc, (QWidget*)widget,
2264 widget ? widget->objectName().toLocal8Bit().constData() : "*Unknown*",
2265 widget ? widget->metaObject()->className() : "*Unknown*",
2266 button, (int)buttons, (int)modifiers, wheel_deltaX);
2267#endif
2268 } else {
2269 handled_event = false;
2270 }
2271 break;
2272 }
2273 case kEventClassTextInput:
2274 case kEventClassKeyboard: {
2275 EventRef key_event = event;
2276 if(eclass == kEventClassTextInput) {
2277 Q_ASSERT(ekind == kEventTextInputUnicodeForKeyEvent);
2278 OSStatus err = GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, 0,
2279 sizeof(key_event), 0, &key_event);
2280 Q_ASSERT(err == noErr);
2281 Q_UNUSED(err);
2282 }
2283 const UInt32 key_ekind = GetEventKind(key_event);
2284 Q_ASSERT(GetEventClass(key_event) == kEventClassKeyboard);
2285
2286 if(key_ekind == kEventRawKeyDown)
2287 qt_keymapper_private()->updateKeyMap(er, key_event, data);
2288 if(mac_keyboard_grabber)
2289 widget = mac_keyboard_grabber;
2290 else if (app->activePopupWidget())
2291 widget = (app->activePopupWidget()->focusWidget() ?
2292 app->activePopupWidget()->focusWidget() : app->activePopupWidget());
2293 else if(QApplication::focusWidget())
2294 widget = QApplication::focusWidget();
2295 else
2296 widget = app->activeWindow();
2297
2298 if (widget) {
2299 if (widget->macEvent(er, event))
2300 return noErr;
2301 } else {
2302 // Darn, I need to update tho modifier state, even though
2303 // Qt itself isn't getting them, otherwise the keyboard state get inconsistent.
2304 if (key_ekind == kEventRawKeyModifiersChanged) {
2305 UInt32 modifiers = 0;
2306 GetEventParameter(key_event, kEventParamKeyModifiers, typeUInt32, 0,
2307 sizeof(modifiers), 0, &modifiers);
2308 extern void qt_mac_send_modifiers_changed(quint32 modifiers, QObject *object); // qkeymapper_mac.cpp
2309 // Just send it to the qApp for the time being.
2310 qt_mac_send_modifiers_changed(modifiers, qApp);
2311 }
2312 handled_event = false;
2313 break;
2314 }
2315
2316 if(app_do_modal && !qt_try_modal(widget, key_event))
2317 break;
2318 if (eclass == kEventClassTextInput) {
2319 handled_event = false;
2320 } else {
2321 handled_event = qt_keymapper_private()->translateKeyEvent(widget, er, key_event, data,
2322 widget == mac_keyboard_grabber);
2323 }
2324 break; }
2325 case kEventClassWindow: {
2326 WindowRef wid = 0;
2327 GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0,
2328 sizeof(WindowRef), 0, &wid);
2329 widget = qt_mac_find_window(wid);
2330 if (widget && widget->macEvent(er, event))
2331 return noErr;
2332 if(ekind == kEventWindowActivated) {
2333 if(QApplicationPrivate::app_style) {
2334 QEvent ev(QEvent::Style);
2335 QApplication::sendSpontaneousEvent(QApplicationPrivate::app_style, &ev);
2336 }
2337
2338 if(widget && app_do_modal && !qt_try_modal(widget, event))
2339 break;
2340
2341 if(widget && widget->window()->isVisible()) {
2342 QWidget *tlw = widget->window();
2343 if(tlw->isWindow() && !(tlw->windowType() == Qt::Popup)
2344 && !qt_mac_is_macdrawer(tlw)
2345 && (!tlw->parentWidget() || tlw->isModal()
2346 || !(tlw->windowType() == Qt::Tool))) {
2347 bool just_send_event = false;
2348 {
2349 WindowActivationScope scope;
2350 if(GetWindowActivationScope((WindowRef)wid, &scope) == noErr &&
2351 scope == kWindowActivationScopeIndependent) {
2352 if(GetFrontWindowOfClass(kAllWindowClasses, true) != wid)
2353 just_send_event = true;
2354 }
2355 }
2356 if(just_send_event) {
2357 QEvent e(QEvent::WindowActivate);
2358 QApplication::sendSpontaneousEvent(widget, &e);
2359 } else {
2360 app->setActiveWindow(tlw);
2361 }
2362 }
2363 QMenuBar::macUpdateMenuBar();
2364 }
2365 } else if(ekind == kEventWindowDeactivated) {
2366 if(widget && QApplicationPrivate::active_window == widget)
2367 app->setActiveWindow(0);
2368 } else {
2369 handled_event = false;
2370 }
2371 break; }
2372 case kEventClassApplication:
2373 if(ekind == kEventAppActivated) {
2374 if(QApplication::desktopSettingsAware())
2375 qt_mac_update_os_settings();
2376 if(qt_clipboard) { //manufacture an event so the clipboard can see if it has changed
2377 QEvent ev(QEvent::Clipboard);
2378 QApplication::sendSpontaneousEvent(qt_clipboard, &ev);
2379 }
2380 if(app) {
2381 QEvent ev(QEvent::ApplicationActivate);
2382 QApplication::sendSpontaneousEvent(app, &ev);
2383 }
2384 if(!app->activeWindow()) {
2385 WindowPtr wp = ActiveNonFloatingWindow();
2386 if(QWidget *tmp_w = qt_mac_find_window(wp))
2387 app->setActiveWindow(tmp_w);
2388 }
2389 QMenuBar::macUpdateMenuBar();
2390 } else if(ekind == kEventAppDeactivated) {
2391 //qt_mac_no_click_through_mode = false;
2392 while(app->d_func()->inPopupMode())
2393 app->activePopupWidget()->close();
2394 if(app) {
2395 QEvent ev(QEvent::ApplicationDeactivate);
2396 QApplication::sendSpontaneousEvent(app, &ev);
2397 }
2398 app->setActiveWindow(0);
2399 } else if(ekind == kEventAppAvailableWindowBoundsChanged) {
2400 QDesktopWidgetImplementation::instance()->onResize();
2401 } else {
2402 handled_event = false;
2403 }
2404 break;
2405 case kAppearanceEventClass:
2406 if(ekind == kAEAppearanceChanged) {
2407 if(QApplication::desktopSettingsAware())
2408 qt_mac_update_os_settings();
2409 if(QApplicationPrivate::app_style) {
2410 QEvent ev(QEvent::Style);
2411 QApplication::sendSpontaneousEvent(QApplicationPrivate::app_style, &ev);
2412 }
2413 } else {
2414 handled_event = false;
2415 }
2416 break;
2417 case kEventClassAppleEvent:
2418 if(ekind == kEventAppleEvent) {
2419 EventRecord erec;
2420 if(!ConvertEventRefToEventRecord(event, &erec))
2421 qDebug("Qt: internal: WH0A, unexpected condition reached. %s:%d", __FILE__, __LINE__);
2422 else if(AEProcessAppleEvent(&erec) != noErr)
2423 handled_event = false;
2424 } else {
2425 handled_event = false;
2426 }
2427 break;
2428 case kEventClassCommand:
2429 if(ekind == kEventCommandProcess) {
2430 HICommand cmd;
2431 GetEventParameter(event, kEventParamDirectObject, typeHICommand,
2432 0, sizeof(cmd), 0, &cmd);
2433 handled_event = false;
2434 if(!cmd.menu.menuRef && GetApplicationDockTileMenu()) {
2435 EventRef copy = CopyEvent(event);
2436 HICommand copy_cmd;
2437 GetEventParameter(event, kEventParamDirectObject, typeHICommand,
2438 0, sizeof(copy_cmd), 0, &copy_cmd);
2439 copy_cmd.menu.menuRef = GetApplicationDockTileMenu();
2440 SetEventParameter(copy, kEventParamDirectObject, typeHICommand, sizeof(copy_cmd), &copy_cmd);
2441 if(SendEventToMenu(copy, copy_cmd.menu.menuRef) == noErr)
2442 handled_event = true;
2443 }
2444 if(!handled_event) {
2445 if(cmd.commandID == kHICommandQuit) {
2446 // Quitting the application is not Qt's responsibility if
2447 // used in a plugin or just embedded into a native application.
2448 // In that case, let the event pass down to the native apps event handler.
2449 if (!QApplication::testAttribute(Qt::AA_MacPluginApplication)) {
2450 handled_event = true;
2451 HiliteMenu(0);
2452 bool handle_quit = true;
2453 if(QApplicationPrivate::modalState()) {
2454 int visible = 0;
2455 const QWidgetList tlws = QApplication::topLevelWidgets();
2456 for(int i = 0; i < tlws.size(); ++i) {
2457 if(tlws.at(i)->isVisible())
2458 ++visible;
2459 }
2460 handle_quit = (visible <= 1);
2461 }
2462 if(handle_quit) {
2463 QCloseEvent ev;
2464 QApplication::sendSpontaneousEvent(app, &ev);
2465 if(ev.isAccepted())
2466 app->quit();
2467 } else {
2468 QApplication::beep();
2469 }
2470 }
2471 } else if(cmd.commandID == kHICommandSelectWindow) {
2472 if((GetCurrentKeyModifiers() & cmdKey))
2473 handled_event = true;
2474 } else if(cmd.commandID == kHICommandAbout) {
2475 QMessageBox::aboutQt(0);
2476 HiliteMenu(0);
2477 handled_event = true;
2478 }
2479 }
2480 }
2481 break;
2482 }
2483
2484#ifdef DEBUG_EVENTS
2485 qDebug("%shandled event %c%c%c%c %d", handled_event ? "(*) " : "",
2486 char(eclass >> 24), char((eclass >> 16) & 255), char((eclass >> 8) & 255),
2487 char(eclass & 255), (int)ekind);
2488#endif
2489 if(!handled_event) //let the event go through
2490 return eventNotHandledErr;