1/**************************************************************************** 2** 3** Copyright (C) 2015 The Qt Company Ltd. 4** Contact: http://www.qt.io/licensing/ 5** 6** This file is part of the QtGui module of the Qt Toolkit. 7** 8** $QT_BEGIN_LICENSE:LGPL$ 9** Commercial License Usage 10** Licensees holding valid commercial Qt licenses may use this file in 11** accordance with the commercial license agreement provided with the 12** Software or, alternatively, in accordance with the terms contained in 13** a written agreement between you and The Qt Company. For licensing terms 14** and conditions see http://www.qt.io/terms-conditions. For further 15** information use the contact form at http://www.qt.io/contact-us. 16** 17** GNU Lesser General Public License Usage 18** Alternatively, this file may be used under the terms of the GNU Lesser 19** General Public License version 2.1 or version 3 as published by the Free 20** Software Foundation and appearing in the file LICENSE.LGPLv21 and 21** LICENSE.LGPLv3 included in the packaging of this file. Please review the 22** following information to ensure the GNU Lesser General Public License 23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 25** 26** As a special exception, The Qt Company gives you certain additional 27** rights. These rights are described in The Qt Company LGPL Exception 28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 29** 30** GNU General Public License Usage 31** Alternatively, this file may be used under the terms of the GNU 32** General Public License version 3.0 as published by the Free Software 33** Foundation and appearing in the file LICENSE.GPL included in the 34** packaging of this file. Please review the following information to 35** ensure the GNU General Public License version 3.0 requirements will be 36** met: http://www.gnu.org/copyleft/gpl.html. 37** 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; 168QPointer<QWidget> topLevelAt_cache = 0; 169 170/***************************************************************************** 171 Internal variables and functions 172 *****************************************************************************/ 173static struct { 174 bool use_qt_time_limit; 175 QPointer<QWidget> last_widget; 176 int last_x, last_y; 177 int last_modifiers, last_button; 178 EventTime last_time; 179} qt_mac_dblclick = { false, 0, -1, -1, 0, 0, -2 }; 180 181static bool app_do_modal = false; // modal mode 182extern QWidgetList *qt_modal_stack; // stack of modal widgets 183extern bool qt_tab_all_widgets; // from qapplication.cpp 184bool qt_mac_app_fullscreen = false; 185bool qt_scrollbar_jump_to_pos = false; 186static bool qt_mac_collapse_on_dblclick = true; 187extern int qt_antialiasing_threshold; // from qapplication.cpp 188QWidget * qt_button_down; // widget got last button-down 189QPointer<QWidget> qt_last_mouse_receiver; 190#ifndef QT_MAC_USE_COCOA 191static bool qt_button_down_in_content; // whether the button_down was in the content area. 192static bool qt_mac_previous_press_in_popup_mode = false; 193static bool qt_mac_no_click_through_mode = false; 194static int tablet_button_state = 0; 195#endif 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 *); //qcursor_mac.cpp 220extern bool qt_mac_is_macsheet(const QWidget *); //qwidget_mac.cpp 221extern void qt_mac_command_set_enabled(MenuRef, UInt32, bool); //qmenu_mac.cpp 222extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); // qapplication.cpp 223extern void qt_mac_update_cursor(); // qcursor_mac.mm 224 225// Forward Decls 226void onApplicationWindowChangedActivation( QWidget*widget, bool activated ); 227void onApplicationChangedActivation( bool activated ); 228 229#ifdef QT_MAC_USE_COCOA 230void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader) 231{ 232 // Create qt_menu.nib dir in temp. 233 QDir temp = QDir::temp(); 234 temp.mkdir("qt_menu.nib"); 235 QString nibDir = temp.canonicalPath() + QLatin1String("/") + QLatin1String("qt_menu.nib/"); 236 if (!QDir(nibDir).exists()) { 237 qWarning("qt_mac_loadMenuNib: could not create nib directory in temp"); 238 return; 239 } 240 241 // Copy nib files from resources to temp. 242 QDir nibResource(":/trolltech/mac/qt_menu.nib/"); 243 if (!nibResource.exists()) { 244 qWarning("qt_mac_loadMenuNib: could not load nib from resources"); 245 return; 246 } 247 foreach (const QFileInfo &file, nibResource.entryInfoList()) 248 QFile::copy(file.absoluteFilePath(), nibDir + QLatin1String("/") + file.fileName()); 249 250 // Load and instantiate nib file from temp 251 NSURL *nibUrl = [NSURL fileURLWithPath : const_cast<NSString *>(reinterpret_cast<const NSString *>(QCFString::toCFStringRef(nibDir)))]; 252 NSNib *nib = [[NSNib alloc] initWithContentsOfURL : nibUrl]; 253 [nib autorelease]; 254 if (!nib) { 255 qWarning("qt_mac_loadMenuNib: could not load nib from temp"); 256 return; 257 } 258 bool ok = [nib instantiateNibWithOwner : qtMenuLoader topLevelObjects : nil]; 259 if (!ok) 260 qWarning("qt_mac_loadMenuNib: could not instantiate nib"); 261} 262#endif 263 264static void qt_mac_read_fontsmoothing_settings() 265{ 266 qt_applefontsmoothing_enabled = true; 267 int w = 10, h = 10; 268 QImage image(w, h, QImage::Format_RGB32); 269 image.fill(0xffffffff); 270 QPainter p(&image); 271 p.drawText(0, h, "X\\"); 272 p.end(); 273 274 const int *bits = (const int *) ((const QImage &) image).bits(); 275 int bpl = image.bytesPerLine() / 4; 276 for (int y=0; y<w; ++y) { 277 for (int x=0; x<h; ++x) { 278 int r = qRed(bits[x]); 279 int g = qGreen(bits[x]); 280 int b = qBlue(bits[x]); 281 if (r != g || r != b) { 282 qt_applefontsmoothing_enabled = true; 283 return; 284 } 285 } 286 bits += bpl; 287 } 288 qt_applefontsmoothing_enabled = false; 289} 290 291Q_GUI_EXPORT bool qt_mac_execute_apple_script(const char *script, long script_len, AEDesc *ret) { 292 OSStatus err; 293 AEDesc scriptTextDesc; 294 ComponentInstance theComponent = 0; 295 OSAID scriptID = kOSANullScript, resultID = kOSANullScript; 296 297 // set up locals to a known state 298 AECreateDesc(typeNull, 0, 0, &scriptTextDesc); 299 scriptID = kOSANullScript; 300 resultID = kOSANullScript; 301 302 // open the scripting component 303 theComponent = OpenDefaultComponent(kOSAComponentType, typeAppleScript); 304 if (!theComponent) { 305 err = paramErr; 306 goto bail; 307 } 308 309 // put the script text into an aedesc 310 err = AECreateDesc(typeUTF8Text, script, script_len, &scriptTextDesc); 311 if (err != noErr) 312 goto bail; 313 314 // compile the script 315 err = OSACompile(theComponent, &scriptTextDesc, kOSAModeNull, &scriptID); 316 if (err != noErr) 317 goto bail; 318 319 // run the script 320 err = OSAExecute(theComponent, scriptID, kOSANullScript, kOSAModeNull, &resultID); 321 322 // collect the results - if any 323 if (ret) { 324 AECreateDesc(typeNull, 0, 0, ret); 325 if (err == errOSAScriptError) 326 OSAScriptError(theComponent, kOSAErrorMessage, typeChar, ret); 327 else if (err == noErr && resultID != kOSANullScript) 328 OSADisplay(theComponent, resultID, typeChar, kOSAModeNull, ret); 329 } 330bail: 331 AEDisposeDesc(&scriptTextDesc); 332 if (scriptID != kOSANullScript) 333 OSADispose(theComponent, scriptID); 334 if (resultID != kOSANullScript) 335 OSADispose(theComponent, resultID); 336 if (theComponent) 337 CloseComponent(theComponent); 338 return err == noErr; 339} 340 341Q_GUI_EXPORT bool qt_mac_execute_apple_script(const char *script, AEDesc *ret) 342{ 343 return qt_mac_execute_apple_script(script, qstrlen(script), ret); 344} 345 346Q_GUI_EXPORT bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret) 347{ 348 const QByteArray l = script.toUtf8(); return qt_mac_execute_apple_script(l.constData(), l.size(), ret); 349} 350 351/* Resolution change magic */ 352void qt_mac_display_change_callbk(CGDirectDisplayID, CGDisplayChangeSummaryFlags flags, void *) 353{ 354#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) 355 const bool resized = flags & kCGDisplayDesktopShapeChangedFlag; 356#else 357 Q_UNUSED(flags); 358 const bool resized = true; 359#endif 360 if (resized && qApp) { 361 if (QDesktopWidget *dw = qApp->desktop()) { 362 QResizeEvent *re = new QResizeEvent(dw->size(), dw->size()); 363 QApplication::postEvent(dw, re); 364 QCoreGraphicsPaintEngine::cleanUpMacColorSpaces(); 365 } 366 } 367} 368 369#ifdef DEBUG_PLATFORM_SETTINGS 370static void qt_mac_debug_palette(const QPalette &pal, const QPalette &pal2, const QString &where) 371{ 372 const char *const groups[] = {"Active", "Disabled", "Inactive" }; 373 const char *const roles[] = { "WindowText", "Button", "Light", "Midlight", "Dark", "Mid", 374 "Text", "BrightText", "ButtonText", "Base", "Window", "Shadow", 375 "Highlight", "HighlightedText", "Link", "LinkVisited" }; 376 if (!where.isNull()) 377 qDebug("qt-internal: %s", where.toLatin1().constData()); 378 for(int grp = 0; grp < QPalette::NColorGroups; grp++) { 379 for(int role = 0; role < QPalette::NColorRoles; role++) { 380 QBrush b = pal.brush((QPalette::ColorGroup)grp, (QPalette::ColorRole)role); 381 QPixmap pm = b.texture(); 382 qDebug(" %s::%s %d::%d::%d [%p]%s", groups[grp], roles[role], b.color().red(), 383 b.color().green(), b.color().blue(), pm.isNull() ? 0 : &pm, 384 pal2.brush((QPalette::ColorGroup)grp, (QPalette::ColorRole)role) != b ? " (*)" : ""); 385 } 386 } 387 388} 389#else 390#define qt_mac_debug_palette(x, y, z) 391#endif 392 393//raise a notification 394#ifndef QT_MAC_USE_COCOA 395static NMRec qt_mac_notification = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 396#endif 397void qt_mac_send_notification() 398{ 399#ifndef QT_MAC_USE_COCOA 400 //send it 401 qt_mac_notification.nmMark = 1; //non-zero magic number 402 qt_mac_notification.qType = nmType; 403 NMInstall(&qt_mac_notification); 404#else 405 QMacCocoaAutoReleasePool pool; 406 [[NSApplication sharedApplication] requestUserAttention:NSInformationalRequest]; 407#endif 408} 409 410void qt_mac_cancel_notification() 411{ 412#ifndef QT_MAC_USE_COCOA 413 NMRemove(&qt_mac_notification); 414#else 415 QMacCocoaAutoReleasePool pool; 416 [[NSApplication sharedApplication] cancelUserAttentionRequest:NSInformationalRequest]; 417#endif 418} 419 420#ifndef QT_MAC_USE_COCOA 421//find widget (and part) at a given point 422static short qt_mac_window_at(int x, int y, QWidget **w=0) 423{ 424 Point p; 425 p.h = x; 426 p.v = y; 427 OSWindowRef wp; 428 WindowPartCode wpc; 429 OSStatus err = FindWindowOfClass(&p, kAllWindowClasses, &wp, &wpc); 430 if(err != noErr) { 431 if(w) 432 (*w) = 0; 433 return wpc; 434 } 435 if(w) { 436 if(wp) { 437 *w = qt_mac_find_window(wp); 438#if 0 439 if(!*w) 440 qWarning("QApplication: qt_mac_window_at: Couldn't find %d",(int)wp); 441#endif 442 } else { 443 *w = 0; 444 } 445 } 446 return wpc; 447} 448 449#endif 450 451void qt_mac_set_app_icon(const QPixmap &pixmap) 452{ 453#ifndef QT_MAC_USE_COCOA 454 if(pixmap.isNull()) { 455 RestoreApplicationDockTileImage(); 456 } else { 457 CGImageRef img = (CGImageRef)pixmap.macCGHandle(); 458 SetApplicationDockTileImage(img); 459 CGImageRelease(img); 460 } 461#else 462 QMacCocoaAutoReleasePool pool; 463 NSImage *image = NULL; 464 if (pixmap.isNull()) { 465 // Get Application icon from bundle 466 image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; // released below 467 } else { 468 image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap)); 469 } 470 471 [[NSApplication sharedApplication] setApplicationIconImage:image]; 472 [image release]; 473#endif 474} 475 476Q_GUI_EXPORT void qt_mac_set_press_and_hold_context(bool b) 477{ 478 Q_UNUSED(b); 479 qWarning("qt_mac_set_press_and_hold_context: This functionality is no longer available"); 480} 481 482bool qt_nograb() // application no-grab option 483{ 484#if defined(QT_DEBUG) 485 return appNoGrab; 486#else 487 return false; 488#endif 489} 490 491void qt_mac_update_os_settings() 492{ 493 if (!qApp) 494 return; 495 if (!QApplication::startingUp()) { 496 static bool needToPolish = true; 497 if (needToPolish) { 498 QApplication::style()->polish(qApp); 499 needToPolish = false; 500 } 501 } 502 //focus mode 503 /* First worked as of 10.2.3 */ 504 QSettings appleSettings(QLatin1String("apple.com")); 505 QVariant appleValue = appleSettings.value(QLatin1String("AppleKeyboardUIMode"), 0); 506 qt_tab_all_widgets = (appleValue.toInt() & 0x2); 507 //paging mode 508 /* First worked as of 10.2.3 */ 509 appleValue = appleSettings.value(QLatin1String("AppleScrollerPagingBehavior"), false); 510 qt_scrollbar_jump_to_pos = appleValue.toBool(); 511 //collapse 512 /* First worked as of 10.3.3 */ 513 appleValue = appleSettings.value(QLatin1String("AppleMiniaturizeOnDoubleClick"), true); 514 qt_mac_collapse_on_dblclick = appleValue.toBool(); 515 516 // Anti-aliasing threshold 517 appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold")); 518 if (appleValue.isValid()) 519 qt_antialiasing_threshold = appleValue.toInt(); 520 521#ifdef DEBUG_PLATFORM_SETTINGS 522 qDebug("qt_mac_update_os_settings *********************************************************************"); 523#endif 524 { // setup the global palette 525 QColor qc; 526 (void) QApplication::style(); // trigger creation of application style and system palettes 527 QPalette pal = *QApplicationPrivate::sys_pal; 528 529 pal.setBrush( QPalette::Active, QPalette::Highlight, qcolorForTheme(kThemeBrushPrimaryHighlightColor) ); 530 pal.setBrush( QPalette::Inactive, QPalette::Highlight, qcolorForTheme(kThemeBrushSecondaryHighlightColor) ); 531 532 pal.setBrush( QPalette::Disabled, QPalette::Highlight, qcolorForTheme(kThemeBrushSecondaryHighlightColor) ); 533 pal.setBrush( QPalette::Active, QPalette::Shadow, qcolorForTheme(kThemeBrushButtonActiveDarkShadow) ); 534 535 pal.setBrush( QPalette::Inactive, QPalette::Shadow, qcolorForTheme(kThemeBrushButtonInactiveDarkShadow) ); 536 pal.setBrush( QPalette::Disabled, QPalette::Shadow, qcolorForTheme(kThemeBrushButtonInactiveDarkShadow) ); 537 538 qc = qcolorForThemeTextColor(kThemeTextColorDialogActive); 539 pal.setColor(QPalette::Active, QPalette::Text, qc); 540 pal.setColor(QPalette::Active, QPalette::WindowText, qc); 541 pal.setColor(QPalette::Active, QPalette::HighlightedText, qc); 542 543 qc = qcolorForThemeTextColor(kThemeTextColorDialogInactive); 544 pal.setColor(QPalette::Inactive, QPalette::Text, qc); 545 pal.setColor(QPalette::Inactive, QPalette::WindowText, qc); 546 pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc); 547 pal.setColor(QPalette::Disabled, QPalette::Text, qc); 548 pal.setColor(QPalette::Disabled, QPalette::WindowText, qc); 549 pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc); 550 pal.setBrush(QPalette::ToolTipBase, QColor(255, 255, 199)); 551 552 if (!QApplicationPrivate::sys_pal || *QApplicationPrivate::sys_pal != pal) { 553 QApplicationPrivate::setSystemPalette(pal); 554 QApplication::setPalette(pal); 555 } 556#ifdef DEBUG_PLATFORM_SETTINGS 557 qt_mac_debug_palette(pal, QApplication::palette(), "Global Palette"); 558#endif 559 } 560 561 QFont fnt = qfontForThemeFont(kThemeApplicationFont); 562#ifdef DEBUG_PLATFORM_SETTINGS 563 qDebug("qt-internal: Font for Application [%s::%d::%d::%d]", 564 fnt.family().toLatin1().constData(), fnt.pointSize(), fnt.bold(), fnt.italic()); 565#endif 566 if (!QApplicationPrivate::sys_font || *QApplicationPrivate::sys_font != fnt) 567 QApplicationPrivate::setSystemFont(fnt); 568 569 { //setup the fonts 570 struct FontMap { 571 FontMap(const char *qc, short fk) : qt_class(qc), font_key(fk) { } 572 const char *const qt_class; 573 short font_key; 574 } mac_widget_fonts[] = { 575 FontMap("QPushButton", kThemePushButtonFont), 576 FontMap("QListView", kThemeViewsFont), 577 FontMap("QListBox", kThemeViewsFont), 578 FontMap("QTitleBar", kThemeWindowTitleFont), 579 FontMap("QMenuBar", kThemeMenuTitleFont), 580 FontMap("QMenu", kThemeMenuItemFont), 581 FontMap("QComboMenuItem", kThemeSystemFont), 582 FontMap("QHeaderView", kThemeSmallSystemFont), 583 FontMap("Q3Header", kThemeSmallSystemFont), 584 FontMap("QTipLabel", kThemeSmallSystemFont), 585 FontMap("QLabel", kThemeSystemFont), 586 FontMap("QToolButton", kThemeSmallSystemFont), 587 FontMap("QMenuItem", kThemeMenuItemFont), // It doesn't exist, but its unique. 588 FontMap("QComboLineEdit", kThemeViewsFont), // It doesn't exist, but its unique. 589 FontMap("QSmallFont", kThemeSmallSystemFont), // It doesn't exist, but its unique. 590 FontMap("QMiniFont", kThemeMiniSystemFont), // It doesn't exist, but its unique. 591 FontMap(0, 0) }; 592 for(int i = 0; mac_widget_fonts[i].qt_class; i++) { 593 QFont fnt = qfontForThemeFont(mac_widget_fonts[i].font_key); 594 bool set_font = true; 595 FontHash *hash = qt_app_fonts_hash(); 596 if (!hash->isEmpty()) { 597 FontHash::const_iterator it 598 = hash->constFind(mac_widget_fonts[i].qt_class); 599 if (it != hash->constEnd()) 600 set_font = (fnt != *it); 601 } 602 if (set_font) { 603 QApplication::setFont(fnt, mac_widget_fonts[i].qt_class); 604#ifdef DEBUG_PLATFORM_SETTINGS 605 qDebug("qt-internal: Font for %s [%s::%d::%d::%d]", mac_widget_fonts[i].qt_class, 606 fnt.family().toLatin1().constData(), fnt.pointSize(), fnt.bold(), fnt.italic()); 607#endif 608 } 609 } 610 } 611 QApplicationPrivate::initializeWidgetPaletteHash(); 612#ifdef DEBUG_PLATFORM_SETTINGS 613 qDebug("qt_mac_update_os_settings END !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); 614#endif 615} 616 617void QApplicationPrivate::initializeWidgetPaletteHash() 618{ 619 { //setup the palette 620 struct PaletteMap { 621 inline PaletteMap(const char *qc, ThemeBrush a, ThemeBrush i) : 622 qt_class(qc), active(a), inactive(i) { } 623 const char *const qt_class; 624 ThemeBrush active, inactive; 625 } mac_widget_colors[] = { 626 PaletteMap("QToolButton", kThemeTextColorBevelButtonActive, kThemeTextColorBevelButtonInactive), 627 PaletteMap("QAbstractButton", kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive), 628 PaletteMap("QHeaderView", kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive), 629 PaletteMap("Q3Header", kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive), 630 PaletteMap("QComboBox", kThemeTextColorPopupButtonActive, kThemeTextColorPopupButtonInactive), 631 PaletteMap("QAbstractItemView", kThemeTextColorListView, kThemeTextColorDialogInactive), 632 PaletteMap("QMessageBoxLabel", kThemeTextColorAlertActive, kThemeTextColorAlertInactive), 633 PaletteMap("QTabBar", kThemeTextColorTabFrontActive, kThemeTextColorTabFrontInactive), 634 PaletteMap("QLabel", kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive), 635 PaletteMap("QGroupBox", kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive), 636 PaletteMap("QMenu", kThemeTextColorPopupLabelActive, kThemeTextColorPopupLabelInactive), 637 PaletteMap("QTextEdit", 0, 0), 638 PaletteMap("QTextControl", 0, 0), 639 PaletteMap("QLineEdit", 0, 0), 640 PaletteMap(0, 0, 0) }; 641 QColor qc; 642 for(int i = 0; mac_widget_colors[i].qt_class; i++) { 643 QPalette pal; 644 if (mac_widget_colors[i].active != 0) { 645 qc = qcolorForThemeTextColor(mac_widget_colors[i].active); 646 pal.setColor(QPalette::Active, QPalette::Text, qc); 647 pal.setColor(QPalette::Active, QPalette::WindowText, qc); 648 pal.setColor(QPalette::Active, QPalette::HighlightedText, qc); 649 qc = qcolorForThemeTextColor(mac_widget_colors[i].inactive); 650 pal.setColor(QPalette::Inactive, QPalette::Text, qc); 651 pal.setColor(QPalette::Disabled, QPalette::Text, qc); 652 pal.setColor(QPalette::Inactive, QPalette::WindowText, qc); 653 pal.setColor(QPalette::Disabled, QPalette::WindowText, qc); 654 pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc); 655 pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc); 656 } 657 if (!strcmp(mac_widget_colors[i].qt_class, "QMenu")) { 658 qc = qcolorForThemeTextColor(kThemeTextColorMenuItemActive); 659 pal.setBrush(QPalette::ButtonText, qc); 660 qc = qcolorForThemeTextColor(kThemeTextColorMenuItemSelected); 661 pal.setBrush(QPalette::HighlightedText, qc); 662 qc = qcolorForThemeTextColor(kThemeTextColorMenuItemDisabled); 663 pal.setBrush(QPalette::Disabled, QPalette::Text, qc); 664 } else if (!strcmp(mac_widget_colors[i].qt_class, "QAbstractButton") 665 || !strcmp(mac_widget_colors[i].qt_class, "QHeaderView") 666 || !strcmp(mac_widget_colors[i].qt_class, "Q3Header")) { //special 667 pal.setColor(QPalette::Disabled, QPalette::ButtonText, 668 pal.color(QPalette::Disabled, QPalette::Text)); 669 pal.setColor(QPalette::Inactive, QPalette::ButtonText, 670 pal.color(QPalette::Inactive, QPalette::Text)); 671 pal.setColor(QPalette::Active, QPalette::ButtonText, 672 pal.color(QPalette::Active, QPalette::Text)); 673 } else if (!strcmp(mac_widget_colors[i].qt_class, "QAbstractItemView")) { 674 pal.setBrush(QPalette::Active, QPalette::Highlight, 675 qcolorForTheme(kThemeBrushAlternatePrimaryHighlightColor)); 676 qc = qcolorForThemeTextColor(kThemeTextColorMenuItemSelected); 677 pal.setBrush(QPalette::Active, QPalette::HighlightedText, qc); 678#if 1 679 pal.setBrush(QPalette::Inactive, QPalette::Text, 680 pal.brush(QPalette::Active, QPalette::Text)); 681 pal.setBrush(QPalette::Inactive, QPalette::HighlightedText, 682 pal.brush(QPalette::Active, QPalette::Text)); 683#endif 684 } else if (!strcmp(mac_widget_colors[i].qt_class, "QTextEdit") 685 || !strcmp(mac_widget_colors[i].qt_class, "QTextControl")) { 686 pal.setBrush(QPalette::Inactive, QPalette::Text, 687 pal.brush(QPalette::Active, QPalette::Text)); 688 pal.setBrush(QPalette::Inactive, QPalette::HighlightedText, 689 pal.brush(QPalette::Active, QPalette::Text)); 690 } else if (!strcmp(mac_widget_colors[i].qt_class, "QLineEdit")) { 691 pal.setBrush(QPalette::Disabled, QPalette::Base, 692 pal.brush(QPalette::Active, QPalette::Base)); 693 } 694 695 bool set_palette = true; 696 PaletteHash *phash = qt_app_palettes_hash(); 697 if (!phash->isEmpty()) { 698 PaletteHash::const_iterator it 699 = phash->constFind(mac_widget_colors[i].qt_class); 700 if (it != phash->constEnd()) 701 set_palette = (pal != *it); 702 } 703 if (set_palette) { 704 QApplication::setPalette(pal, mac_widget_colors[i].qt_class); 705#ifdef DEBUG_PLATFORM_SETTINGS 706 qt_mac_debug_palette(pal, QApplication::palette(), QLatin1String("Palette for ") + QString::fromLatin1(mac_widget_colors[i].qt_class)); 707#endif 708 } 709 } 710 } 711} 712 713static void qt_mac_event_release(EventRef &event) 714{ 715 ReleaseEvent(event); 716 event = 0; 717} 718#ifndef QT_MAC_USE_COCOA 719static void qt_mac_event_release(QWidget *w, EventRef &event) 720{ 721 if (event) { 722 QWidget *widget = 0; 723 if (GetEventParameter(event, kEventParamQWidget, typeQWidget, 0, sizeof(widget), 0, &widget) == noErr 724 && w == widget) { 725 if (IsEventInQueue(GetMainEventQueue(), event)) 726 RemoveEventFromQueue(GetMainEventQueue(), event); 727 qt_mac_event_release(event); 728 } 729 } 730} 731 732static bool qt_mac_event_remove(EventRef &event) 733{ 734 if (event) { 735 if (IsEventInQueue(GetMainEventQueue(), event)) 736 RemoveEventFromQueue(GetMainEventQueue(), event); 737 qt_mac_event_release(event); 738 return true; 739 } 740 return false; 741} 742#endif 743 744/* sheets */ 745#ifndef QT_MAC_USE_COCOA 746static EventRef request_showsheet_pending = 0; 747#endif 748void qt_event_request_showsheet(QWidget *w) 749{ 750 Q_ASSERT(qt_mac_is_macsheet(w)); 751#ifdef QT_MAC_USE_COCOA 752 w->repaint(); 753 [[NSApplication sharedApplication] beginSheet:qt_mac_window_for(w) modalForWindow:qt_mac_window_for(w->parentWidget()) 754 modalDelegate:nil didEndSelector:nil contextInfo:0]; 755#else 756 qt_mac_event_remove(request_showsheet_pending); 757 CreateEvent(0, kEventClassQt, kEventQtRequestShowSheet, GetCurrentEventTime(), 758 kEventAttributeUserEvent, &request_showsheet_pending); 759 SetEventParameter(request_showsheet_pending, kEventParamQWidget, typeQWidget, sizeof(w), &w); 760 PostEventToQueue(GetMainEventQueue(), request_showsheet_pending, kEventPriorityStandard); 761#endif 762} 763 764static void qt_post_window_change_event(QWidget *widget) 765{ 766 qt_widget_private(widget)->needWindowChange = true; 767 QEvent *glWindowChangeEvent = new QEvent(QEvent::MacGLWindowChange); 768 QApplication::postEvent(widget, glWindowChangeEvent); 769} 770 771/* 772 Posts updates to all child and grandchild OpenGL widgets for the given widget. 773*/ 774static void qt_mac_update_child_gl_widgets(QWidget *widget) 775{ 776 // Update all OpenGL child widgets for the given widget. 777 QList<QWidgetPrivate::GlWidgetInfo> &glWidgets = qt_widget_private(widget)->glWidgets; 778 QList<QWidgetPrivate::GlWidgetInfo>::iterator end = glWidgets.end(); 779 QList<QWidgetPrivate::GlWidgetInfo>::iterator it = glWidgets.begin(); 780 781 for (;it != end; ++it) { 782 qt_post_window_change_event(it->widget); 783 } 784} 785 786/* 787 Sends updates to all child and grandchild gl widgets that have updates pending. 788*/ 789void qt_mac_send_posted_gl_updates(QWidget *widget) 790{ 791 QList<QWidgetPrivate::GlWidgetInfo> &glWidgets = qt_widget_private(widget)->glWidgets; 792 QList<QWidgetPrivate::GlWidgetInfo>::iterator end = glWidgets.end(); 793 QList<QWidgetPrivate::GlWidgetInfo>::iterator it = glWidgets.begin(); 794 795 for (;it != end; ++it) { 796 QWidget *glWidget = it->widget; 797 if (qt_widget_private(glWidget)->needWindowChange) { 798 QEvent glChangeEvent(QEvent::MacGLWindowChange); 799 QApplication::sendEvent(glWidget, &glChangeEvent); 800 } 801 } 802} 803 804/* 805 Posts updates to all OpenGL widgets within the window that the given widget intersects. 806*/ 807static void qt_mac_update_intersected_gl_widgets(QWidget *widget) 808{ 809#ifndef QT_MAC_USE_COCOA 810 QList<QWidgetPrivate::GlWidgetInfo> &glWidgets = qt_widget_private(widget->window())->glWidgets; 811 if (glWidgets.isEmpty()) 812 return; 813 814 // Exit if the window has not been created yet (mapToGlobal/size will force create it) 815 if (widget->testAttribute(Qt::WA_WState_Created) == false || HIViewGetWindow(qt_mac_nativeview_for(widget)) == 0) 816 return; 817 818 const QRect globalWidgetRect = QRect(widget->mapToGlobal(QPoint(0, 0)), widget->size()); 819 820 QList<QWidgetPrivate::GlWidgetInfo>::iterator end = glWidgets.end(); 821 QList<QWidgetPrivate::GlWidgetInfo>::iterator it = glWidgets.begin(); 822 823 for (;it != end; ++it){ 824 QWidget *glWidget = it->widget; 825 const QRect globalGlWidgetRect = QRect(glWidget->mapToGlobal(QPoint(0, 0)), glWidget->size()); 826 if (globalWidgetRect.intersects(globalGlWidgetRect)) { 827 qt_post_window_change_event(glWidget); 828 it->lastUpdateWidget = widget; 829 } else if (it->lastUpdateWidget == widget) { 830 // Update the gl wigets that the widget intersected the last time around, 831 // and that we are not intersecting now. This prevents paint errors when the 832 // intersecting widget leaves a gl widget. 833 qt_post_window_change_event(glWidget); 834 it->lastUpdateWidget = 0; 835 } 836 } 837#else 838 Q_UNUSED(widget); 839#endif 840} 841 842/* 843 Posts a kEventQtRequestWindowChange event to the main Carbon event queue. 844*/ 845static EventRef request_window_change_pending = 0; 846Q_GUI_EXPORT void qt_event_request_window_change() 847{ 848 if(request_window_change_pending) 849 return; 850 851 CreateEvent(0, kEventClassQt, kEventQtRequestWindowChange, GetCurrentEventTime(), 852 kEventAttributeUserEvent, &request_window_change_pending); 853 PostEventToQueue(GetMainEventQueue(), request_window_change_pending, kEventPriorityHigh); 854} 855 856/* window changing. This is a hack around Apple's missing functionality, pending the toolbox 857 team fix. --Sam */ 858Q_GUI_EXPORT void qt_event_request_window_change(QWidget *widget) 859{ 860 if (!widget) 861 return; 862 863 // Post a kEventQtRequestWindowChange event. This event is semi-public, 864 // don't remove this line! 865 qt_event_request_window_change(); 866 867 // Post update request on gl widgets unconditionally. 868 if (qt_widget_private(widget)->isGLWidget == true) { 869 qt_post_window_change_event(widget); 870 return; 871 } 872 873 qt_mac_update_child_gl_widgets(widget); 874 qt_mac_update_intersected_gl_widgets(widget); 875} 876 877/* activation */ 878static struct { 879 QPointer<QWidget> widget; 880 EventRef event; 881 EventLoopTimerRef timer; 882 EventLoopTimerUPP timerUPP; 883} request_activate_pending = { 0, 0, 0, 0 }; 884bool qt_event_remove_activate() 885{ 886 if (request_activate_pending.timer) { 887 RemoveEventLoopTimer(request_activate_pending.timer); 888 request_activate_pending.timer = 0; 889 } 890 if (request_activate_pending.event) 891 qt_mac_event_release(request_activate_pending.event); 892 return true; 893} 894 895void qt_event_activate_timer_callbk(EventLoopTimerRef r, void *) 896{ 897 EventLoopTimerRef otc = request_activate_pending.timer; 898 qt_event_remove_activate(); 899 if (r == otc && !request_activate_pending.widget.isNull()) { 900 const QWidget *tlw = request_activate_pending.widget->window(); 901 Qt::WindowType wt = tlw->windowType(); 902 if (tlw->isVisible() 903 && ((wt != Qt::Desktop && wt != Qt::Popup && wt != Qt::Tool) || tlw->isModal())) { 904 CreateEvent(0, kEventClassQt, kEventQtRequestActivate, GetCurrentEventTime(), 905 kEventAttributeUserEvent, &request_activate_pending.event); 906 PostEventToQueue(GetMainEventQueue(), request_activate_pending.event, kEventPriorityHigh); 907 } 908 } 909} 910 911void qt_event_request_activate(QWidget *w) 912{ 913 if (w == request_activate_pending.widget) 914 return; 915 916 /* We put these into a timer because due to order of events being sent we need to be sure this 917 comes from inside of the event loop */ 918 qt_event_remove_activate(); 919 if (!request_activate_pending.timerUPP) 920 request_activate_pending.timerUPP = NewEventLoopTimerUPP(qt_event_activate_timer_callbk); 921 request_activate_pending.widget = w; 922 InstallEventLoopTimer(GetMainEventLoop(), 0, 0, request_activate_pending.timerUPP, 0, &request_activate_pending.timer); 923} 924 925 926/* menubars */ 927#ifndef QT_MAC_USE_COCOA 928static EventRef request_menubarupdate_pending = 0; 929#endif 930void qt_event_request_menubarupdate() 931{ 932#ifndef QT_MAC_USE_COCOA 933 if (request_menubarupdate_pending) { 934 if (IsEventInQueue(GetMainEventQueue(), request_menubarupdate_pending)) 935 return; 936#ifdef DEBUG_DROPPED_EVENTS 937 qDebug("%s:%d Whoa, we dropped an event on the floor!", __FILE__, __LINE__); 938#endif 939 } 940 941 CreateEvent(0, kEventClassQt, kEventQtRequestMenubarUpdate, GetCurrentEventTime(), 942 kEventAttributeUserEvent, &request_menubarupdate_pending); 943 PostEventToQueue(GetMainEventQueue(), request_menubarupdate_pending, kEventPriorityHigh); 944#else 945 // Just call this. The request has the benefit that we don't call this multiple times, but 946 // we can optimize this. 947 QMenuBar::macUpdateMenuBar(); 948#endif 949} 950 951#ifndef QT_MAC_USE_COCOA 952//context menu 953static EventRef request_context_pending = 0; 954static void qt_event_request_context(QWidget *w=0, EventRef *where=0) 955{ 956 if (!where) 957 where = &request_context_pending; 958 if (*where) 959 return; 960 CreateEvent(0, kEventClassQt, kEventQtRequestContext, GetCurrentEventTime(), 961 kEventAttributeUserEvent, where); 962 if (w) 963 SetEventParameter(*where, kEventParamQWidget, typeQWidget, sizeof(w), &w); 964 PostEventToQueue(GetMainEventQueue(), *where, kEventPriorityStandard); 965} 966#endif 967 968void QApplicationPrivate::createEventDispatcher() 969{ 970 Q_Q(QApplication); 971 if (q->type() != QApplication::Tty) 972 eventDispatcher = new QEventDispatcherMac(q); 973 else 974 eventDispatcher = new QEventDispatcherUNIX(q); 975} 976 977/* clipboard */ 978void qt_event_send_clipboard_changed() 979{ 980#ifndef QT_MAC_USE_COCOA 981 AppleEvent ae; 982 if (AECreateAppleEvent(kEventClassQt, typeAEClipboardChanged, 0, kAutoGenerateReturnID, kAnyTransactionID, &ae) != noErr) 983 qDebug("Can't happen!!"); 984 AppleEvent reply; 985 AESend(&ae, &reply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, 0, 0); 986#endif 987} 988 989/* app menu */ 990static QMenu *qt_mac_dock_menu = 0; 991Q_GUI_EXPORT void qt_mac_set_dock_menu(QMenu *menu) 992{ 993 qt_mac_dock_menu = menu; 994#ifdef QT_MAC_USE_COCOA 995 [[NSApplication sharedApplication] setDockMenu:menu->macMenu()]; 996#else 997 SetApplicationDockTileMenu(menu->macMenu()); 998#endif 999} 1000 1001/* events that hold pointers to widgets, must be cleaned up like this */ 1002void qt_mac_event_release(QWidget *w) 1003{ 1004 if (w) { 1005#ifndef QT_MAC_USE_COCOA 1006 qt_mac_event_release(w, request_showsheet_pending); 1007 qt_mac_event_release(w, request_context_pending); 1008#endif 1009 if (w == qt_mac_dock_menu) { 1010 qt_mac_dock_menu = 0; 1011#ifndef QT_MAC_USE_COCOA 1012 SetApplicationDockTileMenu(0); 1013#else 1014 [[NSApplication sharedApplication] setDockMenu:0]; 1015#endif 1016 } 1017 } 1018} 1019 1020struct QMacAppleEventTypeSpec { 1021 AEEventClass mac_class; 1022 AEEventID mac_id; 1023} app_apple_events[] = { 1024 { kCoreEventClass, kAEQuitApplication }, 1025 { kCoreEventClass, kAEOpenDocuments }, 1026 { kInternetEventClass, kAEGetURL }, 1027}; 1028 1029#ifndef QT_MAC_USE_COCOA 1030 1031#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) 1032enum 1033{ 1034 kEventMouseScroll = 11, 1035 kEventParamMouseWheelSmoothVerticalDelta = 'saxy', 1036 kEventParamMouseWheelSmoothHorizontalDelta = 'saxx', 1037}; 1038#endif 1039 1040/* watched events */ 1041static EventTypeSpec app_events[] = { 1042 { kEventClassQt, kEventQtRequestWindowChange }, 1043 { kEventClassQt, kEventQtRequestShowSheet }, 1044 { kEventClassQt, kEventQtRequestContext }, 1045 { kEventClassQt, kEventQtRequestActivate }, 1046 { kEventClassQt, kEventQtRequestMenubarUpdate }, 1047 1048 { kEventClassWindow, kEventWindowActivated }, 1049 { kEventClassWindow, kEventWindowDeactivated }, 1050 1051 { kEventClassMouse, kEventMouseScroll }, 1052 { kEventClassMouse, kEventMouseWheelMoved }, 1053 { kEventClassMouse, kEventMouseDown }, 1054 { kEventClassMouse, kEventMouseUp }, 1055 { kEventClassMouse, kEventMouseDragged }, 1056 { kEventClassMouse, kEventMouseMoved }, 1057 1058 { kEventClassTablet, kEventTabletProximity }, 1059 1060 { kEventClassApplication, kEventAppActivated }, 1061 { kEventClassApplication, kEventAppDeactivated }, 1062 { kEventClassApplication, kEventAppAvailableWindowBoundsChanged }, 1063 1064 // { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, 1065 { kEventClassKeyboard, kEventRawKeyModifiersChanged }, 1066 { kEventClassKeyboard, kEventRawKeyRepeat }, 1067 { kEventClassKeyboard, kEventRawKeyUp }, 1068 { kEventClassKeyboard, kEventRawKeyDown }, 1069 1070 { kEventClassCommand, kEventCommandProcess }, 1071 1072 { kEventClassAppleEvent, kEventAppleEvent }, 1073 1074 { kAppearanceEventClass, kAEAppearanceChanged } 1075}; 1076 1077void qt_init_app_proc_handler() 1078{ 1079 InstallEventHandler(GetApplicationEventTarget(), app_proc_handlerUPP, 1080 GetEventTypeCount(app_events), app_events, (void *)qApp, 1081 &app_proc_handler); 1082} 1083#endif // QT_MAC_USE_COCOA 1084 1085static void qt_init_tablet_proximity_handler() 1086{ 1087 EventTypeSpec tabletProximityEvent = { kEventClassTablet, kEventTabletProximity }; 1088 InstallEventHandler(GetEventMonitorTarget(), tablet_proximity_UPP, 1089 1, &tabletProximityEvent, qApp, &tablet_proximity_handler); 1090} 1091 1092static void qt_release_tablet_proximity_handler() 1093{ 1094 RemoveEventHandler(tablet_proximity_handler); 1095} 1096 1097QString QApplicationPrivate::appName() const 1098{ 1099 static QString applName; 1100 if (applName.isEmpty()) { 1101 applName = QCoreApplicationPrivate::macMenuBarName(); 1102 ProcessSerialNumber psn; 1103 if (applName.isEmpty() && qt_is_gui_used && GetCurrentProcess(&psn) == noErr) { 1104 QCFString cfstr; 1105 CopyProcessName(&psn, &cfstr); 1106 applName = cfstr; 1107 } 1108 } 1109 return applName; 1110} 1111 1112void qt_release_app_proc_handler() 1113{ 1114#ifndef QT_MAC_USE_COCOA 1115 if (app_proc_handler) { 1116 RemoveEventHandler(app_proc_handler); 1117 app_proc_handler = 0; 1118 } 1119#endif 1120} 1121 1122void qt_color_profile_changed(CFNotificationCenterRef, void *, CFStringRef, const void *, 1123 CFDictionaryRef) 1124{ 1125 QCoreGraphicsPaintEngine::cleanUpMacColorSpaces(); 1126} 1127/* platform specific implementations */ 1128void qt_init(QApplicationPrivate *priv, int) 1129{ 1130 if (qt_is_gui_used) { 1131 CGDisplayRegisterReconfigurationCallback(qt_mac_display_change_callbk, 0); 1132 CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); 1133 CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed, 1134 kCMDeviceUnregisteredNotification, 0, 1135 CFNotificationSuspensionBehaviorDeliverImmediately); 1136 CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed, 1137 kCMDefaultDeviceNotification, 0, 1138 CFNotificationSuspensionBehaviorDeliverImmediately); 1139 CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed, 1140 kCMDeviceProfilesNotification, 0, 1141 CFNotificationSuspensionBehaviorDeliverImmediately); 1142 CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed, 1143 kCMDefaultDeviceProfileNotification, 0, 1144 CFNotificationSuspensionBehaviorDeliverImmediately); 1145 ProcessSerialNumber psn; 1146 if (GetCurrentProcess(&psn) == noErr) { 1147 // Jambi needs to transform itself since most people aren't "used" 1148 // to putting things in bundles, but other people may actually not 1149 // want to tranform the process (running as a helper or something) 1150 // so don't do that for them. This means checking both LSUIElement 1151 // and LSBackgroundOnly. If you set them both... well, you 1152 // shouldn't do that. 1153 1154 bool forceTransform = true; 1155 CFTypeRef value = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), 1156 CFSTR("LSUIElement")); 1157 if (value) { 1158 CFTypeID valueType = CFGetTypeID(value); 1159 // Officially it's supposed to be a string, a boolean makes sense, so we'll check. 1160 // A number less so, but OK. 1161 if (valueType == CFStringGetTypeID()) 1162 forceTransform = !(QCFString::toQString(static_cast<CFStringRef>(value)).toInt()); 1163 else if (valueType == CFBooleanGetTypeID()) 1164 forceTransform = !CFBooleanGetValue(static_cast<CFBooleanRef>(value)); 1165 else if (valueType == CFNumberGetTypeID()) { 1166 int valueAsInt; 1167 CFNumberGetValue(static_cast<CFNumberRef>(value), kCFNumberIntType, &valueAsInt); 1168 forceTransform = !valueAsInt; 1169 } 1170 } 1171 1172 if (forceTransform) { 1173 value = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), 1174 CFSTR("LSBackgroundOnly")); 1175 if (value) { 1176 CFTypeID valueType = CFGetTypeID(value); 1177 if (valueType == CFBooleanGetTypeID()) 1178 forceTransform = !CFBooleanGetValue(static_cast<CFBooleanRef>(value)); 1179 else if (valueType == CFStringGetTypeID()) 1180 forceTransform = !(QCFString::toQString(static_cast<CFStringRef>(value)).toInt()); 1181 else if (valueType == CFNumberGetTypeID()) { 1182 int valueAsInt; 1183 CFNumberGetValue(static_cast<CFNumberRef>(value), kCFNumberIntType, &valueAsInt); 1184 forceTransform = !valueAsInt; 1185 } 1186 } 1187 } 1188 1189 1190 if (forceTransform) { 1191 TransformProcessType(&psn, kProcessTransformToForegroundApplication); 1192 } 1193 } 1194 } 1195 1196 char **argv = priv->argv; 1197 1198 // Get command line params 1199 if (int argc = priv->argc) { 1200 int i, j = 1; 1201 QString passed_psn; 1202 for(i=1; i < argc; i++) { 1203 if (argv[i] && *argv[i] != '-') { 1204 argv[j++] = argv[i]; 1205 continue; 1206 } 1207 QByteArray arg(argv[i]); 1208#if defined(QT_DEBUG) 1209 if (arg == "-nograb") 1210 appNoGrab = !appNoGrab; 1211 else 1212#endif // QT_DEBUG 1213 if (arg.left(5) == "-psn_") { 1214 passed_psn = QString::fromLatin1(arg.mid(6)); 1215 } else { 1216 argv[j++] = argv[i]; 1217 } 1218 } 1219 if (j < priv->argc) { 1220 priv->argv[j] = 0; 1221 priv->argc = j; 1222 } 1223 1224 //special hack to change working directory (for an app bundle) when running from finder 1225 if (!passed_psn.isNull() && QDir::currentPath() == QLatin1String("/")) { 1226 QCFType<CFURLRef> bundleURL(CFBundleCopyBundleURL(CFBundleGetMainBundle())); 1227 QString qbundlePath = QCFString(CFURLCopyFileSystemPath(bundleURL, 1228 kCFURLPOSIXPathStyle)); 1229 if (qbundlePath.endsWith(QLatin1String(".app"))) 1230 QDir::setCurrent(qbundlePath.section(QLatin1Char('/'), 0, -2)); 1231 } 1232 } 1233 1234 QMacPasteboardMime::initialize(); 1235 1236 qApp->setObjectName(priv->appName()); 1237 if (qt_is_gui_used) { 1238 QColormap::initialize(); 1239 QFont::initialize(); 1240 QCursorData::initialize(); 1241 QCoreGraphicsPaintEngine::initialize(); 1242#ifndef QT_NO_ACCESSIBILITY 1243 QAccessible::initialize(); 1244#endif 1245#ifndef QT_NO_IM 1246 QMacInputContext::initialize(); 1247 QApplicationPrivate::inputContext = new QMacInputContext; 1248#endif 1249 if (QApplication::desktopSettingsAware()) 1250 qt_mac_update_os_settings(); 1251#ifndef QT_MAC_USE_COCOA 1252 if (!app_proc_handler) { 1253 app_proc_handlerUPP = NewEventHandlerUPP(QApplicationPrivate::globalEventProcessor); 1254 qt_init_app_proc_handler(); 1255 } 1256 1257#endif 1258 if (!app_proc_ae_handlerUPP && !QApplication::testAttribute(Qt::AA_MacPluginApplication)) { 1259 app_proc_ae_handlerUPP = AEEventHandlerUPP(QApplicationPrivate::globalAppleEventProcessor); 1260 for(uint i = 0; i < sizeof(app_apple_events) / sizeof(QMacAppleEventTypeSpec); ++i) { 1261 // Install apple event handler, but avoid overwriting an already 1262 // existing handler (it means a 3rd party application has installed one): 1263 SRefCon refCon = 0; 1264 AEEventHandlerUPP current_handler = NULL; 1265 AEGetEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id, ¤t_handler, &refCon, false); 1266 if (!current_handler) 1267 AEInstallEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id, 1268 app_proc_ae_handlerUPP, SRefCon(qApp), false); 1269 } 1270 } 1271 1272 if (QApplicationPrivate::app_style) { 1273 QEvent ev(QEvent::Style); 1274 qt_sendSpontaneousEvent(QApplicationPrivate::app_style, &ev); 1275 } 1276 } 1277 if (QApplication::desktopSettingsAware()) 1278 QApplicationPrivate::qt_mac_apply_settings(); 1279 1280 // Cocoa application delegate 1281#ifdef QT_MAC_USE_COCOA 1282 NSApplication *cocoaApp = [QT_MANGLE_NAMESPACE(QNSApplication) sharedApplication]; 1283 qt_redirectNSApplicationSendEvent(); 1284 1285 QMacCocoaAutoReleasePool pool; 1286 id oldDelegate = [cocoaApp delegate]; 1287 QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; 1288 Q_ASSERT(newDelegate); 1289 [newDelegate setQtPrivate:priv]; 1290 // Only do things that make sense to do once, otherwise we crash. 1291 if (oldDelegate != newDelegate && !QApplication::testAttribute(Qt::AA_MacPluginApplication)) { 1292 [newDelegate setReflectionDelegate:oldDelegate]; 1293 [cocoaApp setDelegate:newDelegate]; 1294 1295 QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader = [[QT_MANGLE_NAMESPACE(QCocoaMenuLoader) alloc] init]; 1296 qt_mac_loadMenuNib(qtMenuLoader); 1297 1298 [cocoaApp setMenu:[qtMenuLoader menu]]; 1299 [newDelegate setMenuLoader:qtMenuLoader]; 1300 } 1301#endif 1302 // Register for Carbon tablet proximity events on the event monitor target. 1303 // This means that we should receive proximity events even when we aren't the active application. 1304 if (!tablet_proximity_handler) { 1305 tablet_proximity_UPP = NewEventHandlerUPP(QApplicationPrivate::tabletProximityCallback); 1306 qt_init_tablet_proximity_handler(); 1307 } 1308 priv->native_modal_dialog_active = false; 1309 1310 qt_mac_read_fontsmoothing_settings(); 1311} 1312 1313void qt_release_apple_event_handler() 1314{ 1315 if(app_proc_ae_handlerUPP) { 1316 for(uint i = 0; i < sizeof(app_apple_events) / sizeof(QMacAppleEventTypeSpec); ++i) 1317 AERemoveEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id, 1318 app_proc_ae_handlerUPP, true); 1319 DisposeAEEventHandlerUPP(app_proc_ae_handlerUPP); 1320 app_proc_ae_handlerUPP = 0; 1321 } 1322} 1323 1324/***************************************************************************** 1325 qt_cleanup() - cleans up when the application is finished 1326 *****************************************************************************/ 1327 1328void qt_cleanup() 1329{ 1330 CGDisplayRemoveReconfigurationCallback(qt_mac_display_change_callbk, 0); 1331 CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); 1332 CFNotificationCenterRemoveObserver(center, qApp, kCMDeviceUnregisteredNotification, 0); 1333 CFNotificationCenterRemoveObserver(center, qApp, kCMDefaultDeviceNotification, 0); 1334 CFNotificationCenterRemoveObserver(center, qApp, kCMDeviceProfilesNotification, 0); 1335 CFNotificationCenterRemoveObserver(center, qApp, kCMDefaultDeviceProfileNotification, 0); 1336 1337#ifndef QT_MAC_USE_COCOA 1338 qt_release_app_proc_handler(); 1339 if (app_proc_handlerUPP) { 1340 DisposeEventHandlerUPP(app_proc_handlerUPP); 1341 app_proc_handlerUPP = 0; 1342 } 1343#endif 1344 qt_release_apple_event_handler(); 1345 1346#ifdef QT_MAC_USE_COCOA 1347 qt_resetNSApplicationSendEvent(); 1348#endif 1349 1350 qt_release_tablet_proximity_handler(); 1351 if (tablet_proximity_UPP) 1352 DisposeEventHandlerUPP(tablet_proximity_UPP); 1353 1354 QPixmapCache::clear(); 1355 if (qt_is_gui_used) { 1356#ifndef QT_NO_ACCESSIBILITY 1357 QAccessible::cleanup(); 1358#endif 1359#ifndef QT_NO_IM 1360 QMacInputContext::cleanup(); 1361#endif 1362 QCursorData::cleanup(); 1363 QFont::cleanup(); 1364 QColormap::cleanup(); 1365 if (qt_mac_safe_pdev) { 1366 delete qt_mac_safe_pdev; 1367 qt_mac_safe_pdev = 0; 1368 } 1369 extern void qt_mac_unregister_widget(); // qapplication_mac.cpp 1370 qt_mac_unregister_widget(); 1371 } 1372} 1373 1374/***************************************************************************** 1375 Platform specific global and internal functions 1376 *****************************************************************************/ 1377void qt_updated_rootinfo() 1378{ 1379} 1380 1381bool qt_wstate_iconified(WId) 1382{ 1383 return false; 1384} 1385 1386/***************************************************************************** 1387 Platform specific QApplication members 1388 *****************************************************************************/ 1389extern QWidget * mac_mouse_grabber; 1390extern QWidget * mac_keyboard_grabber; 1391 1392#ifdef QT3_SUPPORT 1393void QApplication::setMainWidget(QWidget *mainWidget) 1394{ 1395 QApplicationPrivate::main_widget = mainWidget; 1396 if (QApplicationPrivate::main_widget && windowIcon().isNull() 1397 && QApplicationPrivate::main_widget->testAttribute(Qt::WA_SetWindowIcon)) 1398 setWindowIcon(QApplicationPrivate::main_widget->windowIcon()); 1399} 1400#endif 1401#ifndef QT_NO_CURSOR 1402 1403/***************************************************************************** 1404 QApplication cursor stack 1405 *****************************************************************************/ 1406 1407void QApplication::setOverrideCursor(const QCursor &cursor) 1408{ 1409 qApp->d_func()->cursor_list.prepend(cursor); 1410 1411#ifdef QT_MAC_USE_COCOA 1412 qt_mac_update_cursor(); 1413#else 1414 if (qApp && qApp->activeWindow()) 1415 qt_mac_set_cursor(&qApp->d_func()->cursor_list.first()); 1416#endif 1417} 1418 1419void QApplication::restoreOverrideCursor() 1420{ 1421 if (qApp->d_func()->cursor_list.isEmpty()) 1422 return; 1423 qApp->d_func()->cursor_list.removeFirst(); 1424 1425#ifdef QT_MAC_USE_COCOA 1426 qt_mac_update_cursor(); 1427#else 1428 if (qApp && qApp->activeWindow()) { 1429 const QCursor def(Qt::ArrowCursor); 1430 qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first()); 1431 } 1432#endif 1433} 1434#endif // QT_NO_CURSOR 1435 1436Qt::KeyboardModifiers QApplication::queryKeyboardModifiers() 1437{ 1438 return qt_mac_get_modifiers(GetCurrentEventKeyModifiers()); 1439} 1440 1441QWidget *QApplication::topLevelAt(const QPoint &p) 1442{ 1443#ifndef QT_MAC_USE_COCOA 1444 QWidget *widget; 1445 qt_mac_window_at(p.x(), p.y(), &widget); 1446 return widget; 1447#else 1448 // Use a cache to avoid iterate through the whole list of windows for all 1449 // calls to to topLevelAt. We e.g. do this for each and every mouse 1450 // move since we need to find the widget under mouse: 1451 if (topLevelAt_cache && topLevelAt_cache->frameGeometry().contains(p)) 1452 return topLevelAt_cache; 1453 1454 // INVARIANT: Cache miss. Go through the list if windows instead: 1455 QMacCocoaAutoReleasePool pool; 1456 NSPoint cocoaPoint = flipPoint(p); 1457 NSInteger windowCount; 1458 NSCountWindows(&windowCount); 1459 if (windowCount <= 0) 1460 return 0; // There's no window to find! 1461 1462 QVarLengthArray<NSInteger> windowList(windowCount); 1463 NSWindowList(windowCount, windowList.data()); 1464 int firstQtWindowFound = -1; 1465 for (int i = 0; i < windowCount; ++i) { 1466 NSWindow *window = [[NSApplication sharedApplication] windowWithWindowNumber:windowList[i]]; 1467 if (window) { 1468 QWidget *candidateWindow = [window QT_MANGLE_NAMESPACE(qt_qwidget)]; 1469 if (candidateWindow && firstQtWindowFound == -1) 1470 firstQtWindowFound = i; 1471 1472 if (NSPointInRect(cocoaPoint, [window frame])) { 1473 // Check to see if there's a hole in the window where the mask is. 1474 // If there is, we should just continue to see if there is a window below. 1475 if (candidateWindow && !candidateWindow->mask().isEmpty()) { 1476 QPoint localPoint = candidateWindow->mapFromGlobal(p); 1477 if (!candidateWindow->mask().contains(localPoint)) 1478 continue; 1479 else 1480 return candidateWindow; 1481 } else { 1482 if (i == firstQtWindowFound) { 1483 // The cache will only work when the window under mouse is 1484 // top most (that is, not partially obscured by other windows. 1485 // And we only set it if no mask is present to optimize for the common case: 1486 topLevelAt_cache = candidateWindow; 1487 } 1488 return candidateWindow; 1489 } 1490 } 1491 } 1492 } 1493 1494 topLevelAt_cache = 0; 1495 return 0; 1496#endif 1497} 1498 1499/***************************************************************************** 1500 Main event loop 1501 *****************************************************************************/ 1502 1503bool QApplicationPrivate::modalState() 1504{ 1505 return app_do_modal; 1506} 1507 1508#ifdef QT_MAC_USE_COCOA 1509#endif 1510 1511void QApplicationPrivate::enterModal_sys(QWidget *widget) 1512{ 1513#ifdef DEBUG_MODAL_EVENTS 1514 Q_ASSERT(widget); 1515 qDebug("Entering modal state with %s::%s::%p (%d)", widget->metaObject()->className(), widget->objectName().toLocal8Bit().constData(), 1516 widget, qt_modal_stack ? (int)qt_modal_stack->count() : -1); 1517#endif 1518 if (!qt_modal_stack) 1519 qt_modal_stack = new QWidgetList; 1520 1521 dispatchEnterLeave(0, qt_last_mouse_receiver); 1522 qt_last_mouse_receiver = 0; 1523 1524 qt_modal_stack->insert(0, widget); 1525 if (!app_do_modal) 1526 qt_event_request_menubarupdate(); 1527 app_do_modal = true; 1528 qt_button_down = 0; 1529 1530#ifdef QT_MAC_USE_COCOA 1531 if (!qt_mac_is_macsheet(widget)) 1532 QEventDispatcherMacPrivate::beginModalSession(widget); 1533#endif 1534} 1535 1536void QApplicationPrivate::leaveModal_sys(QWidget *widget) 1537{ 1538 if (qt_modal_stack && qt_modal_stack->removeAll(widget)) { 1539#ifdef DEBUG_MODAL_EVENTS 1540 qDebug("Leaving modal state with %s::%s::%p (%d)", widget->metaObject()->className(), widget->objectName().toLocal8Bit().constData(), 1541 widget, qt_modal_stack->count()); 1542#endif 1543 if (qt_modal_stack->isEmpty()) { 1544 delete qt_modal_stack; 1545 qt_modal_stack = 0; 1546 QPoint p(QCursor::pos()); 1547 app_do_modal = false; 1548 QWidget* w = 0; 1549 if (QWidget *grabber = QWidget::mouseGrabber()) 1550 w = grabber; 1551 else 1552 w = QApplication::widgetAt(p.x(), p.y()); 1553 dispatchEnterLeave(w, qt_last_mouse_receiver); // send synthetic enter event 1554 qt_last_mouse_receiver = w; 1555 } 1556#ifdef QT_MAC_USE_COCOA 1557 if (!qt_mac_is_macsheet(widget)) 1558 QEventDispatcherMacPrivate::endModalSession(widget); 1559#endif 1560 } 1561#ifdef DEBUG_MODAL_EVENTS 1562 else qDebug("Failure to remove %s::%s::%p -- %p", widget->metaObject()->className(), widget->objectName().toLocal8Bit().constData(), widget, qt_modal_stack); 1563#endif 1564 app_do_modal = (qt_modal_stack != 0); 1565 if (!app_do_modal) 1566 qt_event_request_menubarupdate(); 1567} 1568 1569QWidget *QApplicationPrivate::tryModalHelper_sys(QWidget *top) 1570{ 1571#ifndef QT_MAC_USE_COCOA 1572 if(top && qt_mac_is_macsheet(top) && !IsWindowVisible(qt_mac_window_for(top))) { 1573 if(OSWindowRef wp = GetFrontWindowOfClass(kSheetWindowClass, true)) { 1574 if(QWidget *sheet = qt_mac_find_window(wp)) 1575 top = sheet; 1576 } 1577 } 1578#endif 1579 return top; 1580} 1581 1582#ifndef QT_MAC_USE_COCOA 1583static bool qt_try_modal(QWidget *widget, EventRef event) 1584{ 1585 QWidget * top = 0; 1586 1587 if (QApplicationPrivate::tryModalHelper(widget, &top)) 1588 return true; 1589 1590 // INVARIANT: widget is modally shaddowed within its 1591 // window, and should therefore not handle the event. 1592 // However, if the window is not active, the event 1593 // might suggest that we should bring it to front: 1594 1595 bool block_event = false; 1596 1597 if (event) { 1598 switch (GetEventClass(event)) { 1599 case kEventClassMouse: 1600 case kEventClassKeyboard: 1601 block_event = true; 1602 break; 1603 } 1604 } 1605 1606 QWidget *activeWidget = QApplication::activeWindow(); 1607 if ((!activeWidget || QApplicationPrivate::isBlockedByModal(activeWidget)) && 1608 top->isWindow() && block_event && !QApplicationPrivate::native_modal_dialog_active) 1609 top->raise(); 1610 1611#ifdef DEBUG_MODAL_EVENTS 1612 qDebug("%s:%d -- final decision! (%s)", __FILE__, __LINE__, block_event ? "false" : "true"); 1613#endif 1614 return !block_event; 1615} 1616#endif 1617 1618OSStatus QApplicationPrivate::tabletProximityCallback(EventHandlerCallRef, EventRef carbonEvent, 1619 void *) 1620{ 1621 OSType eventClass = GetEventClass(carbonEvent); 1622 UInt32 eventKind = GetEventKind(carbonEvent); 1623 if (eventClass != kEventClassTablet || eventKind != kEventTabletProximity) 1624 return eventNotHandledErr; 1625 1626 // Get the current point of the device and its unique ID. 1627 ::TabletProximityRec proxRec; 1628 GetEventParameter(carbonEvent, kEventParamTabletProximityRec, typeTabletProximityRec, 0, 1629 sizeof(proxRec), 0, &proxRec); 1630 qt_dispatchTabletProximityEvent(proxRec); 1631 return noErr; 1632} 1633 1634OSStatus 1635QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event, void *data) 1636{ 1637#ifndef QT_MAC_USE_COCOA 1638 QApplication *app = (QApplication *)data; 1639 QScopedLoopLevelCounter loopLevelCounter(app->d_func()->threadData); 1640 long result; 1641 if (app->filterEvent(&event, &result)) 1642 return result; 1643 if(app->macEventFilter(er, event)) //someone else ate it 1644 return noErr; 1645 QPointer<QWidget> widget; 1646 1647 /*We assume all events are handled and in 1648 the code below we set it to false when we know we didn't handle it, this 1649 will let rogue events through (shouldn't really happen, but better safe 1650 than sorry) */ 1651 bool handled_event=true; 1652 UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event); 1653 switch(eclass) 1654 { 1655 case kEventClassQt: 1656 if(ekind == kEventQtRequestShowSheet) { 1657 request_showsheet_pending = 0; 1658 QWidget *widget = 0; 1659 GetEventParameter(event, kEventParamQWidget, typeQWidget, 0, 1660 sizeof(widget), 0, &widget); 1661 if(widget) { 1662 if (widget->macEvent(er, event)) 1663 return noErr; 1664 WindowPtr window = qt_mac_window_for(widget); 1665 bool just_show = !qt_mac_is_macsheet(widget); 1666 if(!just_show) { 1667 OSStatus err = ShowSheetWindow(window, qt_mac_window_for(widget->parentWidget())); 1668 if(err != noErr) 1669 qWarning("Qt: QWidget: Unable to show as sheet %s::%s [%ld]", widget->metaObject()->className(), 1670 widget->objectName().toLocal8Bit().constData(), long(err)); 1671 just_show = true; 1672 } 1673 if(just_show) //at least the window will be visible, but the sheet flag doesn't work sadly (probalby too many sheets) 1674 ShowHide(window, true); 1675 } 1676 } else if(ekind == kEventQtRequestWindowChange) { 1677 qt_mac_event_release(request_window_change_pending); 1678 } else if(ekind == kEventQtRequestMenubarUpdate) { 1679 qt_mac_event_release(request_menubarupdate_pending); 1680 QMenuBar::macUpdateMenuBar(); 1681 } else if(ekind == kEventQtRequestActivate) { 1682 qt_mac_event_release(request_activate_pending.event); 1683 if(request_activate_pending.widget) { 1684 QWidget *tlw = request_activate_pending.widget->window(); 1685 if (tlw->macEvent(er, event)) 1686 return noErr; 1687 request_activate_pending.widget = 0; 1688 tlw->activateWindow(); 1689 SelectWindow(qt_mac_window_for(tlw)); 1690 } 1691 } else if(ekind == kEventQtRequestContext) { 1692 bool send = false; 1693 if ((send = (event == request_context_pending))) 1694 qt_mac_event_release(request_context_pending); 1695 if(send) { 1696 //figure out which widget to send it to 1697 QPoint where = QCursor::pos(); 1698 QWidget *widget = 0; 1699 GetEventParameter(event, kEventParamQWidget, typeQWidget, 0, 1700 sizeof(widget), 0, &widget); 1701 if(!widget) { 1702 if(qt_button_down) 1703 widget = qt_button_down; 1704 else 1705 widget = QApplication::widgetAt(where.x(), where.y()); 1706 } 1707 if(widget && !isBlockedByModal(widget)) { 1708 if (widget->macEvent(er, event)) 1709 return noErr; 1710 QPoint plocal(widget->mapFromGlobal(where)); 1711 const Qt::KeyboardModifiers keyboardModifiers = qt_mac_get_modifiers(GetCurrentEventKeyModifiers()); 1712 QContextMenuEvent qme(QContextMenuEvent::Mouse, plocal, where, keyboardModifiers); 1713 QApplication::sendEvent(widget, &qme); 1714 if(qme.isAccepted()) { //once this happens the events before are pitched 1715 qt_button_down = 0; 1716 qt_mac_dblclick.last_widget = 0; 1717 } 1718 } else { 1719 handled_event = false; 1720 } 1721 } 1722 } else { 1723 handled_event = false; 1724 } 1725 break; 1726 case kEventClassTablet: 1727 switch (ekind) { 1728 case kEventTabletProximity: 1729 // Get the current point of the device and its unique ID. 1730 ::TabletProximityRec proxRec; 1731 GetEventParameter(event, kEventParamTabletProximityRec, typeTabletProximityRec, 0, 1732 sizeof(proxRec), 0, &proxRec); 1733 qt_dispatchTabletProximityEvent(proxRec); 1734 } 1735 break; 1736 case kEventClassMouse: 1737 { 1738 static const int kEventParamQAppSeenMouseEvent = 'QASM'; 1739 // Check if we've seen the event, if we have we shouldn't process 1740 // it again as it may lead to spurious "double events" 1741 bool seenEvent; 1742 if (GetEventParameter(event, kEventParamQAppSeenMouseEvent, 1743 typeBoolean, 0, sizeof(bool), 0, &seenEvent) == noErr) { 1744 if (seenEvent) 1745 return eventNotHandledErr; 1746 } 1747 seenEvent = true; 1748 SetEventParameter(event, kEventParamQAppSeenMouseEvent, typeBoolean, 1749 sizeof(bool), &seenEvent); 1750 1751 Point where; 1752 bool inNonClientArea = false; 1753 GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, 1754 sizeof(where), 0, &where); 1755#if defined(DEBUG_MOUSE_MAPS) 1756 const char *edesc = 0; 1757 switch(ekind) { 1758 case kEventMouseDown: edesc = "MouseButtonPress"; break; 1759 case kEventMouseUp: edesc = "MouseButtonRelease"; break; 1760 case kEventMouseDragged: case kEventMouseMoved: edesc = "MouseMove"; break; 1761 case kEventMouseScroll: edesc = "MouseWheelScroll"; break; 1762 case kEventMouseWheelMoved: edesc = "MouseWheelMove"; break; 1763 } 1764 if(ekind == kEventMouseDown || ekind == kEventMouseUp) 1765 qDebug("Handling mouse: %s", edesc); 1766#endif 1767 QEvent::Type etype = QEvent::None; 1768 Qt::KeyboardModifiers modifiers; 1769 { 1770 UInt32 mac_modifiers = 0; 1771 GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, 0, 1772 sizeof(mac_modifiers), 0, &mac_modifiers); 1773 modifiers = qt_mac_get_modifiers(mac_modifiers); 1774 } 1775 Qt::MouseButtons buttons; 1776 { 1777 UInt32 mac_buttons = 0; 1778 GetEventParameter(event, kEventParamMouseChord, typeUInt32, 0, 1779 sizeof(mac_buttons), 0, &mac_buttons); 1780 if (ekind != kEventMouseWheelMoved) 1781 buttons = qt_mac_get_buttons(mac_buttons); 1782 else 1783 buttons = QApplication::mouseButtons(); 1784 } 1785 1786 int wheel_deltaX = 0; 1787 int wheel_deltaY = 0; 1788 static EventRef compatibilityEvent = 0; 1789 1790 if (ekind == kEventMouseScroll) { 1791 // kEventMouseScroll is the new way of dealing with mouse wheel 1792 // events (kEventMouseWheelMoved was the old). kEventMouseScroll results 1793 // in much smoother scrolling when using Mighty Mouse or TrackPad. For 1794 // compatibility with older applications, carbon will also send us 1795 // kEventMouseWheelMoved events if we dont eat this event 1796 // (actually two events; one for horizontal and one for vertical). 1797 // As a results of this, and to make sure we dont't receive duplicate events, 1798 // we try to detect when this happend by checking the 'compatibilityEvent'. 1799 // Since delta is delivered as pixels rather than degrees, we need to 1800 // convert from pixels to degrees in a sensible manner. 1801 // It looks like 1/4 degrees per pixel behaves most native. 1802 // (NB: Qt expects the unit for delta to be 8 per degree): 1803 const int pixelsToDegrees = 2; 1804 SInt32 mdelt = 0; 1805 GetEventParameter(event, kEventParamMouseWheelSmoothHorizontalDelta, typeSInt32, 0, 1806 sizeof(mdelt), 0, &mdelt); 1807 wheel_deltaX = mdelt * pixelsToDegrees; 1808 mdelt = 0; 1809 GetEventParameter(event, kEventParamMouseWheelSmoothVerticalDelta, typeSInt32, 0, 1810 sizeof(mdelt), 0, &mdelt); 1811 wheel_deltaY = mdelt * pixelsToDegrees; 1812 GetEventParameter(event, kEventParamEventRef, typeEventRef, 0, 1813 sizeof(compatibilityEvent), 0, &compatibilityEvent); 1814 } else if (ekind == kEventMouseWheelMoved) { 1815 if (event != compatibilityEvent) { 1816 compatibilityEvent = 0; 1817 int mdelt = 0; 1818 GetEventParameter(event, kEventParamMouseWheelDelta, typeSInt32, 0, 1819 sizeof(mdelt), 0, &mdelt); 1820 EventMouseWheelAxis axis; 1821 GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, 0, 1822 sizeof(axis), 0, &axis); 1823 1824 // Remove acceleration, and use either -120 or 120 as delta: 1825 if (axis == kEventMouseWheelAxisX) 1826 wheel_deltaX = qBound(-120, int(mdelt * 10000), 120); 1827 else 1828 wheel_deltaY = qBound(-120, int(mdelt * 10000), 120); 1829 } 1830 } 1831 1832 Qt::MouseButton button = Qt::NoButton; 1833 if(ekind == kEventMouseDown || ekind == kEventMouseUp) { 1834 EventMouseButton mac_button = 0; 1835 GetEventParameter(event, kEventParamMouseButton, typeMouseButton, 0, 1836 sizeof(mac_button), 0, &mac_button); 1837 button = qt_mac_get_button(mac_button); 1838 } 1839 1840 switch(ekind) { 1841 case kEventMouseDown: 1842 etype = QEvent::MouseButtonPress; 1843 break; 1844 case kEventMouseUp: 1845 etype = QEvent::MouseButtonRelease; 1846 break; 1847 case kEventMouseDragged: 1848 case kEventMouseMoved: 1849 etype = QEvent::MouseMove; 1850 break; 1851 } 1852 1853 const bool inPopupMode = app->d_func()->inPopupMode(); 1854 1855 // A click outside a popup closes the popup. Make sure 1856 // that no events are generated for the release part of that click. 1857 // (The press goes to the popup and closes it.) 1858 if (etype == QEvent::MouseButtonPress) { 1859 qt_mac_previous_press_in_popup_mode = inPopupMode; 1860 } else if (qt_mac_previous_press_in_popup_mode && !inPopupMode && etype == QEvent::MouseButtonRelease) { 1861 qt_mac_previous_press_in_popup_mode = false; 1862 handled_event = true; 1863#if defined(DEBUG_MOUSE_MAPS) 1864 qDebug("Bail out early due to qt_mac_previous_press_in_popup_mode"); 1865#endif 1866 break; // break from case kEventClassMouse 1867 } 1868 1869 //figure out which widget to send it to 1870 if(inPopupMode) { 1871 QWidget *popup = qApp->activePopupWidget(); 1872 if (qt_button_down && qt_button_down->window() == popup) { 1873 widget = qt_button_down; 1874 } else { 1875 QPoint pos = popup->mapFromGlobal(QPoint(where.h, where.v)); 1876 widget = popup->childAt(pos); 1877 } 1878 if(!widget) 1879 widget = popup; 1880 } else { 1881 if(mac_mouse_grabber) { 1882 widget = mac_mouse_grabber; 1883 } else if (qt_button_down) { 1884 widget = qt_button_down; 1885 } else { 1886 { 1887 WindowPtr window = 0; 1888 if(GetEventParameter(event, kEventParamWindowRef, typeWindowRef, 0, 1889 sizeof(window), 0, &window) != noErr) 1890 FindWindowOfClass(&where, kAllWindowClasses, &window, 0); 1891 if(window) { 1892 HIViewRef hiview; 1893 if(HIViewGetViewForMouseEvent(HIViewGetRoot(window), event, &hiview) == noErr) { 1894 widget = QWidget::find((WId)hiview); 1895 if (widget) { 1896 // Make sure we didn't pass over a widget with a "fake hole" in it. 1897 QWidget *otherWidget = QApplication::widgetAt(where.h, where.v); 1898 if (otherWidget && otherWidget->testAttribute(Qt::WA_MouseNoMask)) 1899 widget = otherWidget; 1900 } 1901 } 1902 } 1903 } 1904 if(!widget) //fallback 1905 widget = QApplication::widgetAt(where.h, where.v); 1906 if(ekind == kEventMouseUp && widget) { 1907 short part = qt_mac_window_at(where.h, where.v); 1908 if(part == inDrag) { 1909 UInt32 count = 0; 1910 GetEventParameter(event, kEventParamClickCount, typeUInt32, NULL, 1911 sizeof(count), NULL, &count); 1912 if(count == 2 && qt_mac_collapse_on_dblclick) { 1913 if (widget->macEvent(er, event)) 1914 return noErr; 1915 widget->setWindowState(widget->windowState() | Qt::WindowMinimized); 1916 //we send a hide to be like X11/Windows 1917 QEvent e(QEvent::Hide); 1918 QApplication::sendSpontaneousEvent(widget, &e); 1919 break; 1920 } 1921 } 1922 } 1923 } 1924 } 1925 if (widget && widget->macEvent(er, event)) 1926 return noErr; 1927 WindowPartCode wpc = qt_mac_window_at(where.h, where.v, 0); 1928 if (wpc == inProxyIcon && modifiers == Qt::ControlModifier && buttons != Qt::NoButton) { 1929 QIconDragEvent e; 1930 QApplication::sendSpontaneousEvent(widget, &e); 1931 if (e.isAccepted()) { 1932 return noErr; // IconDrag ate it. 1933 } 1934 } 1935 if (inPopupMode == false 1936 && (qt_button_down == 0 || qt_button_down_in_content == false) 1937 && (wpc != inContent && wpc != inStructure)) { 1938 inNonClientArea = true; 1939 switch (etype) { 1940 case QEvent::MouseButtonPress: { 1941 UInt32 count = 0; 1942 GetEventParameter(event, kEventParamClickCount, typeUInt32, 0, 1943 sizeof(count), 0, &count); 1944 if(count % 2 || count == 0) { 1945 etype = QEvent::NonClientAreaMouseButtonPress; 1946 } else { 1947 etype = QEvent::NonClientAreaMouseButtonDblClick; 1948 }} break; 1949 case QEvent::MouseButtonRelease: 1950 etype = QEvent::NonClientAreaMouseButtonRelease; 1951 break; 1952 case QEvent::MouseMove: 1953 if (widget == 0 || widget->hasMouseTracking()) 1954 etype = QEvent::NonClientAreaMouseMove; 1955 break; 1956 default: 1957 break; 1958 } 1959 } 1960 1961 if(qt_mac_find_window((FrontWindow()))) { //set the cursor up 1962 QCursor cursor(Qt::ArrowCursor); 1963 QWidget *cursor_widget = widget; 1964 if(cursor_widget && cursor_widget == qt_button_down && ekind == kEventMouseUp) 1965 cursor_widget = QApplication::widgetAt(where.h, where.v); 1966 if(cursor_widget) { //only over the app, do we set a cursor.. 1967 if(!qApp->d_func()->cursor_list.isEmpty()) { 1968 cursor = qApp->d_func()->cursor_list.first(); 1969 } else { 1970 for(; cursor_widget; cursor_widget = cursor_widget->parentWidget()) { 1971 QWExtra *extra = cursor_widget->d_func()->extraData(); 1972 if(extra && extra->curs && cursor_widget->isEnabled()) { 1973 cursor = *extra->curs; 1974 break; 1975 } 1976 } 1977 } 1978 } 1979 qt_mac_set_cursor(&cursor); 1980 } 1981 1982 //This mouse button state stuff looks like this on purpose 1983 //although it looks hacky it is VERY intentional.. 1984 if(widget && app_do_modal && !qt_try_modal(widget, event)) { 1985 if(ekind == kEventMouseDown && qt_mac_is_macsheet(QApplication::activeModalWidget())) 1986 QApplication::activeModalWidget()->parentWidget()->activateWindow(); //sheets have a parent 1987 handled_event = false; 1988#if defined(DEBUG_MOUSE_MAPS) 1989 qDebug("Bail out early due to qt_try_modal"); 1990#endif 1991 break; 1992 } 1993 1994 UInt32 tabletEventType = 0; 1995 GetEventParameter(event, kEventParamTabletEventType, typeUInt32, 0, 1996 sizeof(tabletEventType), 0, &tabletEventType); 1997 if (tabletEventType == kEventTabletPoint) { 1998 TabletPointRec tabletPointRec; 1999 GetEventParameter(event, kEventParamTabletPointRec, typeTabletPointRec, 0, 2000 sizeof(tabletPointRec), 0, &tabletPointRec); 2001 QEvent::Type t = QEvent::TabletMove; //default 2002 int new_tablet_button_state = tabletPointRec.buttons ? 1 : 0; 2003 if (new_tablet_button_state != tablet_button_state) 2004 if (new_tablet_button_state) 2005 t = QEvent::TabletPress; 2006 else 2007 t = QEvent::TabletRelease; 2008 tablet_button_state = new_tablet_button_state; 2009 2010 QMacTabletHash *tabletHash = qt_mac_tablet_hash(); 2011 if (!tabletHash->contains(tabletPointRec.deviceID) && t != QEvent::TabletRelease) { 2012 // Never discard TabletRelease events as they may be delivered *after* TabletLeaveProximity events 2013 qWarning("handleTabletEvent: This tablet device is unknown" 2014 " (received no proximity event for it). Discarding event."); 2015 return false; 2016 } 2017 QTabletDeviceData &deviceData = tabletHash->operator[](tabletPointRec.deviceID); 2018 if (t == QEvent::TabletPress) { 2019 deviceData.widgetToGetPress = widget; 2020 } else if (t == QEvent::TabletRelease && deviceData.widgetToGetPress) { 2021 widget = deviceData.widgetToGetPress; 2022 deviceData.widgetToGetPress = 0; 2023 } 2024 2025 if (widget) { 2026 int tiltX = ((int)tabletPointRec.tiltX)/(32767/64); // 32K -> 60 2027 int tiltY = ((int)tabletPointRec.tiltY)/(-32767/64); // 32K -> 60 2028 HIPoint hiPoint; 2029 GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, 0, sizeof(HIPoint), 0, &hiPoint); 2030 QPointF hiRes(hiPoint.x, hiPoint.y); 2031 QPoint global(where.h, where.v); 2032 2033 2034 2035 QPoint local(widget->mapFromGlobal(global)); 2036 int z = 0; 2037 qreal rotation = 0.0; 2038 qreal tp = 0.0; 2039 // Again from the Wacom.h header 2040 2041 if (deviceData.capabilityMask & 0x0200) // Z-axis 2042 z = tabletPointRec.absZ; 2043 2044 if (deviceData.capabilityMask & 0x0800) // Tangential pressure 2045 tp = tabletPointRec.tangentialPressure / 32767.0; 2046 2047 if (deviceData.capabilityMask & 0x2000) // Rotation 2048 rotation = qreal(tabletPointRec.rotation) / 64.0; 2049 2050 QTabletEvent e(t, local, global, hiRes, deviceData.tabletDeviceType, 2051 deviceData.tabletPointerType, 2052 qreal(tabletPointRec.pressure / qreal(0xffff)), tiltX, tiltY, 2053 tp, rotation, z, modifiers, deviceData.tabletUniqueID); 2054 QApplication::sendSpontaneousEvent(widget, &e); 2055 if (e.isAccepted()) { 2056 if (t == QEvent::TabletPress) { 2057 qt_button_down = widget; 2058 } else if (t == QEvent::TabletRelease) { 2059 qt_button_down = 0; 2060 } 2061#if defined(DEBUG_MOUSE_MAPS) 2062 qDebug("Bail out early due to tablet acceptance"); 2063#endif 2064 break; 2065 } 2066 } 2067 } 2068 2069 if(ekind == kEventMouseDown) { 2070 qt_mac_no_click_through_mode = false; 2071 const short windowPart = qt_mac_window_at(where.h, where.v, 0); 2072 // Menubar almost always wins. 2073 if (!inPopupMode && windowPart == inMenuBar) { 2074 MenuSelect(where); //allow menu tracking 2075 return noErr; 2076 } 2077 2078 if (widget && !(GetCurrentKeyModifiers() & cmdKey)) { 2079 extern bool qt_isGenuineQWidget(const QWidget *); // qwidget_mac.cpp 2080 QWidget *window = widget->window(); 2081 bool genuineQtWidget = qt_isGenuineQWidget(widget); // the widget, not the window. 2082 window->raise(); 2083 2084 bool needActivate = (window->windowType() != Qt::Desktop) 2085 && (window->windowType() != Qt::Popup) 2086 && !qt_mac_is_macsheet(window); 2087 if (needActivate && (!window->isModal() && qobject_cast<QDockWidget *>(window))) 2088 needActivate = false; 2089 2090 if (genuineQtWidget && needActivate) 2091 needActivate = !window->isActiveWindow() 2092 || !IsWindowActive(qt_mac_window_for(window)); 2093 2094 if (needActivate) { 2095 window->activateWindow(); 2096 if (!qt_mac_can_clickThrough(widget)) { 2097 qt_mac_no_click_through_mode = true; 2098 handled_event = false; 2099#if defined(DEBUG_MOUSE_MAPS) 2100 qDebug("Bail out early due to qt_mac_canClickThrough %s::%s", widget->metaObject()->className(), 2101 widget->objectName().toLocal8Bit().constData()); 2102#endif 2103 break; 2104 } 2105 } 2106 } 2107 2108 if(qt_mac_dblclick.last_widget && 2109 qt_mac_dblclick.last_x != -1 && qt_mac_dblclick.last_y != -1 && 2110 QRect(qt_mac_dblclick.last_x-2, qt_mac_dblclick.last_y-2, 4, 4).contains(QPoint(where.h, where.v))) { 2111 if(qt_mac_dblclick.use_qt_time_limit) { 2112 EventTime now = GetEventTime(event); 2113 if(qt_mac_dblclick.last_time != -2 && qt_mac_dblclick.last_widget == widget && 2114 now - qt_mac_dblclick.last_time <= ((double)QApplicationPrivate::mouse_double_click_time)/1000 && 2115 qt_mac_dblclick.last_button == button) 2116 etype = QEvent::MouseButtonDblClick; 2117 } else { 2118 UInt32 count = 0; 2119 GetEventParameter(event, kEventParamClickCount, typeUInt32, 0, 2120 sizeof(count), 0, &count); 2121 if(!(count % 2) && qt_mac_dblclick.last_modifiers == modifiers && 2122 qt_mac_dblclick.last_widget == widget && qt_mac_dblclick.last_button == button) 2123 etype = QEvent::MouseButtonDblClick; 2124 } 2125 if(etype == QEvent::MouseButtonDblClick) 2126 qt_mac_dblclick.last_widget = 0; 2127 } 2128 if(etype != QEvent::MouseButtonDblClick) { 2129 qt_mac_dblclick.last_x = where.h; 2130 qt_mac_dblclick.last_y = where.v; 2131 } else { 2132 qt_mac_dblclick.last_x = qt_mac_dblclick.last_y = -1; 2133 } 2134 } else if(qt_mac_no_click_through_mode) { 2135 if(ekind == kEventMouseUp) 2136 qt_mac_no_click_through_mode = false; 2137 handled_event = false; 2138#if defined(DEBUG_MOUSE_MAPS) 2139 qDebug("Bail out early due to qt_mac_no_click_through_mode"); 2140#endif 2141 break; 2142 } 2143 2144 QPointer<QWidget> leaveAfterRelease = 0; 2145 switch(ekind) { 2146 case kEventMouseUp: 2147 if (!buttons) { 2148 if (!inPopupMode && !QWidget::mouseGrabber()) 2149 leaveAfterRelease = qt_button_down; 2150 qt_button_down = 0; 2151 } 2152 break; 2153 case kEventMouseDown: { 2154 if (!qt_button_down) 2155 qt_button_down = widget; 2156 WindowPartCode wpc = qt_mac_window_at(where.h, where.v, 0); 2157 qt_button_down_in_content = (wpc == inContent || wpc == inStructure); 2158 break; } 2159 } 2160 2161 // Check if we should send enter/leave events: 2162 switch(ekind) { 2163 case kEventMouseDragged: 2164 case kEventMouseMoved: 2165 case kEventMouseUp: 2166 case kEventMouseDown: { 2167 // If we are in popup mode, widget will point to the current popup no matter 2168 // where the mouse cursor is. In that case find out if the mouse cursor is 2169 // really over the popup in order to send correct enter / leave envents. 2170 QWidget * const enterLeaveWidget = (inPopupMode || ekind == kEventMouseUp) ? 2171 QApplication::widgetAt(where.h, where.v) : static_cast<QWidget*>(widget); 2172 2173 if ((QWidget *) qt_last_mouse_receiver != enterLeaveWidget || inNonClientArea) { 2174#ifdef DEBUG_MOUSE_MAPS 2175 qDebug("Entering: %p - %s (%s), Leaving %s (%s)", (QWidget*)enterLeaveWidget, 2176 enterLeaveWidget ? enterLeaveWidget->metaObject()->className() : "none", 2177 enterLeaveWidget ? enterLeaveWidget->objectName().toLocal8Bit().constData() : "", 2178 qt_last_mouse_receiver ? qt_last_mouse_receiver->metaObject()->className() : "none", 2179 qt_last_mouse_receiver ? qt_last_mouse_receiver->objectName().toLocal8Bit().constData() : ""); 2180#endif 2181 2182 QWidget * const mouseGrabber = QWidget::mouseGrabber(); 2183 2184 if (inPopupMode) { 2185 QWidget *enter = enterLeaveWidget; 2186 QWidget *leave = qt_last_mouse_receiver; 2187 if (mouseGrabber) { 2188 QWidget * const popupWidget = qApp->activePopupWidget(); 2189 if (leave == popupWidget) 2190 enter = mouseGrabber; 2191 if (enter == popupWidget) 2192 leave = mouseGrabber; 2193 if ((enter == mouseGrabber && leave == popupWidget) 2194 || (leave == mouseGrabber && enter == popupWidget)) { 2195 QApplicationPrivate::dispatchEnterLeave(enter, leave); 2196 qt_last_mouse_receiver = enter; 2197 } 2198 } else { 2199 QApplicationPrivate::dispatchEnterLeave(enter, leave); 2200 qt_last_mouse_receiver = enter; 2201 } 2202 } else if ((!qt_button_down || !qt_last_mouse_receiver) && !mouseGrabber && !leaveAfterRelease) { 2203 QApplicationPrivate::dispatchEnterLeave(enterLeaveWidget, qt_last_mouse_receiver); 2204 qt_last_mouse_receiver = enterLeaveWidget; 2205 } 2206 } 2207 break; } 2208 } 2209 2210 if(widget) { 2211 QPoint p(where.h, where.v); 2212 QPoint plocal(widget->mapFromGlobal(p)); 2213 if(etype == QEvent::MouseButtonPress) { 2214 qt_mac_dblclick.last_widget = widget; 2215 qt_mac_dblclick.last_modifiers = modifiers; 2216 qt_mac_dblclick.last_button = button; 2217 qt_mac_dblclick.last_time = GetEventTime(event); 2218 } 2219 2220 if (wheel_deltaX || wheel_deltaY) { 2221#ifndef QT_NO_WHEELEVENT 2222 if (wheel_deltaX) { 2223 QWheelEvent qwe(plocal, p, wheel_deltaX, buttons, modifiers, Qt::Horizontal); 2224 QApplication::sendSpontaneousEvent(widget, &qwe); 2225 if (!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) { 2226 QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p, 2227 wheel_deltaX, buttons, modifiers, Qt::Horizontal); 2228 QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); 2229 if (!qwe2.isAccepted()) 2230 handled_event = false; 2231 } 2232 } 2233 if (wheel_deltaY) { 2234 QWheelEvent qwe(plocal, p, wheel_deltaY, buttons, modifiers, Qt::Vertical); 2235 QApplication::sendSpontaneousEvent(widget, &qwe); 2236 if (!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) { 2237 QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p, 2238 wheel_deltaY, buttons, modifiers, Qt::Vertical); 2239 QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); 2240 if (!qwe2.isAccepted()) 2241 handled_event = false; 2242 } 2243 } 2244#endif // QT_NO_WHEELEVENT 2245 } else { 2246#ifdef QMAC_SPEAK_TO_ME 2247 const int speak_keys = Qt::AltModifier | Qt::ShiftModifier; 2248 if(etype == QMouseEvent::MouseButtonDblClick && ((modifiers & speak_keys) == speak_keys)) { 2249 QVariant v = widget->property("displayText"); 2250 if(!v.isValid()) v = widget->property("text"); 2251 if(!v.isValid()) v = widget->property("windowTitle"); 2252 if(v.isValid()) { 2253 QString s = v.toString(); 2254 s.replace(QRegExp(QString::fromLatin1("(\\&|\\<[^\\>]*\\>)")), QLatin1String("")); 2255 SpeechChannel ch; 2256 NewSpeechChannel(0, &ch); 2257 SpeakText(ch, s.toLatin1().constData(), s.length()); 2258 DisposeSpeechChannel(ch); 2259 } 2260 } 2261#endif 2262 Qt::MouseButton buttonToSend = button; 2263 static bool lastButtonTranslated = false; 2264 if(ekind == kEventMouseDown && 2265 button == Qt::LeftButton && (modifiers & Qt::MetaModifier)) { 2266 buttonToSend = Qt::RightButton; 2267 lastButtonTranslated = true; 2268 } else if(ekind == kEventMouseUp && lastButtonTranslated) { 2269 buttonToSend = Qt::RightButton; 2270 lastButtonTranslated = false; 2271 } 2272 QMouseEvent qme(etype, plocal, p, buttonToSend, buttons, modifiers); 2273 QApplication::sendSpontaneousEvent(widget, &qme); 2274 if(!qme.isAccepted() || inNonClientArea) 2275 handled_event = false; 2276 } 2277 2278 if (leaveAfterRelease) { 2279 QWidget *enter = QApplication::widgetAt(where.h, where.v); 2280 QApplicationPrivate::dispatchEnterLeave(enter, leaveAfterRelease); 2281 qt_last_mouse_receiver = enter; 2282 leaveAfterRelease = 0; 2283 } 2284 2285 if(ekind == kEventMouseDown && 2286 ((button == Qt::RightButton) || 2287 (button == Qt::LeftButton && (modifiers & Qt::MetaModifier)))) 2288 qt_event_request_context(); 2289 2290#ifdef DEBUG_MOUSE_MAPS 2291 const char *event_desc = edesc; 2292 if(etype == QEvent::MouseButtonDblClick) 2293 event_desc = "Double Click"; 2294 else if(etype == QEvent::NonClientAreaMouseButtonPress) 2295 event_desc = "NonClientMousePress"; 2296 else if(etype == QEvent::NonClientAreaMouseButtonRelease) 2297 event_desc = "NonClientMouseRelease"; 2298 else if(etype == QEvent::NonClientAreaMouseMove) 2299 event_desc = "NonClientMouseMove"; 2300 else if(etype == QEvent::NonClientAreaMouseButtonDblClick) 2301 event_desc = "NonClientMouseDblClick"; 2302 qDebug("%d %d (%d %d) - Would send (%s) event to %p %s %s (%d 0x%08x 0x%08x %d)", p.x(), p.y(), 2303 plocal.x(), plocal.y(), event_desc, (QWidget*)widget, 2304 widget ? widget->objectName().toLocal8Bit().constData() : "*Unknown*", 2305 widget ? widget->metaObject()->className() : "*Unknown*", 2306 button, (int)buttons, (int)modifiers, wheel_deltaX); 2307#endif 2308 } else { 2309 handled_event = false; 2310 } 2311 break; 2312 } 2313 case kEventClassTextInput: 2314 case kEventClassKeyboard: { 2315 EventRef key_event = event; 2316 if(eclass == kEventClassTextInput) { 2317 Q_ASSERT(ekind == kEventTextInputUnicodeForKeyEvent); 2318 OSStatus err = GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, 0, 2319 sizeof(key_event), 0, &key_event); 2320 Q_ASSERT(err == noErr); 2321 Q_UNUSED(err); 2322 } 2323 const UInt32 key_ekind = GetEventKind(key_event); 2324 Q_ASSERT(GetEventClass(key_event) == kEventClassKeyboard); 2325 2326 if(key_ekind == kEventRawKeyDown) 2327 qt_keymapper_private()->updateKeyMap(er, key_event, data); 2328 if(mac_keyboard_grabber) 2329 widget = mac_keyboard_grabber; 2330 else if (app->activePopupWidget()) 2331 widget = (app->activePopupWidget()->focusWidget() ? 2332 app->activePopupWidget()->focusWidget() : app->activePopupWidget()); 2333 else if(QApplication::focusWidget()) 2334 widget = QApplication::focusWidget(); 2335 else 2336 widget = app->activeWindow(); 2337 2338 if (widget) { 2339 if (widget->macEvent(er, event)) 2340 return noErr; 2341 } else { 2342 // Darn, I need to update tho modifier state, even though 2343 // Qt itself isn't getting them, otherwise the keyboard state get inconsistent. 2344 if (key_ekind == kEventRawKeyModifiersChanged) { 2345 UInt32 modifiers = 0; 2346 GetEventParameter(key_event, kEventParamKeyModifiers, typeUInt32, 0, 2347 sizeof(modifiers), 0, &modifiers); 2348 extern void qt_mac_send_modifiers_changed(quint32 modifiers, QObject *object); // qkeymapper_mac.cpp 2349 // Just send it to the qApp for the time being. 2350 qt_mac_send_modifiers_changed(modifiers, qApp); 2351 } 2352 handled_event = false; 2353 break; 2354 } 2355 2356 if(app_do_modal && !qt_try_modal(widget, key_event)) 2357 break; 2358 if (eclass == kEventClassTextInput) { 2359 handled_event = false; 2360 } else { 2361 handled_event = qt_keymapper_private()->translateKeyEvent(widget, er, key_event, data, 2362 widget == mac_keyboard_grabber); 2363 } 2364 break; } 2365 case kEventClassWindow: { 2366 WindowRef wid = 0; 2367 GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0, 2368 sizeof(WindowRef), 0, &wid); 2369 widget = qt_mac_find_window(wid); 2370 if (widget && widget->macEvent(er, event)) 2371 return noErr; 2372 if(ekind == kEventWindowActivated) { 2373 if(QApplicationPrivate::app_style) { 2374 QEvent ev(QEvent::Style); 2375 QApplication::sendSpontaneousEvent(QApplicationPrivate::app_style, &ev); 2376 } 2377 2378 if(widget && app_do_modal && !qt_try_modal(widget, event)) 2379 break; 2380 2381 if(widget && widget->window()->isVisible()) { 2382 QWidget *tlw = widget->window(); 2383 if(tlw->isWindow() && !(tlw->windowType() == Qt::Popup) 2384 && !qt_mac_is_macdrawer(tlw) 2385 && (!tlw->parentWidget() || tlw->isModal() 2386 || !(tlw->windowType() == Qt::Tool))) { 2387 bool just_send_event = false; 2388 { 2389 WindowActivationScope scope; 2390 if(GetWindowActivationScope((WindowRef)wid, &scope) == noErr && 2391 scope == kWindowActivationScopeIndependent) { 2392 if(GetFrontWindowOfClass(kAllWindowClasses, true) != wid) 2393 just_send_event = true; 2394 } 2395 } 2396 if(just_send_event) { 2397 QEvent e(QEvent::WindowActivate); 2398 QApplication::sendSpontaneousEvent(widget, &e); 2399 } else { 2400 app->setActiveWindow(tlw); 2401 } 2402 } 2403 QMenuBar::macUpdateMenuBar(); 2404 } 2405 } else if(ekind == kEventWindowDeactivated) { 2406 if(widget && QApplicationPrivate::active_window == widget) 2407 app->setActiveWindow(0); 2408 } else { 2409 handled_event = false; 2410 } 2411 break; } 2412 case kEventClassApplication: 2413 if(ekind == kEventAppActivated) { 2414 if(QApplication::desktopSettingsAware()) 2415 qt_mac_update_os_settings(); 2416 if(qt_clipboard) { //manufacture an event so the clipboard can see if it has changed 2417 QEvent ev(QEvent::Clipboard); 2418 QApplication::sendSpontaneousEvent(qt_clipboard, &ev); 2419 } 2420 if(app) { 2421 QEvent ev(QEvent::ApplicationActivate); 2422 QApplication::sendSpontaneousEvent(app, &ev); 2423 } 2424 if(!app->activeWindow()) { 2425 WindowPtr wp = ActiveNonFloatingWindow(); 2426 if(QWidget *tmp_w = qt_mac_find_window(wp)) 2427 app->setActiveWindow(tmp_w); 2428 } 2429 QMenuBar::macUpdateMenuBar(); 2430 } else if(ekind == kEventAppDeactivated) { 2431 //qt_mac_no_click_through_mode = false; 2432 while(app->d_func()->inPopupMode()) 2433 app->activePopupWidget()->close(); 2434 if(app) { 2435 QEvent ev(QEvent::ApplicationDeactivate); 2436 QApplication::sendSpontaneousEvent(app, &ev); 2437 } 2438 app->setActiveWindow(0); 2439 } else if(ekind == kEventAppAvailableWindowBoundsChanged) { 2440 QDesktopWidgetImplementation::instance()->onResize(); 2441 } else { 2442 handled_event = false; 2443 } 2444 break; 2445 case kAppearanceEventClass: 2446 if(ekind == kAEAppearanceChanged) { 2447 if(QApplication::desktopSettingsAware()) 2448 qt_mac_update_os_settings(); 2449 if(QApplicationPrivate::app_style) { 2450 QEvent ev(QEvent::Style); 2451 QApplication::sendSpontaneousEvent(QApplicationPrivate::app_style, &ev); 2452 } 2453 } else { 2454 handled_event = false; 2455 } 2456 break; 2457 case kEventClassAppleEvent: 2458 if(ekind == kEventAppleEvent) { 2459 EventRecord erec; 2460 if(!ConvertEventRefToEventRecord(event, &erec)) 2461 qDebug("Qt: internal: WH0A, unexpected condition reached. %s:%d", __FILE__, __LINE__); 2462 else if(AEProcessAppleEvent(&erec) != noErr) 2463 handled_event = false; 2464 } else { 2465 handled_event = false; 2466 } 2467 break; 2468 case kEventClassCommand: 2469 if(ekind == kEventCommandProcess) { 2470 HICommand cmd; 2471 GetEventParameter(event, kEventParamDirectObject, typeHICommand, 2472 0, sizeof(cmd), 0, &cmd); 2473 handled_event = false; 2474 if(!cmd.menu.menuRef && GetApplicationDockTileMenu()) { 2475 EventRef copy = CopyEvent(event); 2476 HICommand copy_cmd; 2477 GetEventParameter(event, kEventParamDirectObject, typeHICommand, 2478 0, sizeof(copy_cmd), 0, ©_cmd); 2479 copy_cmd.menu.menuRef = GetApplicationDockTileMenu(); 2480 SetEventParameter(copy, kEventParamDirectObject, typeHICommand, sizeof(copy_cmd), ©_cmd); 2481 if(SendEventToMenu(copy, copy_cmd.menu.menuRef) == noErr) 2482 handled_event = true; 2483 } 2484 if(!handled_event) { 2485 if(cmd.commandID == kHICommandQuit) { 2486 // Quitting the application is not Qt's responsibility if 2487 // used in a plugin or just embedded into a native application. 2488 // In that case, let the event pass down to the native apps event handler. 2489 if (!QApplication::testAttribute(Qt::AA_MacPluginApplication)) { 2490 handled_event = true; 2491 HiliteMenu(0); 2492 bool handle_quit = true; 2493 if(QApplicationPrivate::modalState()) { 2494 int visible = 0; 2495 const QWidgetList tlws = QApplication::topLevelWidgets(); 2496 for(int i = 0; i < tlws.size(); ++i) { 2497 if(tlws.at(i)->isVisible()) 2498 ++visible; 2499 } 2500 handle_quit = (visible <= 1); 2501 } 2502 if(handle_quit) { 2503 QCloseEvent ev; 2504 QApplication::sendSpontaneousEvent(app, &ev); 2505 if(ev.isAccepted()) 2506 app->quit(); 2507 } else { 2508 QApplication::beep(); 2509 } 2510 } 2511 } else if(cmd.commandID == kHICommandSelectWindow) { 2512 if((GetCurrentKeyModifiers() & cmdKey)) 2513 handled_event = true; 2514 } else if(cmd.commandID == kHICommandAbout) { 2515 QMessageBox::aboutQt(0); 2516 HiliteMenu(0); 2517 handled_event = true; 2518 } 2519 } 2520 } 2521 break; 2522 } 2523 2524#ifdef DEBUG_EVENTS 2525 qDebug("%shandled event %c%c%c%c %d", handled_event ? "(*) " : "", 2526 char(eclass >> 24), char((eclass >> 16) & 255), char((eclass >> 8) & 255), 2527 char(eclass & 255), (int)ekind); 2528#endif 2529 if(!handled_event) //let the event go through 2530 return eventNotHandledErr; 2531 return noErr; //we eat the event 2532#else 2533 Q_UNUSED(er); 2534 Q_UNUSED(event); 2535 Q_UNUSED(data); 2536 return eventNotHandledErr; 2537#endif 2538} 2539 2540#ifdef QT_MAC_USE_COCOA 2541void QApplicationPrivate::qt_initAfterNSAppStarted() 2542{ 2543 setupAppleEvents(); 2544 qt_mac_update_cursor(); 2545} 2546 2547void QApplicationPrivate::setupAppleEvents() 2548{ 2549 // This function is called from the event dispatcher when NSApplication has 2550 // finished initialization, which appears to be just after [NSApplication run] has 2551 // started to execute. By setting up our apple events handlers this late, we override 2552 // the ones set up by NSApplication. 2553 2554 // If Qt is used as a plugin, we let the 3rd party application handle events 2555 // like quit and open file events. Otherwise, if we install our own handlers, we 2556 // easily end up breaking functionallity the 3rd party application depend on: 2557 if (QApplication::testAttribute(Qt::AA_MacPluginApplication)) 2558 return; 2559 2560 QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; 2561 NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager]; 2562 [eventManager setEventHandler:newDelegate andSelector:@selector(appleEventQuit:withReplyEvent:) 2563 forEventClass:kCoreEventClass andEventID:kAEQuitApplication]; 2564 [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:) 2565 forEventClass:kInternetEventClass andEventID:kAEGetURL]; 2566} 2567#endif 2568 2569// In Carbon this is your one stop for apple events. 2570// In Cocoa, it ISN'T. This is the catch-all Apple Event handler that exists 2571// for the time between instantiating the NSApplication, but before the 2572// NSApplication has installed it's OWN Apple Event handler. When Cocoa has 2573// that set up, we remove this. So, if you are debugging problems, you likely 2574// want to check out QCocoaApplicationDelegate instead. 2575OSStatus QApplicationPrivate::globalAppleEventProcessor(const AppleEvent *ae, AppleEvent *, long handlerRefcon) 2576{ 2577 QApplication *app = (QApplication *)handlerRefcon; 2578 bool handled_event=false; 2579 OSType aeID=typeWildCard, aeClass=typeWildCard; 2580 AEGetAttributePtr(ae, keyEventClassAttr, typeType, 0, &aeClass, sizeof(aeClass), 0); 2581 AEGetAttributePtr(ae, keyEventIDAttr, typeType, 0, &aeID, sizeof(aeID), 0); 2582 if(aeClass == kCoreEventClass) { 2583 switch(aeID) { 2584 case kAEQuitApplication: { 2585 extern bool qt_mac_quit_menu_item_enabled; // qmenu_mac.cpp 2586 if (qt_mac_quit_menu_item_enabled) { 2587 QCloseEvent ev; 2588 QApplication::sendSpontaneousEvent(app, &ev); 2589 if(ev.isAccepted()) { 2590 handled_event = true; 2591 app->quit(); 2592 } 2593 } else { 2594 QApplication::beep(); // Sorry, you can't quit right now. 2595 } 2596 break; } 2597 case kAEOpenDocuments: { 2598 AEDescList docs; 2599 if(AEGetParamDesc(ae, keyDirectObject, typeAEList, &docs) == noErr) { 2600 long cnt = 0; 2601 AECountItems(&docs, &cnt); 2602 UInt8 *str_buffer = NULL; 2603 for(int i = 0; i < cnt; i++) { 2604 FSRef ref; 2605 if(AEGetNthPtr(&docs, i+1, typeFSRef, 0, 0, &ref, sizeof(ref), 0) != noErr) 2606 continue; 2607 if(!str_buffer) 2608 str_buffer = (UInt8 *)malloc(1024); 2609 FSRefMakePath(&ref, str_buffer, 1024); 2610 QFileOpenEvent ev(QString::fromUtf8((const char *)str_buffer)); 2611 QApplication::sendSpontaneousEvent(app, &ev); 2612 } 2613 if(str_buffer) 2614 free(str_buffer); 2615 } 2616 break; } 2617 default: 2618 break; 2619 } 2620 } else if (aeClass == kInternetEventClass) { 2621 switch (aeID) { 2622 case kAEGetURL: { 2623 char urlData[1024]; 2624 Size actualSize; 2625 if (AEGetParamPtr(ae, keyDirectObject, typeChar, 0, urlData, 2626 sizeof(urlData) - 1, &actualSize) == noErr) { 2627 urlData[actualSize] = 0; 2628 QFileOpenEvent ev(QUrl(QString::fromUtf8(urlData))); 2629 QApplication::sendSpontaneousEvent(app, &ev); 2630 } 2631 break; 2632 } 2633 default: 2634 break; 2635 } 2636 } 2637#ifdef DEBUG_EVENTS 2638 qDebug("Qt: internal: %shandled Apple event! %c%c%c%c %c%c%c%c", handled_event ? "(*)" : "", 2639 char(aeID >> 24), char((aeID >> 16) & 255), char((aeID >> 8) & 255),char(aeID & 255), 2640 char(aeClass >> 24), char((aeClass >> 16) & 255), char((aeClass >> 8) & 255),char(aeClass & 255)); 2641#else 2642 if(!handled_event) //let the event go through 2643 return eventNotHandledErr; 2644 return noErr; //we eat the event 2645#endif 2646} 2647 2648/*! 2649 \fn bool QApplication::macEventFilter(EventHandlerCallRef caller, EventRef event) 2650 2651 \warning This virtual function is only used under Mac OS X, and behaves different 2652 depending on if Qt is based on Carbon or Cocoa. 2653 2654 For the Carbon port, If you create an application that inherits QApplication and reimplement 2655 this function, you get direct access to all Carbon Events that Qt registers 2656 for from Mac OS X with this function being called with the \a caller and 2657 the \a event. 2658 2659 For the Cocoa port, If you create an application that inherits QApplication and reimplement 2660 this function, you get direct access to all Cocoa Events that Qt receives 2661 from Mac OS X with this function being called with the \a caller being 0 and 2662 the \a event being an NSEvent pointer: 2663 2664 NSEvent *e = reinterpret_cast<NSEvent *>(event); 2665 2666 Return true if you want to stop the event from being processed. 2667 Return false for normal event dispatching. The default 2668 implementation returns false. 2669*/ 2670bool QApplication::macEventFilter(EventHandlerCallRef, EventRef) 2671{ 2672 return false; 2673} 2674 2675/*! 2676 \internal 2677*/ 2678void QApplicationPrivate::openPopup(QWidget *popup) 2679{ 2680 if (!QApplicationPrivate::popupWidgets) // create list 2681 QApplicationPrivate::popupWidgets = new QWidgetList; 2682 QApplicationPrivate::popupWidgets->append(popup); // add to end of list 2683 2684 // popups are not focus-handled by the window system (the first 2685 // popup grabbed the keyboard), so we have to do that manually: A 2686 // new popup gets the focus 2687 if (popup->focusWidget()) { 2688 popup->focusWidget()->setFocus(Qt::PopupFocusReason); 2689 } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup 2690 popup->setFocus(Qt::PopupFocusReason); 2691 } 2692} 2693 2694/*! 2695 \internal 2696*/ 2697void QApplicationPrivate::closePopup(QWidget *popup) 2698{ 2699 Q_Q(QApplication); 2700 if (!QApplicationPrivate::popupWidgets) 2701 return; 2702 2703 QApplicationPrivate::popupWidgets->removeAll(popup); 2704 if (popup == qt_button_down) 2705 qt_button_down = 0; 2706 if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup 2707 delete QApplicationPrivate::popupWidgets; 2708 QApplicationPrivate::popupWidgets = 0; 2709 2710 // Special case for Tool windows: since they are activated and deactived together 2711 // with a normal window they never become the QApplicationPrivate::active_window. 2712 QWidget *appFocusWidget = QApplication::focusWidget(); 2713 if (appFocusWidget && appFocusWidget->window()->windowType() == Qt::Tool) { 2714 appFocusWidget->setFocus(Qt::PopupFocusReason); 2715 } else if (QApplicationPrivate::active_window) { 2716 if (QWidget *fw = QApplicationPrivate::active_window->focusWidget()) { 2717 if (fw != QApplication::focusWidget()) { 2718 fw->setFocus(Qt::PopupFocusReason); 2719 } else { 2720 QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason); 2721 q->sendEvent(fw, &e); 2722 } 2723 } 2724 } 2725 } else { 2726 // popups are not focus-handled by the window system (the 2727 // first popup grabbed the keyboard), so we have to do that 2728 // manually: A popup was closed, so the previous popup gets 2729 // the focus. 2730 QWidget* aw = QApplicationPrivate::popupWidgets->last(); 2731 if (QWidget *fw = aw->focusWidget()) 2732 fw->setFocus(Qt::PopupFocusReason); 2733 } 2734} 2735 2736void QApplication::beep() 2737{ 2738 qt_mac_beep(); 2739} 2740 2741void QApplication::alert(QWidget *widget, int duration) 2742{ 2743 if (!QApplicationPrivate::checkInstance("alert")) 2744 return; 2745 2746 QWidgetList windowsToMark; 2747 if (!widget) 2748 windowsToMark += topLevelWidgets(); 2749 else 2750 windowsToMark.append(widget->window()); 2751 2752 bool needNotification = false; 2753 for (int i = 0; i < windowsToMark.size(); ++i) { 2754 QWidget *window = windowsToMark.at(i); 2755 if (!window->isActiveWindow() && window->isVisible()) { 2756 needNotification = true; // yeah, we may set it multiple times, but that's OK. 2757 if (duration != 0) { 2758 QTimer *timer = new QTimer(qApp); 2759 timer->setSingleShot(true); 2760 connect(timer, SIGNAL(timeout()), qApp, SLOT(_q_alertTimeOut())); 2761 if (QTimer *oldTimer = qApp->d_func()->alertTimerHash.value(widget)) { 2762 qApp->d_func()->alertTimerHash.remove(widget); 2763 delete oldTimer; 2764 } 2765 qApp->d_func()->alertTimerHash.insert(widget, timer); 2766 timer->start(duration); 2767 } 2768 } 2769 } 2770 if (needNotification) 2771 qt_mac_send_notification(); 2772} 2773 2774void QApplicationPrivate::_q_alertTimeOut() 2775{ 2776 if (QTimer *timer = qobject_cast<QTimer *>(q_func()->sender())) { 2777 QHash<QWidget *, QTimer *>::iterator it = alertTimerHash.begin(); 2778 while (it != alertTimerHash.end()) { 2779 if (it.value() == timer) { 2780 alertTimerHash.erase(it); 2781 timer->deleteLater(); 2782 break; 2783 } 2784 ++it; 2785 } 2786 if (alertTimerHash.isEmpty()) { 2787 qt_mac_cancel_notification(); 2788 } 2789 } 2790} 2791 2792void QApplication::setCursorFlashTime(int msecs) 2793{ 2794 QApplicationPrivate::cursor_flash_time = msecs; 2795} 2796 2797int QApplication::cursorFlashTime() 2798{ 2799 return QApplicationPrivate::cursor_flash_time; 2800} 2801 2802void QApplication::setDoubleClickInterval(int ms) 2803{ 2804 qt_mac_dblclick.use_qt_time_limit = true; 2805 QApplicationPrivate::mouse_double_click_time = ms; 2806} 2807 2808int QApplication::doubleClickInterval() 2809{ 2810 if (!qt_mac_dblclick.use_qt_time_limit) { //get it from the system 2811 QSettings appleSettings(QLatin1String("apple.com")); 2812 /* First worked as of 10.3.3 */ 2813 double dci = appleSettings.value(QLatin1String("com/apple/mouse/doubleClickThreshold"), 0.5).toDouble(); 2814 return int(dci * 1000); 2815 } 2816 return QApplicationPrivate::mouse_double_click_time; 2817} 2818 2819void QApplication::setKeyboardInputInterval(int ms) 2820{ 2821 QApplicationPrivate::keyboard_input_time = ms; 2822} 2823 2824int QApplication::keyboardInputInterval() 2825{ 2826 // FIXME: get from the system 2827 return QApplicationPrivate::keyboard_input_time; 2828} 2829 2830#ifndef QT_NO_WHEELEVENT 2831void QApplication::setWheelScrollLines(int n) 2832{ 2833 QApplicationPrivate::wheel_scroll_lines = n; 2834} 2835 2836int QApplication::wheelScrollLines() 2837{ 2838 return QApplicationPrivate::wheel_scroll_lines; 2839} 2840#endif 2841 2842void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) 2843{ 2844 switch (effect) { 2845 case Qt::UI_FadeMenu: 2846 QApplicationPrivate::fade_menu = enable; 2847 break; 2848 case Qt::UI_AnimateMenu: 2849 QApplicationPrivate::animate_menu = enable; 2850 break; 2851 case Qt::UI_FadeTooltip: 2852 QApplicationPrivate::fade_tooltip = enable; 2853 break; 2854 case Qt::UI_AnimateTooltip: 2855 QApplicationPrivate::animate_tooltip = enable; 2856 break; 2857 case Qt::UI_AnimateCombo: 2858 QApplicationPrivate::animate_combo = enable; 2859 break; 2860 case Qt::UI_AnimateToolBox: 2861 QApplicationPrivate::animate_toolbox = enable; 2862 break; 2863 case Qt::UI_General: 2864 QApplicationPrivate::fade_tooltip = true; 2865 break; 2866 default: 2867 QApplicationPrivate::animate_ui = enable; 2868 break; 2869 } 2870 2871 if (enable) 2872 QApplicationPrivate::animate_ui = true; 2873} 2874 2875bool QApplication::isEffectEnabled(Qt::UIEffect effect) 2876{ 2877 if (QColormap::instance().depth() < 16 || !QApplicationPrivate::animate_ui) 2878 return false; 2879 2880 switch(effect) { 2881 case Qt::UI_AnimateMenu: 2882 return QApplicationPrivate::animate_menu; 2883 case Qt::UI_FadeMenu: 2884 return QApplicationPrivate::fade_menu; 2885 case Qt::UI_AnimateCombo: 2886 return QApplicationPrivate::animate_combo; 2887 case Qt::UI_AnimateTooltip: 2888 return QApplicationPrivate::animate_tooltip; 2889 case Qt::UI_FadeTooltip: 2890 return QApplicationPrivate::fade_tooltip; 2891 case Qt::UI_AnimateToolBox: 2892 return QApplicationPrivate::animate_toolbox; 2893 default: 2894 break; 2895 } 2896 return QApplicationPrivate::animate_ui; 2897} 2898 2899/*! 2900 \internal 2901*/ 2902bool QApplicationPrivate::qt_mac_apply_settings() 2903{ 2904 QSettings settings(QSettings::UserScope, QLatin1String("Trolltech")); 2905 settings.beginGroup(QLatin1String("Qt")); 2906 2907 /* 2908 Qt settings. This is how they are written into the datastream. 2909 Palette/ * - QPalette 2910 font - QFont 2911 libraryPath - QStringList 2912 style - QString 2913 doubleClickInterval - int 2914 cursorFlashTime - int 2915 wheelScrollLines - int 2916 colorSpec - QString 2917 defaultCodec - QString 2918 globalStrut/width - int 2919 globalStrut/height - int 2920 GUIEffects - QStringList 2921 Font Substitutions/ * - QStringList 2922 Font Substitutions/... - QStringList 2923 */ 2924 2925 // read library (ie. plugin) path list 2926 QString libpathkey = 2927 QString::fromLatin1("%1.%2/libraryPath") 2928 .arg(QT_VERSION >> 16) 2929 .arg((QT_VERSION & 0xff00) >> 8); 2930 QStringList pathlist = settings.value(libpathkey).toString().split(QLatin1Char(':')); 2931 if (!pathlist.isEmpty()) { 2932 QStringList::ConstIterator it = pathlist.begin(); 2933 while(it != pathlist.end()) 2934 QApplication::addLibraryPath(*it++); 2935 } 2936 2937 QString defaultcodec = settings.value(QLatin1String("defaultCodec"), QVariant(QLatin1String("none"))).toString(); 2938 if (defaultcodec != QLatin1String("none")) { 2939 QTextCodec *codec = QTextCodec::codecForName(defaultcodec.toLatin1().constData()); 2940 if (codec) 2941 QTextCodec::setCodecForTr(codec); 2942 } 2943 2944 if (qt_is_gui_used) { 2945 QString str; 2946 QStringList strlist; 2947 int num; 2948 2949 // read new palette 2950 int i; 2951 QPalette pal(QApplication::palette()); 2952 strlist = settings.value(QLatin1String("Palette/active")).toStringList(); 2953 if (strlist.count() == QPalette::NColorRoles) { 2954 for (i = 0; i < QPalette::NColorRoles; i++) 2955 pal.setColor(QPalette::Active, (QPalette::ColorRole) i, 2956 QColor(strlist[i])); 2957 } 2958 strlist = settings.value(QLatin1String("Palette/inactive")).toStringList(); 2959 if (strlist.count() == QPalette::NColorRoles) { 2960 for (i = 0; i < QPalette::NColorRoles; i++) 2961 pal.setColor(QPalette::Inactive, (QPalette::ColorRole) i, 2962 QColor(strlist[i])); 2963 } 2964 strlist = settings.value(QLatin1String("Palette/disabled")).toStringList(); 2965 if (strlist.count() == QPalette::NColorRoles) { 2966 for (i = 0; i < QPalette::NColorRoles; i++) 2967 pal.setColor(QPalette::Disabled, (QPalette::ColorRole) i, 2968 QColor(strlist[i])); 2969 } 2970 2971 if (pal != QApplication::palette()) 2972 QApplication::setPalette(pal); 2973 2974 // read new font 2975 QFont font(QApplication::font()); 2976 str = settings.value(QLatin1String("font")).toString(); 2977 if (!str.isEmpty()) { 2978 font.fromString(str); 2979 if (font != QApplication::font()) 2980 QApplication::setFont(font); 2981 } 2982 2983 // read new QStyle 2984 QString stylename = settings.value(QLatin1String("style")).toString(); 2985 if (! stylename.isNull() && ! stylename.isEmpty()) { 2986 QStyle *style = QStyleFactory::create(stylename); 2987 if (style) 2988 QApplication::setStyle(style); 2989 else 2990 stylename = QLatin1String("default"); 2991 } else { 2992 stylename = QLatin1String("default"); 2993 } 2994 2995 num = settings.value(QLatin1String("doubleClickInterval"), 2996 QApplication::doubleClickInterval()).toInt(); 2997 QApplication::setDoubleClickInterval(num); 2998 2999 num = settings.value(QLatin1String("cursorFlashTime"), 3000 QApplication::cursorFlashTime()).toInt(); 3001 QApplication::setCursorFlashTime(num); 3002 3003#ifndef QT_NO_WHEELEVENT 3004 num = settings.value(QLatin1String("wheelScrollLines"), 3005 QApplication::wheelScrollLines()).toInt(); 3006 QApplication::setWheelScrollLines(num); 3007#endif 3008 3009 QString colorspec = settings.value(QLatin1String("colorSpec"), 3010 QVariant(QLatin1String("default"))).toString(); 3011 if (colorspec == QLatin1String("normal")) 3012 QApplication::setColorSpec(QApplication::NormalColor); 3013 else if (colorspec == QLatin1String("custom")) 3014 QApplication::setColorSpec(QApplication::CustomColor); 3015 else if (colorspec == QLatin1String("many")) 3016 QApplication::setColorSpec(QApplication::ManyColor); 3017 else if (colorspec != QLatin1String("default")) 3018 colorspec = QLatin1String("default"); 3019 3020 int w = settings.value(QLatin1String("globalStrut/width")).toInt(); 3021 int h = settings.value(QLatin1String("globalStrut/height")).toInt(); 3022 QSize strut(w, h); 3023 if (strut.isValid()) 3024 QApplication::setGlobalStrut(strut); 3025 3026 QStringList effects = settings.value(QLatin1String("GUIEffects")).toStringList(); 3027 if (!effects.isEmpty()) { 3028 if (effects.contains(QLatin1String("none"))) 3029 QApplication::setEffectEnabled(Qt::UI_General, false); 3030 if (effects.contains(QLatin1String("general"))) 3031 QApplication::setEffectEnabled(Qt::UI_General, true); 3032 if (effects.contains(QLatin1String("animatemenu"))) 3033 QApplication::setEffectEnabled(Qt::UI_AnimateMenu, true); 3034 if (effects.contains(QLatin1String("fademenu"))) 3035 QApplication::setEffectEnabled(Qt::UI_FadeMenu, true); 3036 if (effects.contains(QLatin1String("animatecombo"))) 3037 QApplication::setEffectEnabled(Qt::UI_AnimateCombo, true); 3038 if (effects.contains(QLatin1String("animatetooltip"))) 3039 QApplication::setEffectEnabled(Qt::UI_AnimateTooltip, true); 3040 if (effects.contains(QLatin1String("fadetooltip"))) 3041 QApplication::setEffectEnabled(Qt::UI_FadeTooltip, true); 3042 if (effects.contains(QLatin1String("animatetoolbox"))) 3043 QApplication::setEffectEnabled(Qt::UI_AnimateToolBox, true); 3044 } else { 3045 QApplication::setEffectEnabled(Qt::UI_General, true); 3046 } 3047 3048 settings.beginGroup(QLatin1String("Font Substitutions")); 3049 QStringList fontsubs = settings.childKeys(); 3050 if (!fontsubs.isEmpty()) { 3051 QStringList::Iterator it = fontsubs.begin(); 3052 for (; it != fontsubs.end(); ++it) { 3053 QString fam = QString::fromLatin1((*it).toLatin1().constData()); 3054 QStringList subs = settings.value(fam).toStringList(); 3055 QFont::insertSubstitutions(fam, subs); 3056 } 3057 } 3058 settings.endGroup(); 3059 } 3060 3061 settings.endGroup(); 3062 return true; 3063} 3064 3065// DRSWAT 3066 3067bool QApplicationPrivate::canQuit() 3068{ 3069#ifndef QT_MAC_USE_COCOA 3070 return true; 3071#else 3072 Q_Q(QApplication); 3073#ifdef QT_MAC_USE_COCOA 3074 [[[NSApplication sharedApplication] mainMenu] cancelTracking]; 3075#else 3076 HiliteMenu(0); 3077#endif 3078 3079 bool handle_quit = true; 3080 if (QApplicationPrivate::modalState() && [[[[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] 3081 menuLoader] quitMenuItem] isEnabled]) { 3082 int visible = 0; 3083 const QWidgetList tlws = QApplication::topLevelWidgets(); 3084 for(int i = 0; i < tlws.size(); ++i) { 3085 if (tlws.at(i)->isVisible()) 3086 ++visible; 3087 } 3088 handle_quit = (visible <= 1); 3089 } 3090 if (handle_quit) { 3091 QCloseEvent ev; 3092 QApplication::sendSpontaneousEvent(q, &ev); 3093 if (ev.isAccepted()) { 3094 return true; 3095 } 3096 } 3097 return false; 3098#endif 3099} 3100 3101void onApplicationWindowChangedActivation(QWidget *widget, bool activated) 3102{ 3103#if QT_MAC_USE_COCOA 3104 if (!widget) 3105 return; 3106 3107 if (activated) { 3108 if (QApplicationPrivate::app_style) { 3109 QEvent ev(QEvent::Style); 3110 qt_sendSpontaneousEvent(QApplicationPrivate::app_style, &ev); 3111 } 3112 qApp->setActiveWindow(widget); 3113 } else { // deactivated 3114 if (QApplicationPrivate::active_window == widget) 3115 qApp->setActiveWindow(0); 3116 } 3117 3118 QMenuBar::macUpdateMenuBar(); 3119 qt_mac_update_cursor(); 3120#else 3121 Q_UNUSED(widget); 3122 Q_UNUSED(activated); 3123#endif 3124} 3125 3126 3127void onApplicationChangedActivation( bool activated ) 3128{ 3129#if QT_MAC_USE_COCOA 3130 QApplication *app = qApp; 3131 3132//NSLog(@"App Changed Activation\n"); 3133 3134 if ( activated ) { 3135 if (QApplication::desktopSettingsAware()) 3136 qt_mac_update_os_settings(); 3137 3138 if (qt_clipboard) { //manufacture an event so the clipboard can see if it has changed 3139 QEvent ev(QEvent::Clipboard); 3140 qt_sendSpontaneousEvent(qt_clipboard, &ev); 3141 } 3142 3143 if (app) { 3144 QEvent ev(QEvent::ApplicationActivate); 3145 qt_sendSpontaneousEvent(app, &ev); 3146 } 3147 3148 if (!app->activeWindow()) { 3149 OSWindowRef wp = [[NSApplication sharedApplication] keyWindow]; 3150 if (QWidget *tmp_w = qt_mac_find_window(wp)) 3151 app->setActiveWindow(tmp_w); 3152 } 3153 QMenuBar::macUpdateMenuBar(); 3154 qt_mac_update_cursor(); 3155 } else { // de-activated 3156 QApplicationPrivate *priv = [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] qAppPrivate]; 3157 if (priv->inPopupMode()) 3158 app->activePopupWidget()->close(); 3159 if (app) { 3160 QEvent ev(QEvent::ApplicationDeactivate); 3161 qt_sendSpontaneousEvent(app, &ev); 3162 } 3163 app->setActiveWindow(0); 3164 } 3165#else 3166 Q_UNUSED(activated); 3167#endif 3168} 3169 3170void QApplicationPrivate::initializeMultitouch_sys() 3171{ } 3172void QApplicationPrivate::cleanupMultitouch_sys() 3173{ } 3174 3175QT_END_NAMESPACE 3176