diff options
Diffstat (limited to 'src/plugins')
47 files changed, 916 insertions, 351 deletions
diff --git a/src/plugins/generic/evdevkeyboard/evdevkeyboard.pro b/src/plugins/generic/evdevkeyboard/evdevkeyboard.pro index 281515145f..101ea30bcc 100644 --- a/src/plugins/generic/evdevkeyboard/evdevkeyboard.pro +++ b/src/plugins/generic/evdevkeyboard/evdevkeyboard.pro @@ -1,6 +1,7 @@ TARGET = qevdevkeyboardplugin PLUGIN_TYPE = generic +PLUGIN_EXTENDS = - PLUGIN_CLASS_NAME = QEvdevKeyboardPlugin load(qt_plugin) diff --git a/src/plugins/generic/evdevmouse/evdevmouse.pro b/src/plugins/generic/evdevmouse/evdevmouse.pro index 9a3cc839cc..57a67ead8d 100644 --- a/src/plugins/generic/evdevmouse/evdevmouse.pro +++ b/src/plugins/generic/evdevmouse/evdevmouse.pro @@ -1,6 +1,7 @@ TARGET = qevdevmouseplugin PLUGIN_TYPE = generic +PLUGIN_EXTENDS = - PLUGIN_CLASS_NAME = QEvdevMousePlugin load(qt_plugin) diff --git a/src/plugins/generic/evdevtablet/evdevtablet.pro b/src/plugins/generic/evdevtablet/evdevtablet.pro index ee3fbb3ec1..8ffc0db84d 100644 --- a/src/plugins/generic/evdevtablet/evdevtablet.pro +++ b/src/plugins/generic/evdevtablet/evdevtablet.pro @@ -1,6 +1,7 @@ TARGET = qevdevtabletplugin PLUGIN_TYPE = generic +PLUGIN_EXTENDS = - PLUGIN_CLASS_NAME = QEvdevTabletPlugin load(qt_plugin) diff --git a/src/plugins/generic/evdevtouch/evdevtouch.pro b/src/plugins/generic/evdevtouch/evdevtouch.pro index 3d1c481c36..1f4d1b7e93 100644 --- a/src/plugins/generic/evdevtouch/evdevtouch.pro +++ b/src/plugins/generic/evdevtouch/evdevtouch.pro @@ -1,6 +1,7 @@ TARGET = qevdevtouchplugin PLUGIN_TYPE = generic +PLUGIN_EXTENDS = - PLUGIN_CLASS_NAME = QEvdevTouchScreenPlugin load(qt_plugin) diff --git a/src/plugins/generic/meego/meego.pro b/src/plugins/generic/meego/meego.pro index c428517cd5..4baaa43a4c 100644 --- a/src/plugins/generic/meego/meego.pro +++ b/src/plugins/generic/meego/meego.pro @@ -1,6 +1,7 @@ TARGET = qmeegointegration PLUGIN_TYPE = generic +PLUGIN_EXTENDS = - PLUGIN_CLASS_NAME = QMeeGoIntegrationPlugin load(qt_plugin) diff --git a/src/plugins/generic/tslib/tslib.pro b/src/plugins/generic/tslib/tslib.pro index 035857bb73..bc05efcc32 100644 --- a/src/plugins/generic/tslib/tslib.pro +++ b/src/plugins/generic/tslib/tslib.pro @@ -1,6 +1,7 @@ TARGET = qtslibplugin PLUGIN_TYPE = generic +PLUGIN_EXTENDS = - PLUGIN_CLASS_NAME = QTsLibPlugin load(qt_plugin) diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro index 7182c458fc..10e50a7a7e 100644 --- a/src/plugins/platforminputcontexts/compose/compose.pro +++ b/src/plugins/platforminputcontexts/compose/compose.pro @@ -1,6 +1,7 @@ TARGET = composeplatforminputcontextplugin PLUGIN_TYPE = platforminputcontexts +PLUGIN_EXTENDS = - PLUGIN_CLASS_NAME = QComposePlatformInputContextPlugin load(qt_plugin) diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp index 8bbb490022..ea0b5261c4 100644 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp @@ -430,8 +430,10 @@ void TableGenerator::parseKeySequence(char *line) elem.keys[i] = XKB_KEY_dead_invertedbreve; else if (!strcmp(sym, "dead_double_grave")) elem.keys[i] = XKB_KEY_dead_doublegrave; +#ifdef DEBUG_GENERATOR else qWarning() << QString("Qt Warning - invalid keysym: %1").arg(sym); +#endif } } else { elem.keys[i] = 0; diff --git a/src/plugins/platforminputcontexts/ibus/ibus.pro b/src/plugins/platforminputcontexts/ibus/ibus.pro index 75a5b5838f..401be6d42f 100644 --- a/src/plugins/platforminputcontexts/ibus/ibus.pro +++ b/src/plugins/platforminputcontexts/ibus/ibus.pro @@ -1,6 +1,7 @@ TARGET = ibusplatforminputcontextplugin PLUGIN_TYPE = platforminputcontexts +PLUGIN_EXTENDS = - PLUGIN_CLASS_NAME = QIbusPlatformInputContextPlugin load(qt_plugin) diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index 9efdcad158..760da7a767 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -47,9 +47,7 @@ #include <QTouchEvent> #include <QPointer> -#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL -# include <QDebug> -#endif +#include <QDebug> using namespace QtAndroid; @@ -277,226 +275,393 @@ namespace QtAndroidInput if (key >= 0x0000001d && key <= 0x00000036) return Qt::Key_A + key - 0x0000001d; + // F1--F12 0x00000083 -- 0x0000008e + if (key >= 0x00000083 && key <= 0x0000008e) + return Qt::Key_F1 + key - 0x00000083; + + // NUMPAD_0--NUMPAD_9 0x00000090 -- 0x00000099 + if (key >= 0x00000090 && key <= 0x00000099) + return Qt::KeypadModifier + Qt::Key_0 + key - 0x00000090; + + // BUTTON_1--KEYCODE_BUTTON_16 0x000000bc -- 0x000000cb + switch (key) { - case 0x00000039: - case 0x0000003a: - return Qt::Key_Alt; + case 0x00000000: // KEYCODE_UNKNOWN + return Qt::Key_unknown; + + case 0x00000001: // KEYCODE_SOFT_LEFT + return Qt::Key_Left; + + case 0x00000002: // KEYCODE_SOFT_RIGHT + return Qt::Key_Right; + + // 0x00000003: // KEYCODE_HOME is never delivered to applications. + + case 0x00000004: // KEYCODE_BACK + return Qt::Key_Back; + + case 0x00000005: // KEYCODE_CALL + return Qt::Key_Call; + + case 0x00000006: // KEYCODE_ENDCALL + return Qt::Key_Hangup; + + // 0--9 0x00000007 -- 0x00000010 + + case 0x00000011: // KEYCODE_STAR + return Qt::Key_Asterisk; + + case 0x00000012: // KEYCODE_POUND + return Qt::Key_NumberSign; + + case 0x00000013: //KEYCODE_DPAD_UP + return Qt::Key_Up; + + case 0x00000014: // KEYCODE_DPAD_DOWN + return Qt::Key_Down; + + case 0x00000015: //KEYCODE_DPAD_LEFT + return Qt::Key_Left; + + case 0x00000016: //KEYCODE_DPAD_RIGHT + return Qt::Key_Right; + + case 0x00000017: // KEYCODE_DPAD_CENTER + return Qt::Key_Enter; + + case 0x00000018: // KEYCODE_VOLUME_UP + return Qt::Key_VolumeUp; + + case 0x00000019: // KEYCODE_VOLUME_DOWN + return Qt::Key_VolumeDown; + + case 0x0000001a: + return Qt::Key_PowerOff; + + case 0x0000001b: // KEYCODE_CAMERA + return Qt::Key_Camera; + + case 0x0000001c: // KEYCODE_CLEAR + return Qt::Key_Clear; + + // A--Z 0x0000001d -- 0x00000036 + + case 0x00000037: // KEYCODE_COMMA + return Qt::Key_Comma; + + case 0x00000038: // KEYCODE_PERIOD + return Qt::Key_Period; + + case 0x00000039: // KEYCODE_ALT_LEFT + case 0x0000003a: // KEYCODE_ALT_RIGHT + return Qt::Key_Alt; + + case 0x0000003b: // KEYCODE_SHIFT_LEFT + case 0x0000003c: // KEYCODE_SHIFT_RIGHT + return Qt::Key_Shift; + + case 0x0000003d: // KEYCODE_TAB + return Qt::Key_Tab; + + case 0x0000003e: // KEYCODE_SPACE + return Qt::Key_Space; + + case 0x0000003f: // KEYCODE_SYM + return Qt::Key_Meta; + + case 0x00000040: // KEYCODE_EXPLORER + return Qt::Key_Explorer; + + case 0x00000041: //KEYCODE_ENVELOPE + return Qt::Key_LaunchMail; + + case 0x00000042: // KEYCODE_ENTER + return Qt::Key_Return; + + case 0x00000043: // KEYCODE_DEL + return Qt::Key_Backspace; + + case 0x00000044: // KEYCODE_GRAVE + return Qt::Key_QuoteLeft; + + case 0x00000045: // KEYCODE_MINUS + return Qt::Key_Minus; + + case 0x00000046: // KEYCODE_EQUALS + return Qt::Key_Equal; + + case 0x00000047: // KEYCODE_LEFT_BRACKET + return Qt::Key_BracketLeft; + + case 0x00000048: // KEYCODE_RIGHT_BRACKET + return Qt::Key_BracketRight; + + case 0x00000049: // KEYCODE_BACKSLASH + return Qt::Key_Backslash; + + case 0x0000004a: // KEYCODE_SEMICOLON + return Qt::Key_Semicolon; + + case 0x0000004b: // KEYCODE_APOSTROPHE + return Qt::Key_Apostrophe; + + case 0x0000004c: // KEYCODE_SLASH + return Qt::Key_Slash; + + case 0x0000004d: // KEYCODE_AT + return Qt::Key_At; + + case 0x0000004e: // KEYCODE_NUM + return Qt::Key_Alt; + + case 0x0000004f: // KEYCODE_HEADSETHOOK + return 0; + + case 0x00000050: // KEYCODE_FOCUS + return Qt::Key_CameraFocus; + + case 0x00000051: // KEYCODE_PLUS + return Qt::Key_Plus; + + case 0x00000052: // KEYCODE_MENU + return Qt::Key_Menu; + + case 0x00000053: // KEYCODE_NOTIFICATION + return 0; - case 0x0000004b: - return Qt::Key_Apostrophe; + case 0x00000054: // KEYCODE_SEARCH + return Qt::Key_Search; - case 0x00000004: // KEYCODE_BACK - return Qt::Key_Back; + case 0x00000055: // KEYCODE_MEDIA_PLAY_PAUSE + return Qt::Key_MediaPlay; - case 0x00000049: - return Qt::Key_Backslash; + case 0x00000056: // KEYCODE_MEDIA_STOP + return Qt::Key_MediaStop; - case 0x00000005: - return Qt::Key_Call; + case 0x00000057: // KEYCODE_MEDIA_NEXT + return Qt::Key_MediaNext; - case 0x0000001b: // KEYCODE_CAMERA - return Qt::Key_Camera; + case 0x00000058: // KEYCODE_MEDIA_PREVIOUS + return Qt::Key_MediaPrevious; - case 0x0000001c: - return Qt::Key_Clear; + case 0x00000059: // KEYCODE_MEDIA_REWIND + return Qt::Key_AudioRewind; - case 0x00000037: - return Qt::Key_Comma; + case 0x0000005a: // KEYCODE_MEDIA_FAST_FORWARD + return Qt::Key_AudioForward; - case 0x00000043: // KEYCODE_DEL - return Qt::Key_Backspace; + case 0x0000005b: // KEYCODE_MUTE + return Qt::Key_MicMute; - case 0x00000017: // KEYCODE_DPAD_CENTER - return Qt::Key_Enter; + case 0x0000005c: // KEYCODE_PAGE_UP + return Qt::Key_PageUp; - case 0x00000014: // KEYCODE_DPAD_DOWN - return Qt::Key_Down; + case 0x0000005d: // KEYCODE_PAGE_DOWN + return Qt::Key_PageDown; - case 0x00000015: //KEYCODE_DPAD_LEFT - return Qt::Key_Left; + case 0x0000005e: // KEYCODE_PICTSYMBOLS + return 0; - case 0x00000016: //KEYCODE_DPAD_RIGHT - return Qt::Key_Right; + case 0x00000060: // KEYCODE_BUTTON_A + case 0x00000061: // KEYCODE_BUTTON_B + case 0x00000062: // KEYCODE_BUTTON_B + case 0x00000063: // KEYCODE_BUTTON_X + case 0x00000064: // KEYCODE_BUTTON_Y + case 0x00000065: // KEYCODE_BUTTON_Z + case 0x00000066: // KEYCODE_BUTTON_L1 + case 0x00000067: // KEYCODE_BUTTON_R1 + case 0x00000068: // KEYCODE_BUTTON_L2 + case 0x00000069: // KEYCODE_BUTTON_R2 + case 0x0000006a: // KEYCODE_BUTTON_THUMBL + case 0x0000006b: // KEYCODE_BUTTON_THUMBR + case 0x0000006c: // KEYCODE_BUTTON_START + case 0x0000006d: // KEYCODE_BUTTON_SELECT + case 0x0000006e: // KEYCODE_BUTTON_MODE + return 0; - case 0x00000013: //KEYCODE_DPAD_UP - return Qt::Key_Up; + case 0x0000006f: // KEYCODE_ESCAPE + return Qt::Key_Escape; - case 0x00000006: //KEYCODE_ENDCALL - return Qt::Key_Hangup; + case 0x00000070: // KEYCODE_FORWARD_DEL + return Qt::Key_Delete; - case 0x00000042: - return Qt::Key_Return; + case 0x00000071: // KEYCODE_CTRL_LEFT + case 0x00000072: // KEYCODE_CTRL_RIGHT + return Qt::Key_Control; - case 0x00000041: //KEYCODE_ENVELOPE - return Qt::Key_LaunchMail; + case 0x00000073: // KEYCODE_CAPS_LOCK + return Qt::Key_CapsLock; - case 0x00000046: - return Qt::Key_Equal; + case 0x00000074: // KEYCODE_SCROLL_LOCK + return Qt::Key_ScrollLock; - case 0x00000040: - return Qt::Key_Explorer; + case 0x00000075: // KEYCODE_META_LEFT + case 0x00000076: // KEYCODE_META_RIGHT + return Qt::Key_Meta; - case 0x00000003: - return Qt::Key_Home; + case 0x00000077: // KEYCODE_FUNCTION + return 0; - case 0x00000047: - return Qt::Key_BracketLeft; + case 0x00000078: // KEYCODE_SYSRQ + return Qt::Key_Print; - case 0x0000005a: // KEYCODE_MEDIA_FAST_FORWARD - return Qt::Key_AudioForward; + case 0x00000079: // KEYCODE_BREAK + return Qt::Key_Pause; - case 0x00000057: - return Qt::Key_MediaNext; + case 0x0000007a: // KEYCODE_MOVE_HOME + return Qt::Key_Home; - case 0x00000055: - return Qt::Key_MediaPlay; + case 0x0000007b: // KEYCODE_MOVE_END + return Qt::Key_End; - case 0x00000058: - return Qt::Key_MediaPrevious; + case 0x0000007c: // KEYCODE_MOVE_INSERT + return Qt::Key_Insert; - case 0x00000059: // KEYCODE_MEDIA_REWIND - return Qt::Key_AudioRewind; + case 0x0000007d: // KEYCODE_FORWARD + return Qt::Key_Forward; - case 0x00000056: - return Qt::Key_MediaStop; + case 0x0000007e: // KEYCODE_MEDIA_PLAY + return Qt::Key_MediaPlay; - case 0x00000052: //KEYCODE_MENU - return Qt::Key_Menu; + case 0x0000007f: // KEYCODE_MEDIA_PAUSE + return Qt::Key_MediaPause; - case 0x00000045: - return Qt::Key_Minus; + case 0x00000080: // KEYCODE_MEDIA_CLOSE + case 0x00000081: // KEYCODE_MEDIA_EJECT + return Qt::Key_Eject; - case 0x0000005b: // KEYCODE_MUTE - return Qt::Key_MicMute; + case 0x00000082: // KEYCODE_MEDIA_RECORD + return Qt::Key_MediaRecord; - case 0x0000004e: - return Qt::Key_NumLock; + // F1--F12 0x00000083 -- 0x0000008e - case 0x00000038: - return Qt::Key_Period; + case 0x0000008f: // KEYCODE_NUM_LOCK + return Qt::Key_NumLock; - case 0x00000051: - return Qt::Key_Plus; + // NUMPAD_0--NUMPAD_9 0x00000090 -- 0x00000099 - case 0x0000001a: - return Qt::Key_PowerOff; + case 0x0000009a: // KEYCODE_NUMPAD_DIVIDE + return Qt::KeypadModifier + Qt::Key_Slash; - case 0x00000048: - return Qt::Key_BracketRight; + case 0x0000009b: // KEYCODE_NUMPAD_MULTIPLY + return Qt::KeypadModifier + Qt::Key_Asterisk; - case 0x00000054: - return Qt::Key_Search; + case 0x0000009c: // KEYCODE_NUMPAD_SUBTRACT + return Qt::KeypadModifier + Qt::Key_Minus; - case 0x0000004a: - return Qt::Key_Semicolon; + case 0x0000009d: // KEYCODE_NUMPAD_ADD + return Qt::KeypadModifier + Qt::Key_Plus; - case 0x0000003b: - case 0x0000003c: - return Qt::Key_Shift; + case 0x0000009e: // KEYCODE_NUMPAD_DOT + return Qt::KeypadModifier + Qt::Key_Period; - case 0x0000004c: - return Qt::Key_Slash; + case 0x0000009f: // KEYCODE_NUMPAD_COMMA + return Qt::KeypadModifier + Qt::Key_Comma; - case 0x00000001: - return Qt::Key_Left; + case 0x000000a0: // KEYCODE_NUMPAD_ENTER + return Qt::Key_Enter; - case 0x00000002: - return Qt::Key_Right; + case 0x000000a1: // KEYCODE_NUMPAD_EQUALS + return Qt::KeypadModifier + Qt::Key_Equal; - case 0x0000003e: - return Qt::Key_Space; + case 0x000000a2: // KEYCODE_NUMPAD_LEFT_PAREN + return Qt::Key_ParenLeft; - case 0x0000003f: // KEYCODE_SYM - return Qt::Key_Meta; + case 0x000000a3: // KEYCODE_NUMPAD_RIGHT_PAREN + return Qt::Key_ParenRight; - case 0x0000003d: - return Qt::Key_Tab; + case 0x000000a4: // KEYCODE_VOLUME_MUTE + return Qt::Key_VolumeMute; - case 0x00000019: - return Qt::Key_VolumeDown; + case 0x000000a5: // KEYCODE_INFO + return Qt::Key_Info; - case 0x000000a4: // KEYCODE_VOLUME_MUTE - return Qt::Key_VolumeMute; + case 0x000000a6: // KEYCODE_CHANNEL_UP + return Qt::Key_ChannelUp; - case 0x00000018: - return Qt::Key_VolumeUp; + case 0x000000a7: // KEYCODE_CHANNEL_DOWN + return Qt::Key_ChannelDown; - case 0x00000011: // KEYCODE_STAR - return Qt::Key_Asterisk; + case 0x000000a8: // KEYCODE_ZOOM_IN + return Qt::Key_ZoomIn; - case 0x00000012: // KEYCODE_POUND - return Qt::Key_NumberSign; + case 0x000000a9: // KEYCODE_ZOOM_OUT + return Qt::Key_ZoomOut; - case 0x00000050: // KEYCODE_FOCUS - return Qt::Key_CameraFocus; + case 0x000000aa: // KEYCODE_TV + case 0x000000ab: // KEYCODE_WINDOW + return 0; - case 0x00000070: // KEYCODE_FORWARD_DEL - return Qt::Key_Delete; + case 0x000000ac: // KEYCODE_GUIDE + return Qt::Key_Guide; - case 0x00000080: // KEYCODE_MEDIA_CLOSE - return Qt::Key_Close; + case 0x000000ad: // KEYCODE_DVR + return 0; - case 0x00000081: // KEYCODE_MEDIA_EJECT - return Qt::Key_Eject; + case 0x000000ae: // KEYCODE_BOOKMARK + return Qt::Key_AddFavorite; - case 0x00000082: // KEYCODE_MEDIA_RECORD - return Qt::Key_MediaRecord; + case 0x000000af: // KEYCODE_CAPTIONS + return Qt::Key_Subtitle; - case 0x000000b7: // KEYCODE_PROG_RED - return Qt::Key_Red; + case 0x000000b0: // KEYCODE_SETTINGS + return Qt::Key_Settings; - case 0x000000b8: // KEYCODE_PROG_GREEN - return Qt::Key_Green; + case 0x000000b1: // KEYCODE_TV_POWER + case 0x000000b2: // KEYCODE_TV_INPUT + case 0x000000b3: // KEYCODE_STB_POWER + case 0x000000b4: // KEYCODE_STB_INPUT + case 0x000000b5: // KEYCODE_AVR_POWER + case 0x000000b6: // KEYCODE_AVR_INPUT + return 0; - case 0x000000b9: // KEYCODE_PROG_YELLOW - return Qt::Key_Yellow; + case 0x000000b7: // KEYCODE_PROG_RED + return Qt::Key_Red; - case 0x000000ba: // KEYCODE_PROG_BLUE - return Qt::Key_Blue; + case 0x000000b8: // KEYCODE_PROG_GREEN + return Qt::Key_Green; - case 0x000000a5: // KEYCODE_INFO - return Qt::Key_Info; + case 0x000000b9: // KEYCODE_PROG_YELLOW + return Qt::Key_Yellow; - case 0x000000a6: // KEYCODE_CHANNEL_UP - return Qt::Key_ChannelUp; + case 0x000000ba: // KEYCODE_PROG_BLUE + return Qt::Key_Blue; - case 0x000000a7: // KEYCODE_CHANNEL_DOWN - return Qt::Key_ChannelDown; + // 0x000000bb: // KEYCODE_APP_SWITCH is not sent by the Android O.S. - case 0x000000a8: // KEYCODE_ZOOM_IN - return Qt::Key_ZoomIn; + // BUTTON_1--KEYCODE_BUTTON_16 0x000000bc -- 0x000000cb - case 0x000000a9: // KEYCODE_ZOOM_OUT - return Qt::Key_ZoomOut; + case 0x000000cc: // KEYCODE_LANGUAGE_SWITCH + case 0x000000cd: // KEYCODE_MANNER_MODE do we need such a thing? + case 0x000000ce: // KEYCODE_3D_MODE + case 0x000000cf: // KEYCODE_CONTACTS + return 0; - case 0x000000ac: // KEYCODE_GUIDE - return Qt::Key_Guide; + case 0x000000d0: // KEYCODE_CALENDAR + return Qt::Key_Calendar; - case 0x000000af: // KEYCODE_CAPTIONS - return Qt::Key_Subtitle; + case 0x000000d1: // KEYCODE_MUSIC + return Qt::Key_Music; - case 0x000000b0: // KEYCODE_SETTINGS - return Qt::Key_Settings; + case 0x000000d2: // KEYCODE_CALCULATOR + return Qt::Key_Calculator; - case 0x000000d0: // KEYCODE_CALENDAR - return Qt::Key_Calendar; + // 0x000000d3 -- 0x000000da some japanese specific keys, someone who understand what is about should check ! - case 0x000000d1: // KEYCODE_MUSIC - return Qt::Key_Music; + // 0x000000db: // KEYCODE_ASSIST not delivered to applications. - case 0x000000d2: // KEYCODE_CALCULATOR - return Qt::Key_Calculator; + case 0x000000dc: // KEYCODE_BRIGHTNESS_DOWN + return Qt::Key_KeyboardBrightnessDown; - case 0x00000000: // KEYCODE_UNKNOWN - return Qt::Key_unknown; + case 0x000000dd: // KEYCODE_BRIGHTNESS_UP + return Qt::Key_KeyboardBrightnessUp; - case 0x00000053: // KEYCODE_NOTIFICATION ?!?!? - case 0x0000004f: // KEYCODE_HEADSETHOOK ?!?!? - case 0x00000044: // KEYCODE_GRAVE ?!?!? - return Qt::Key_Any; + case 0x000000de: // KEYCODE_MEDIA_AUDIO_TRACK + return Qt::Key_AudioCycleTrack; - default: - return 0; + default: + qWarning() << "Unhandled key code " << key << "!"; + return 0; } } diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp index 289480c625..152a06c99d 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp @@ -71,7 +71,8 @@ bool QAndroidPlatformOpenGLContext::needsFBOReadBackWorkaroud() const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER)); needsWorkaround = qstrcmp(rendererString, "Mali-400 MP") == 0 - || qstrcmp(rendererString, "Adreno (TM) 200") == 0; + || qstrcmp(rendererString, "Adreno (TM) 200") == 0 + || qstrcmp(rendererString, "GC1000 core") == 0; set = true; } diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp index 1fe80b28b1..8fc8b312f5 100644 --- a/src/plugins/platforms/cocoa/messages.cpp +++ b/src/plugins/platforms/cocoa/messages.cpp @@ -90,6 +90,14 @@ QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption) || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Exit"), Qt::CaseInsensitive)) { return QPlatformMenuItem::QuitRole; } + if (!caption.compare(QCoreApplication::translate("QCocoaMenuItem", "Cut"), Qt::CaseInsensitive)) + return QPlatformMenuItem::CutRole; + if (!caption.compare(QCoreApplication::translate("QCocoaMenuItem", "Copy"), Qt::CaseInsensitive)) + return QPlatformMenuItem::CopyRole; + if (!caption.compare(QCoreApplication::translate("QCocoaMenuItem", "Paste"), Qt::CaseInsensitive)) + return QPlatformMenuItem::PasteRole; + if (!caption.compare(QCoreApplication::translate("QCocoaMenuItem", "Select All"), Qt::CaseInsensitive)) + return QPlatformMenuItem::SelectAllRole; return QPlatformMenuItem::NoRole; } diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h index 86bb5323a7..a78901bfb1 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h @@ -79,7 +79,7 @@ namespace QCocoaAccessible { NSString *macRole(QAccessibleInterface *interface); bool shouldBeIgnored(QAccessibleInterface *interface); -NSArray *unignoredChildren(id parentObject, QAccessibleInterface *interface); +NSArray *unignoredChildren(QAccessibleInterface *interface); NSString *getTranslatedAction(const QString &qtAction); NSMutableArray *createTranslatedActionsList(const QStringList &qtActions); QString translateAction(NSString *nsAction); diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 990acd5301..72045a1bbb 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -55,19 +55,31 @@ QCocoaAccessibility::~QCocoaAccessibility() void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) { - QAccessible::Id interfaceId = event->uniqueId(); - if (!interfaceId) + QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: event->uniqueId()]; + if (!element) { + qWarning() << "QCocoaAccessibility::notifyAccessibilityUpdate: invalid element"; return; + } switch (event->type()) { - case QAccessible::ValueChanged: - case QAccessible::TextInserted : - case QAccessible::TextRemoved : - case QAccessible::TextUpdated : { - QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId : interfaceId parent : nil]; - [element autorelease]; - NSAccessibilityPostNotification(element, NSAccessibilityValueChangedNotification); - break; } + case QAccessible::Focus: { + NSAccessibilityPostNotification(element, NSAccessibilityFocusedUIElementChangedNotification); + break; + } + case QAccessible::StateChanged: + case QAccessible::ValueChanged: + case QAccessible::TextInserted: + case QAccessible::TextRemoved: + case QAccessible::TextUpdated: + NSAccessibilityPostNotification(element, NSAccessibilityValueChangedNotification); + break; + case QAccessible::TextCaretMoved: + case QAccessible::TextSelectionChanged: + NSAccessibilityPostNotification(element, NSAccessibilitySelectedTextChangedNotification); + break; + case QAccessible::NameChanged: + NSAccessibilityPostNotification(element, NSAccessibilityTitleChangedNotification); + break; default: break; } @@ -218,7 +230,7 @@ bool shouldBeIgnored(QAccessibleInterface *interface) return false; } -NSArray *unignoredChildren(id parentObject, QAccessibleInterface *interface) +NSArray *unignoredChildren(QAccessibleInterface *interface) { int numKids = interface->childCount(); // qDebug() << "Children for: " << axid << iface << " are: " << numKids; @@ -231,9 +243,12 @@ NSArray *unignoredChildren(id parentObject, QAccessibleInterface *interface) QAccessible::Id childId = QAccessible::uniqueId(child); //qDebug() << " kid: " << childId << child; - QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId:childId parent:parentObject]; - [kids addObject: element]; - [element release]; + + QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: childId]; + if (element) + [kids addObject: element]; + else + qWarning() << "QCocoaAccessibility: invalid child"; } return NSAccessibilityUnignoredChildren(kids); } diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h index c207cbee2d..babaab5ae2 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h @@ -52,12 +52,11 @@ @interface QCocoaAccessibleElement : NSObject { NSString *role; - NSObject *parent; QAccessible::Id axid; } -- (id)initWithId:(QAccessible::Id)anId parent:(id)aParent; -+ (QCocoaAccessibleElement *)createElementWithId:(QAccessible::Id)anId parent:(id)aParent; +- (id)initWithId:(QAccessible::Id)anId; ++ (QCocoaAccessibleElement *)elementWithId:(QAccessible::Id)anId; @end diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 0b674b8d2f..1df4230385 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -41,6 +41,8 @@ #include "qcocoaaccessibilityelement.h" #include "qcocoaaccessibility.h" #include "qcocoahelpers.h" +#include "qcocoawindow.h" +#include "private/qaccessiblecache_p.h" #include <QtGui/qaccessible.h> @@ -48,7 +50,7 @@ @implementation QCocoaAccessibleElement -- (id)initWithId:(QAccessible::Id)anId parent:(id)aParent +- (id)initWithId:(QAccessible::Id)anId { Q_ASSERT((int)anId < 0); self = [super init]; @@ -57,15 +59,35 @@ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); Q_ASSERT(iface); role = QCocoaAccessible::macRole(iface); - parent = aParent; } return self; } -+ (QCocoaAccessibleElement *)createElementWithId:(QAccessible::Id)anId parent:(id)aParent ++ (id)elementWithId:(QAccessible::Id)anId { - return [[self alloc] initWithId:anId parent:aParent]; + Q_ASSERT(anId); + if (!anId) + return nil; + + QAccessibleCache *cache = QAccessibleCache::instance(); + + QCocoaAccessibleElement *element = cache->elementForId(anId); + if (!element) { + QAccessibleInterface *iface = QAccessible::accessibleInterface(anId); + Q_ASSERT(iface); + if (!iface) + return nil; + element = [[self alloc] initWithId:anId]; + cache->insertElement(anId, element); + } + return element; +} + +- (void)invalidate { + axid = 0; + NSAccessibilityPostNotification(self, NSAccessibilityUIElementDestroyedNotification); + [self release]; } - (void)dealloc { @@ -98,6 +120,10 @@ return [NSNumber numberWithInt: newlines]; } +- (BOOL) accessibilityNotifiesWhenDestroyed { + return YES; +} + - (NSArray *)accessibilityAttributeNames { static NSArray *defaultAttributes = nil; @@ -116,6 +142,7 @@ NSAccessibilityTopLevelUIElementAttribute, NSAccessibilityPositionAttribute, NSAccessibilitySizeAttribute, + NSAccessibilityTitleAttribute, NSAccessibilityDescriptionAttribute, NSAccessibilityEnabledAttribute, nil]; @@ -144,6 +171,26 @@ return [attributes autorelease]; } +- (id)parentElement { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface) + return nil; + + if (QWindow *window = iface->window()) { + QCocoaWindow *win = static_cast<QCocoaWindow*>(window->handle()); + return win->qtView(); + } + + QAccessibleInterface *parent = iface->parent(); + if (!parent) { + qWarning() << "INVALID PARENT FOR INTERFACE: " << iface; + return nil; + } + + QAccessible::Id parentId = QAccessible::uniqueId(parent); + return [QCocoaAccessibleElement elementWithId: parentId]; +} + - (id)accessibilityAttributeValue:(NSString *)attribute { QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (!iface) { @@ -156,19 +203,19 @@ } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { return NSAccessibilityRoleDescription(role, nil); } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { - return QCocoaAccessible::unignoredChildren(self, iface); + return QCocoaAccessible::unignoredChildren(iface); } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { // Just check if the app thinks we're focused. id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute]; return [NSNumber numberWithBool:[focusedElement isEqual:self]]; } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) { - return NSAccessibilityUnignoredAncestor(parent); + return NSAccessibilityUnignoredAncestor([self parentElement]); } else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) { // We're in the same window as our parent. - return [parent accessibilityAttributeValue:NSAccessibilityWindowAttribute]; + return [[self parentElement] accessibilityAttributeValue:NSAccessibilityWindowAttribute]; } else if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) { // We're in the same top level element as our parent. - return [parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute]; + return [[self parentElement] accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute]; } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) { QPoint qtPosition = iface->rect().topLeft(); QSize qtSize = iface->rect().size(); @@ -176,8 +223,10 @@ } else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) { QSize qtSize = iface->rect().size(); return [NSValue valueWithSize: NSMakeSize(qtSize.width(), qtSize.height())]; - } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) { + } else if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) { return QCFString::toNSString(iface->text(QAccessible::Name)); + } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) { + return QCFString::toNSString(iface->text(QAccessible::Description)); } else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) { return [NSNumber numberWithBool:!iface->state().disabled]; } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { @@ -400,20 +449,26 @@ return NSAccessibilityUnignoredAncestor(self); } - QAccessibleInterface *childInterface = iface->childAt(point.x, qt_mac_flipYCoordinate(point.y)); - + int y = qt_mac_flipYCoordinate(point.y); + QAccessibleInterface *childInterface = iface->childAt(point.x, y); // No child found, meaning we hit this element. - if (!childInterface) { -// qDebug() << "Hit test returns: " << id << iface; + if (!childInterface) return NSAccessibilityUnignoredAncestor(self); - } + + // find the deepest child at the point + QAccessibleInterface *childOfChildInterface = 0; + do { + childOfChildInterface = childInterface->childAt(point.x, y); + if (childOfChildInterface) + childInterface = childOfChildInterface; + } while (childOfChildInterface); QAccessible::Id childId = QAccessible::uniqueId(childInterface); // hit a child, forward to child accessible interface. - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childId parent:self]; - [accessibleElement autorelease]; - - return [accessibleElement accessibilityHitTest:point]; + QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childId]; + if (accessibleElement) + return NSAccessibilityUnignoredAncestor(accessibleElement); + return NSAccessibilityUnignoredAncestor(self); } - (id)accessibilityFocusedUIElement { @@ -423,17 +478,15 @@ qWarning() << "FocusedUIElement for INVALID"; return nil; } + QAccessibleInterface *childInterface = iface->focusChild(); if (childInterface) { QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); - // FIXME: parent could be wrong - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self]; - [accessibleElement autorelease]; - return accessibleElement; + QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childAxid]; + return NSAccessibilityUnignoredAncestor(accessibleElement); } - // no focus found - return nil; + return NSAccessibilityUnignoredAncestor(self); } @end diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index 592bfc8e50..b81b9a0b1c 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -308,8 +308,7 @@ NSCursor *QCocoaCursor::createCursorFromBitmap(const QBitmap *bitmap, const QBit NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap pixmap, const QPoint hotspot) { - NSPoint hotSpot = NSMakePoint(hotspot.x() / pixmap.devicePixelRatio(), - hotspot.y() / pixmap.devicePixelRatio()); + NSPoint hotSpot = NSMakePoint(hotspot.x(), hotspot.y()); NSImage *nsimage; if (pixmap.devicePixelRatio() > 1.0) { QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio(); diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 8728ab8764..2b7b8109ad 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -52,6 +52,7 @@ #include <private/qguiapplication_p.h> #include "qt_mac_p.h" #include "qcocoahelpers.h" +#include "qcocoamenubar.h" #include <qregexp.h> #include <qbuffer.h> #include <qdebug.h> @@ -225,6 +226,7 @@ static QString strippedText(QString s) || [self panel:nil shouldShowFilename:filepath]; [self updateProperties]; + QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder(); [mOpenPanel setAllowedFileTypes:nil]; [mSavePanel setNameFieldStringValue:selectable ? QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.fileName()) : @""]; @@ -250,7 +252,9 @@ static QString strippedText(QString s) // cleanup of modal sessions. Do this before showing the native dialog, otherwise it will // close down during the cleanup. qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers); + QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder(); mReturnCode = [mSavePanel runModal]; + QCocoaMenuBar::resetKnownMenuItemsToQt(); QAbstractEventDispatcher::instance()->interrupt(); return (mReturnCode == NSOKButton); @@ -269,6 +273,7 @@ static QString strippedText(QString s) || [self panel:nil shouldShowFilename:filepath]; [self updateProperties]; + QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder(); [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]]; [mSavePanel setNameFieldStringValue:selectable ? QCFString::toNSString(info.fileName()) : @""]; @@ -583,6 +588,7 @@ void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QSt void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted) { + QCocoaMenuBar::resetKnownMenuItemsToQt(); if (accepted) { emit accept(); } else { diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index a73944c07c..9850f83dea 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -74,7 +74,7 @@ void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list) { NSMutableArray *result = [NSMutableArray arrayWithCapacity:list.size()]; for (int i=0; i<list.size(); ++i){ - [result addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(list[i]))]; + [result addObject:list[i].toNSString()]; } return result; } diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 24adc7a95b..9c4f86d893 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -80,6 +80,7 @@ public: qreal refreshRate() const { return m_refreshRate; } QString name() const { return m_name; } QPlatformCursor *cursor() const { return m_cursor; } + QWindow *topLevelAt(const QPoint &point) const; QList<QPlatformScreen *> virtualSiblings() const { return m_siblings; } // ---------------------------------------------------- @@ -138,6 +139,8 @@ public: void setToolbar(QWindow *window, NSToolbar *toolbar); NSToolbar *toolbar(QWindow *window) const; void clearToolbars(); + void setWindow(NSWindow* nsWindow, QCocoaWindow *window); + QCocoaWindow *window(NSWindow *window); private: static QCocoaIntegration *mInstance; @@ -156,6 +159,7 @@ private: QScopedPointer<QCocoaKeyMapper> mKeyboardMapper; QHash<QWindow *, NSToolbar *> mToolbars; + QHash<NSWindow *, QCocoaWindow*> mWindows; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 412818ae47..c4398622e8 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -81,12 +81,16 @@ QCocoaScreen::~QCocoaScreen() NSScreen *QCocoaScreen::osScreen() const { - return [[NSScreen screens] objectAtIndex:m_screenIndex]; + NSArray *screens = [NSScreen screens]; + return ((NSUInteger)m_screenIndex < [screens count]) ? [screens objectAtIndex:m_screenIndex] : nil; } void QCocoaScreen::updateGeometry() { NSScreen *nsScreen = osScreen(); + if (!nsScreen) + return; + NSRect frameRect = [nsScreen frame]; if (m_screenIndex == 0) { @@ -143,7 +147,8 @@ qreal QCocoaScreen::devicePixelRatio() const { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - return qreal([osScreen() backingScaleFactor]); + NSScreen * screen = osScreen(); + return qreal(screen ? [screen backingScaleFactor] : 1.0); } else #endif { @@ -151,6 +156,24 @@ qreal QCocoaScreen::devicePixelRatio() const } } +QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const +{ + // Get a z-ordered list of windows. Iterate through it until + // we find a window which contains the point. + for (NSWindow *nsWindow in [NSApp orderedWindows]) { + QCocoaWindow *cocoaWindow = QCocoaIntegration::instance()->window(nsWindow); + if (!cocoaWindow) + continue; + QWindow *window = cocoaWindow->window(); + if (!window->isTopLevel()) + continue; + if (window->geometry().contains(point)) + return window; + } + + return QPlatformScreen::topLevelAt(point); +} + extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const @@ -495,6 +518,16 @@ NSToolbar *QCocoaIntegration::toolbar(QWindow *window) const return mToolbars.value(window); } +void QCocoaIntegration::setWindow(NSWindow* nsWindow, QCocoaWindow *window) +{ + mWindows.insert(nsWindow, window); +} + +QCocoaWindow *QCocoaIntegration::window(NSWindow *window) +{ + return mWindows.value(window); +} + void QCocoaIntegration::clearToolbars() { QHash<QWindow *, NSToolbar *>::const_iterator it = mToolbars.constBegin(); diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 35e8fdebb4..6acc062eb9 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -269,7 +269,6 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem * QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem); QCocoaMenuItem *beforeItem = static_cast<QCocoaMenuItem *>(before); - SET_COCOA_MENU_ANCESTOR(menuItem, this); cocoaItem->sync(); if (beforeItem) { int index = m_menuItems.indexOf(beforeItem); @@ -315,6 +314,7 @@ void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem) } else { [m_nativeMenu addItem: item->nsItem()]; } + SET_COCOA_MENU_ANCESTOR(item, this); } void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem) diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h index 7a1bda74a4..fa02a7870b 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.h +++ b/src/plugins/platforms/cocoa/qcocoamenubar.h @@ -67,9 +67,13 @@ public: inline NSMenu *nsMenu() const { return m_nativeMenu; } + static void redirectKnownMenuItemsToFirstResponder(); + static void resetKnownMenuItemsToQt(); static void updateMenuBarImmediately(); QList<QCocoaMenuItem*> merged() const; + NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole r); + private: static QCocoaWindow *findWindowForMenubar(); static QCocoaMenuBar *findGlobalMenubar(); diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index 7335deb800..ffc0fabdce 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -205,6 +205,59 @@ QCocoaMenuBar *QCocoaMenuBar::findGlobalMenubar() return NULL; } +void QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder() +{ + // QTBUG-17291: http://forums.macrumors.com/showthread.php?t=1249452 + // When a dialog is opened, shortcuts for actions inside the dialog (cut, paste, ...) + // continue to go through the same menu items which claimed those shortcuts. + // They are not keystrokes which we can intercept in any other way; the OS intercepts them. + // The menu items had to be created by the application. That's why we need roles + // to identify those "special" menu items which can be useful even when non-Qt + // native widgets are in focus. When the native widget is focused it will be the + // first responder, so the menu item needs to have its target be the first responder; + // this is done by setting it to nil. + + // This function will find all menu items on all menus which have + // "special" roles, set the target and also set the standard actions which + // apply to those roles. But afterwards it is necessary to call + // resetKnownMenuItemsToQt() to put back the target and action so that + // those menu items will go back to invoking their associated QActions. + foreach (QCocoaMenuBar *mb, static_menubars) + foreach (QCocoaMenu *m, mb->m_menus) + foreach (QCocoaMenuItem *i, m->items()) { + bool known = true; + switch (i->effectiveRole()) { + case QPlatformMenuItem::CutRole: + [i->nsItem() setAction:@selector(cut:)]; + break; + case QPlatformMenuItem::CopyRole: + [i->nsItem() setAction:@selector(copy:)]; + break; + case QPlatformMenuItem::PasteRole: + [i->nsItem() setAction:@selector(paste:)]; + break; + case QPlatformMenuItem::SelectAllRole: + [i->nsItem() setAction:@selector(selectAll:)]; + break; + // We may discover later that there are other roles/actions which + // are meaningful to standard native widgets; they can be added. + default: + known = false; + break; + } + if (known) + [i->nsItem() setTarget:nil]; + } +} + +void QCocoaMenuBar::resetKnownMenuItemsToQt() +{ + // Undo the effect of redirectKnownMenuItemsToFirstResponder(): + // set the menu items' actions to itemFired and their targets to + // the QCocoaMenuDelegate. + updateMenuBarImmediately(); +} + void QCocoaMenuBar::updateMenuBarImmediately() { QCocoaAutoReleasePool pool; @@ -321,3 +374,13 @@ QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const return 0; } + +NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole r) +{ + foreach (QCocoaMenu *m, m_menus) + foreach (QCocoaMenuItem *i, m->items()) + if (i->effectiveRole() == r) + return i->nsItem(); + return Q_NULLPTR; +} + diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h index b0169b9746..61706c19bc 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.h +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h @@ -98,6 +98,8 @@ public: inline bool isSeparator() const { return m_isSeparator; } QCocoaMenu *menu() const { return m_menu; } + MenuRole effectiveRole() const; + private: QString mergeText(); QKeySequence mergeAccel(); @@ -112,6 +114,7 @@ private: bool m_isSeparator; QFont m_font; MenuRole m_role; + MenuRole m_detectedRole; QKeySequence m_shortcut; bool m_checked; bool m_merged; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 2246d2ce46..58fe07bc62 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -227,7 +227,8 @@ NSMenuItem *QCocoaMenuItem::sync() if (depth == 3 || !menubar) break; // Menu item too deep in the hierarchy, or not connected to any menubar - switch (detectMenuRole(m_text)) { + m_detectedRole = detectMenuRole(m_text); + switch (m_detectedRole) { case QPlatformMenuItem::AboutRole: if (m_text.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1) mergeItem = [loader aboutMenuItem]; @@ -241,6 +242,8 @@ NSMenuItem *QCocoaMenuItem::sync() mergeItem = [loader quitMenuItem]; break; default: + if (m_detectedRole >= CutRole && m_detectedRole < RoleCount && menubar) + mergeItem = menubar->itemForRole(m_detectedRole); if (!m_text.isEmpty()) m_textSynced = true; break; @@ -249,7 +252,7 @@ NSMenuItem *QCocoaMenuItem::sync() } default: - qWarning() << Q_FUNC_INFO << "unsupported role" << (int) m_role; + qWarning() << Q_FUNC_INFO << "menu item" << m_text << "has unsupported role" << (int)m_role; } if (mergeItem) { @@ -374,3 +377,11 @@ void QCocoaMenuItem::syncModalState(bool modal) else [m_native setEnabled:m_enabled]; } + +QPlatformMenuItem::MenuRole QCocoaMenuItem::effectiveRole() const +{ + if (m_role > TextHeuristicRole) + return m_role; + else + return m_detectedRole; +} diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index 29fc0fb674..60bc3b5a55 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -115,14 +115,13 @@ QT_END_NAMESPACE showAllItem = [[appMenu itemWithTitle:@"Show All"] retain]; // Get the names in the nib to match the app name set by Qt. - const NSString *appName = reinterpret_cast<const NSString*>(QCFString::toCFStringRef(qt_mac_applicationName())); + const NSString *appName = qt_mac_applicationName().toNSString(); [quitItem setTitle:[[quitItem title] stringByReplacingOccurrencesOfString:@"NewApplication" withString:const_cast<NSString *>(appName)]]; [hideItem setTitle:[[hideItem title] stringByReplacingOccurrencesOfString:@"NewApplication" withString:const_cast<NSString *>(appName)]]; [aboutItem setTitle:[[aboutItem title] stringByReplacingOccurrencesOfString:@"NewApplication" withString:const_cast<NSString *>(appName)]]; - [appName release]; // Disable the items that don't do anything. If someone associates a QAction with them // They should get synced back in. [preferencesItem setEnabled:NO]; diff --git a/src/plugins/platforms/cocoa/qcocoamimetypes.mm b/src/plugins/platforms/cocoa/qcocoamimetypes.mm index 05d4c19112..8151d31449 100644 --- a/src/plugins/platforms/cocoa/qcocoamimetypes.mm +++ b/src/plugins/platforms/cocoa/qcocoamimetypes.mm @@ -136,9 +136,76 @@ QList<QByteArray> QMacPasteboardMimeTiff::convertFromMime(const QString &mime, Q return ret; } +// This handler is special: It supports converting public.rtf top text/html, +// but not the other way around. +class QMacPasteboardMimeRtfText : public QMacInternalPasteboardMime { +public: + QMacPasteboardMimeRtfText() : QMacInternalPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeRtfText::convertorName() +{ + return QLatin1String("Rtf"); +} + +QString QMacPasteboardMimeRtfText::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("text/html")) + return QLatin1String("public.rtf"); + return QString(); +} + +QString QMacPasteboardMimeRtfText::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.rtf")) + return QLatin1String("text/html"); + return QString(); +} + +bool QMacPasteboardMimeRtfText::canConvert(const QString &mime, QString flav) +{ + return flavorFor(mime) == flav; +} + +QVariant QMacPasteboardMimeRtfText::convertToMime(const QString &mimeType, QList<QByteArray> data, QString flavor) +{ + if (!canConvert(mimeType, flavor)) + return QVariant(); + if (data.count() > 1) + qWarning("QMacPasteboardMimeHTMLText: Cannot handle multiple member data"); + + // Convert Rtf to Html. + NSAttributedString *string = [[NSAttributedString alloc] initWithRTF:data.at(0).toNSData() documentAttributes:NULL]; + NSError *error; + NSRange range = NSMakeRange(0,[string length]); + NSDictionary *dict = [NSDictionary dictionaryWithObject:NSHTMLTextDocumentType forKey:NSDocumentTypeDocumentAttribute]; + NSData *htmldata = [string dataFromRange:range documentAttributes:dict error:&error]; + [string release]; + return QByteArray::fromNSData(htmldata); +} + +QList<QByteArray> QMacPasteboardMimeRtfText::convertFromMime(const QString &mime, QVariant data, QString flavor) +{ + Q_UNUSED(mime); + Q_UNUSED(data); + Q_UNUSED(flavor); + + qWarning("QMacPasteboardMimeRtfText: Conversion from Html to Rtf is not supported"); + QList<QByteArray> ret; + return ret; +} + void QCocoaMimeTypes::initializeMimeTypes() { new QMacPasteboardMimeTiff; + new QMacPasteboardMimeRtfText; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index efdd433d8f..54e45a1d99 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -133,16 +133,23 @@ private: // deregisters. static void registerTouchWindow(QWindow *window, bool enable); - // Request a unified title and toolbar look for the window. + // Enable the unified title and toolbar area for a window. + static void setContentBorderEnabled(QWindow *window, bool enable); + + // Set the size of the unified title and toolbar area. static void setContentBorderThickness(QWindow *window, int topThickness, int bottomThickness); - // Request a unified title and toolbar look for the window by registering - // an area. Multiple callers can register areas and the platform plugin + // Set the size for a unified toolbar content border area. + // Multiple callers can register areas and the platform plugin // will extend the "unified" area to cover them. static void registerContentBorderArea(QWindow *window, quintptr identifer, int upper, int lower); - // Enable the unified title and toolbar area. - static void enableContentBorderArea(QWindow *window, bool enable); + // Enables or disiables a content border area. + static void setContentBorderAreaEnabled(QWindow *window, quintptr identifier, bool enable); + + // Returns true if the given coordinate is inside the current + // content border. + static bool testContentBorderPosition(QWindow *window, int position); // Sets a NSToolbar instance for the given QWindow. The // toolbar will be attached to the native NSWindow when diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index d6a5be8d52..e09c31231d 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -127,10 +127,14 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderThickness); if (resource.toLower() == "registercontentborderarea") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerContentBorderArea); - if (resource.toLower() == "enablecontentborderarea") - return NativeResourceForIntegrationFunction(QCocoaNativeInterface::enableContentBorderArea); + if (resource.toLower() == "setcontentborderareaenabled") + return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderAreaEnabled); + if (resource.toLower() == "setcontentborderenabled") + return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderEnabled); if (resource.toLower() == "setnstoolbar") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setNSToolbar); + if (resource.toLower() == "testcontentborderposition") + return NativeResourceForIntegrationFunction(QCocoaNativeInterface::testContentBorderPosition); return 0; } @@ -301,14 +305,24 @@ void QCocoaNativeInterface::registerContentBorderArea(QWindow *window, quintptr cocoaWindow->registerContentBorderArea(identifier, upper, lower); } -void QCocoaNativeInterface::enableContentBorderArea(QWindow *window, bool enable) +void QCocoaNativeInterface::setContentBorderAreaEnabled(QWindow *window, quintptr identifier, bool enable) { if (!window) return; QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); if (cocoaWindow) - cocoaWindow->enableContentBorderArea(enable); + cocoaWindow->setContentBorderAreaEnabled(identifier, enable); +} + +void QCocoaNativeInterface::setContentBorderEnabled(QWindow *window, bool enable) +{ + if (!window) + return; + + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); + if (cocoaWindow) + cocoaWindow->setContentBorderEnabled(enable); } void QCocoaNativeInterface::setNSToolbar(QWindow *window, void *nsToolbar) @@ -320,4 +334,15 @@ void QCocoaNativeInterface::setNSToolbar(QWindow *window, void *nsToolbar) cocoaWindow->updateNSToolbar(); } +bool QCocoaNativeInterface::testContentBorderPosition(QWindow *window, int position) +{ + if (!window) + return false; + + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); + if (cocoaWindow) + return cocoaWindow->testContentBorderAreaPosition(position); + return false; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm index 3061e84470..57d5c800e0 100644 --- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm +++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm @@ -171,15 +171,18 @@ QPrint::DeviceState QCocoaPrintDevice::state() const QPageSize QCocoaPrintDevice::createPageSize(const PMPaper &paper) const { - QCFString key; + CFStringRef key; double width; double height; - QCFString localizedName; + CFStringRef localizedName; if (PMPaperGetPPDPaperName(paper, &key) == noErr && PMPaperGetWidth(paper, &width) == noErr && PMPaperGetHeight(paper, &height) == noErr && PMPaperCreateLocalizedName(paper, m_printer, &localizedName) == noErr) { - return(QPlatformPrintDevice::createPageSize(key, QSize(width, height), localizedName)); + QPageSize pageSize = QPlatformPrintDevice::createPageSize(QString::fromCFString(key),QSize(width, height), + QString::fromCFString(localizedName)); + CFRelease(localizedName); + return pageSize; } return QPageSize(); } @@ -216,10 +219,11 @@ QPageSize QCocoaPrintDevice::defaultPageSize() const QPageSize pageSize; PMPageFormat pageFormat; PMPaper paper; - if (PMCreatePageFormat(&pageFormat) == noErr - && PMSessionDefaultPageFormat(m_session, pageFormat) == noErr - && PMGetPageFormatPaper(pageFormat, &paper) == noErr) { - pageSize = createPageSize(paper); + if (PMCreatePageFormat(&pageFormat) == noErr) { + if (PMSessionDefaultPageFormat(m_session, pageFormat) == noErr + && PMGetPageFormatPaper(pageFormat, &paper) == noErr) { + pageSize = createPageSize(paper); + } PMRelease(pageFormat); } return pageSize; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index b7a6a14d4a..bb5c0c1974 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -211,7 +211,9 @@ public: void registerTouch(bool enable); void setContentBorderThickness(int topThickness, int bottomThickness); void registerContentBorderArea(quintptr identifier, int upper, int lower); - void enableContentBorderArea(bool enable); + void setContentBorderAreaEnabled(quintptr identifier, bool enable); + void setContentBorderEnabled(bool enable); + bool testContentBorderAreaPosition(int position) const; void applyContentBorderThickness(NSWindow *window); void updateNSToolbar(); @@ -270,6 +272,7 @@ public: // for QNSView bool m_geometryUpdateExposeAllowed; bool m_isExposed; QRect m_exposedGeometry; + qreal m_exposedDevicePixelRatio; int m_registerTouchCount; bool m_resizableTransientParent; bool m_hiddenByClipping; @@ -289,7 +292,8 @@ public: // for QNSView NSApplicationPresentationOptions m_presentationOptions; struct BorderRange { - BorderRange(int u, int l) : upper(u), lower(l) { } + BorderRange(quintptr i, int u, int l) : identifier(i), upper(u), lower(l) { } + quintptr identifier; int upper; int lower; bool operator<(BorderRange const& right) const { @@ -297,6 +301,7 @@ public: // for QNSView } }; QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower + QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index b27e1b03db..5def64ee0a 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -261,6 +261,8 @@ static bool isMouseEvent(NSEvent *ev) { [self close]; + QCocoaIntegration::instance()->setWindow(self, 0); + if (self.helper.grabbingMouse) { self.helper.releaseOnMouseUp = YES; } else { @@ -327,6 +329,7 @@ static bool isMouseEvent(NSEvent *ev) { [self.helper detachFromPlatformWindow]; [self close]; + QCocoaIntegration::instance()->setWindow(self, 0); [self release]; } @@ -619,11 +622,13 @@ void QCocoaWindow::setVisible(bool visible) // update the window geometry if there is a parent. setGeometry(window()->geometry()); - // Register popup windows so that the parent window can - // close them when needed. - if (window()->type() == Qt::Popup) { + // Register popup windows so that the parent window can close them when needed. + if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip) { // qDebug() << "transientParent and popup" << window()->type() << Qt::Popup << (window()->type() & Qt::Popup); parentCocoaWindow->m_activePopupWindow = window(); + } + + if (window()->type() == Qt::Popup) { // QTBUG-30266: a window should not be resizable while a transient popup is open // Since this isn't a native popup, the window manager doesn't close the popup when you click outside NSUInteger parentStyleMask = [parentCocoaWindow->m_nsWindow styleMask]; @@ -1210,11 +1215,18 @@ QCocoaGLContext *QCocoaWindow::currentContext() const void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) { bool wasNSWindowChild = m_isNSWindowChild; - // TODO Set value for m_isNSWindowChild here + m_isNSWindowChild = parentWindow && (window()->property("_q_platform_MacUseNSWindow").toBool()); bool needsNSWindow = m_isNSWindowChild || !parentWindow; QCocoaWindow *oldParentCocoaWindow = m_parentCocoaWindow; m_parentCocoaWindow = const_cast<QCocoaWindow *>(static_cast<const QCocoaWindow *>(parentWindow)); + if (m_parentCocoaWindow && m_isNSWindowChild) { + QWindow *parentQWindow = m_parentCocoaWindow->window(); + if (!parentQWindow->property("_q_platform_MacUseNSWindow").toBool()) { + parentQWindow->setProperty("_q_platform_MacUseNSWindow", QVariant(true)); + m_parentCocoaWindow->recreateWindow(m_parentCocoaWindow->m_parentCocoaWindow); + } + } bool usesNSPanel = [m_nsWindow isKindOfClass:[QNSPanel class]]; @@ -1400,6 +1412,8 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow() applyContentBorderThickness(createdWindow); + QCocoaIntegration::instance()->setWindow(createdWindow, this); + return createdWindow; } @@ -1466,7 +1480,7 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized) || (m_effectivelyMaximized && newState == Qt::WindowNoState)) { if ((m_synchedWindowState & Qt::WindowFullScreen) == (newState & Qt::WindowFullScreen)) { - [m_nsWindow performZoom : m_nsWindow]; // toggles + [m_nsWindow zoom : m_nsWindow]; // toggles m_effectivelyMaximized = !m_effectivelyMaximized; } else if (!(newState & Qt::WindowMaximized)) { // it would be nice to change the target geometry that toggleFullScreen will animate toward @@ -1582,28 +1596,17 @@ void QCocoaWindow::setContentBorderThickness(int topThickness, int bottomThickne void QCocoaWindow::registerContentBorderArea(quintptr identifier, int upper, int lower) { - m_contentBorderAreas.insert(identifier, BorderRange(upper, lower)); - - // Find consecutive registered border areas, starting from the top. - QList<BorderRange> ranges = m_contentBorderAreas.values(); - std::sort(ranges.begin(), ranges.end()); - m_topContentBorderThickness = 0; - foreach (BorderRange range, ranges) { - // Is this sub-range adjacent to or overlaping the - // existing total border area range? If so merge - // it into the total range, - if (range.upper <= (m_topContentBorderThickness + 1)) - m_topContentBorderThickness = qMax(m_topContentBorderThickness, range.lower); - else - break; - } + m_contentBorderAreas.insert(identifier, BorderRange(identifier, upper, lower)); + applyContentBorderThickness(m_nsWindow); +} - m_bottomContentBorderThickness = 0; // (not supported) - if (m_drawContentBorderGradient) - applyContentBorderThickness(m_nsWindow); +void QCocoaWindow::setContentBorderAreaEnabled(quintptr identifier, bool enable) +{ + m_enabledContentBorderAreas.insert(identifier, enable); + applyContentBorderThickness(m_nsWindow); } -void QCocoaWindow::enableContentBorderArea(bool enable) +void QCocoaWindow::setContentBorderEnabled(bool enable) { m_drawContentBorderGradient = enable; applyContentBorderThickness(m_nsWindow); @@ -1619,17 +1622,33 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window) return; } - [window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask]; + // Find consecutive registered border areas, starting from the top. + QList<BorderRange> ranges = m_contentBorderAreas.values(); + std::sort(ranges.begin(), ranges.end()); + int effectiveTopContentBorderThickness = m_topContentBorderThickness; + foreach (BorderRange range, ranges) { + // Skip disiabled ranges (typically hidden tool bars) + if (!m_enabledContentBorderAreas.value(range.identifier, false)) + continue; - if (m_topContentBorderThickness > 0) { - [window setContentBorderThickness:m_topContentBorderThickness forEdge:NSMaxYEdge]; - [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; + // Is this sub-range adjacent to or overlaping the + // existing total border area range? If so merge + // it into the total range, + if (range.upper <= (effectiveTopContentBorderThickness + 1)) + effectiveTopContentBorderThickness = qMax(effectiveTopContentBorderThickness, range.lower); + else + break; } - if (m_bottomContentBorderThickness > 0) { - [window setContentBorderThickness:m_topContentBorderThickness forEdge:NSMinYEdge]; - [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMinYEdge]; - } + int effectiveBottomContentBorderThickness = m_bottomContentBorderThickness; + + [window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask]; + + [window setContentBorderThickness:effectiveTopContentBorderThickness forEdge:NSMaxYEdge]; + [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; + + [window setContentBorderThickness:effectiveBottomContentBorderThickness forEdge:NSMinYEdge]; + [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMinYEdge]; } void QCocoaWindow::updateNSToolbar() @@ -1646,6 +1665,12 @@ void QCocoaWindow::updateNSToolbar() [m_nsWindow setShowsToolbarButton:YES]; } +bool QCocoaWindow::testContentBorderAreaPosition(int position) const +{ + return m_nsWindow && m_drawContentBorderGradient && + 0 <= position && position < [m_nsWindow contentBorderThicknessForEdge: NSMaxYEdge]; +} + qreal QCocoaWindow::devicePixelRatio() const { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 @@ -1685,6 +1710,7 @@ void QCocoaWindow::exposeWindow() if (!m_isExposed) { m_isExposed = true; m_exposedGeometry = geometry(); + m_exposedDevicePixelRatio = devicePixelRatio(); QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); } } @@ -1710,11 +1736,12 @@ void QCocoaWindow::updateExposedGeometry() if (!isWindowExposable()) return; - if (m_exposedGeometry == geometry()) + if (m_exposedGeometry == geometry() && m_exposedDevicePixelRatio == devicePixelRatio()) return; m_isExposed = true; m_exposedGeometry = geometry(); + m_exposedDevicePixelRatio = devicePixelRatio(); QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); } diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index 9368b65866..6549f127b6 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -305,6 +305,11 @@ QMacPasteboard::setMimeData(QMimeData *mime_src) QString mimeType = formats.at(f); for (QList<QMacInternalPasteboardMime *>::Iterator it = availableConverters.begin(); it != availableConverters.end(); ++it) { QMacInternalPasteboardMime *c = (*it); + // Hack: The Rtf handler converts incoming Rtf to Html. We do + // not want to convert outgoing Html to Rtf but instead keep + // posting it as Html. Skip the Rtf handler here. + if (c->convertorName() == QStringLiteral("Rtf")) + continue; QString flavor(c->flavorFor(mimeType)); if (!flavor.isEmpty()) { QVariant mimeData = static_cast<QMacMimeData*>(mime_src)->variantData(mimeType); diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 1197aa9148..0b9683a3ef 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -329,6 +329,7 @@ static QTouchDevice *touchDevice = 0; if (m_window) { NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen]; if (screenIndex != NSNotFound) { + m_platformWindow->updateExposedGeometry(); QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex); QWindowSystemInterface::handleWindowScreenChanged(m_window, cocoaScreen->screen()); } @@ -371,8 +372,9 @@ static QTouchDevice *touchDevice = 0; { m_backingStore = backingStore; m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio(); - QRect br = region.boundingRect(); - [self setNeedsDisplayInRect:NSMakeRect(br.x(), br.y(), br.width(), br.height())]; + foreach (QRect rect, region.rects()) { + [self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())]; + } } - (BOOL) hasMask @@ -1647,6 +1649,21 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) } } +static QWindow *findEventTargetWindow(QWindow *candidate) +{ + while (candidate) { + if (!(candidate->flags() & Qt::WindowTransparentForInput)) + return candidate; + candidate = candidate->parent(); + } + return candidate; +} + +static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint point) +{ + return target->mapFromGlobal(source->mapToGlobal(point)); +} + - (NSDragOperation) draggingSourceOperationMaskForLocal:(BOOL)isLocal { Q_UNUSED(isLocal); @@ -1676,16 +1693,18 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) QPoint qt_windowPoint(windowPoint.x, windowPoint.y); Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]); + QWindow *target = findEventTargetWindow(m_window); + // update these so selecting move/copy/link works QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]]; QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect()); if ([sender draggingSource] != nil) { QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); - response = QWindowSystemInterface::handleDrag(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed); + response = QWindowSystemInterface::handleDrag(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed); } else { QCocoaDropData mimeData([sender draggingPasteboard]); - response = QWindowSystemInterface::handleDrag(m_window, &mimeData, qt_windowPoint, qtAllowed); + response = QWindowSystemInterface::handleDrag(target, &mimeData, mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed); } return qt_mac_mapDropAction(response.acceptedAction()); @@ -1693,16 +1712,20 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)draggingExited:(id <NSDraggingInfo>)sender { + QWindow *target = findEventTargetWindow(m_window); + NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; QPoint qt_windowPoint(windowPoint.x, windowPoint.y); // Send 0 mime data to indicate drag exit - QWindowSystemInterface::handleDrag(m_window, 0 ,qt_windowPoint, Qt::IgnoreAction); + QWindowSystemInterface::handleDrag(target, 0, mapWindowCoordinates(m_window, target, qt_windowPoint), Qt::IgnoreAction); } // called on drop, send the drop to Qt and return if it was accepted. - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender { + QWindow *target = findEventTargetWindow(m_window); + NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; QPoint qt_windowPoint(windowPoint.x, windowPoint.y); Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]); @@ -1710,10 +1733,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) QPlatformDropQtResponse response(false, Qt::IgnoreAction); if ([sender draggingSource] != nil) { QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); - response = QWindowSystemInterface::handleDrop(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed); + response = QWindowSystemInterface::handleDrop(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed); } else { QCocoaDropData mimeData([sender draggingPasteboard]); - response = QWindowSystemInterface::handleDrop(m_window, &mimeData, qt_windowPoint, qtAllowed); + response = QWindowSystemInterface::handleDrop(target, &mimeData, mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed); } if (response.isAccepted()) { QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); @@ -1726,6 +1749,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) { Q_UNUSED(img); Q_UNUSED(operation); + QWindow *target = findEventTargetWindow(m_window); // keep our state, and QGuiApplication state (buttons member) in-sync, // or future mouse events will be processed incorrectly @@ -1738,7 +1762,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) NSPoint screenPoint = [window convertBaseToScreen :point]; QPoint qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y)); - QWindowSystemInterface::handleMouseEvent(m_window, qtWindowPoint, qtScreenPoint, m_buttons); + QWindowSystemInterface::handleMouseEvent(target, mapWindowCoordinates(m_window, target, qtWindowPoint), qtScreenPoint, m_buttons); } @end diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index 31e3e343b9..d18a01b11c 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -59,8 +59,7 @@ return nil; QAccessible::Id childId = QAccessible::uniqueId(m_window->accessibleRoot()); - QCocoaAccessibleElement *child = [QCocoaAccessibleElement createElementWithId: childId parent: self]; - return [child autorelease]; + return [QCocoaAccessibleElement elementWithId: childId]; } // The QNSView is a container that the user does not interact directly with: diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp index f1f9f5469c..9d40d166af 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp @@ -81,15 +81,14 @@ QQnxEglWindow::~QQnxEglWindow() void QQnxEglWindow::createEGLSurface() { - // Fetch the surface size from the window and update - // the window's buffers before we create the EGL surface - const QSize surfaceSize = requestedBufferSize(); - if (!surfaceSize.isValid()) { + if (!m_requestedBufferSize.isValid()) { qWarning("QQNX: Trying to create 0 size EGL surface. " "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); return; } - setBufferSize(surfaceSize); + + // update the window's buffers before we create the EGL surface + setBufferSize(m_requestedBufferSize); const EGLint eglSurfaceAttrs[] = { @@ -99,9 +98,10 @@ void QQnxEglWindow::createEGLSurface() qEglWindowDebug() << "Creating EGL surface" << platformOpenGLContext()->getEglDisplay() << platformOpenGLContext()->getEglConfig(); + // Create EGL surface - m_eglSurface = eglCreateWindowSurface(platformOpenGLContext()->getEglDisplay() - , platformOpenGLContext()->getEglConfig(), + m_eglSurface = eglCreateWindowSurface(platformOpenGLContext()->getEglDisplay(), + platformOpenGLContext()->getEglConfig(), (EGLNativeWindowType) nativeHandle(), eglSurfaceAttrs); if (m_eglSurface == EGL_NO_SURFACE) { const EGLenum error = QQnxGLContext::checkEGLError("eglCreateWindowSurface"); @@ -171,11 +171,6 @@ void QQnxEglWindow::setGeometry(const QRect &rect) QQnxWindow::setGeometry(newGeometry); } -QSize QQnxEglWindow::requestedBufferSize() const -{ - return m_requestedBufferSize; -} - void QQnxEglWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext) { // This function does not take ownership of the platform gl context. diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h index a6a223c58e..cd98f9369d 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.h +++ b/src/plugins/platforms/qnx/qqnxeglwindow.h @@ -65,9 +65,6 @@ public: void setGeometry(const QRect &rect); - // Called by QQnxGLContext::createSurface() - QSize requestedBufferSize() const; - protected: int pixelFormat() const; void resetBuffers(); diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 42318729b1..2e0febff20 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -353,37 +353,39 @@ void QQnxWindow::setBufferSize(const QSize &size) { qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "size =" << size; - // Set window buffer size // libscreen fails when creating empty buffers const QSize nonEmptySize = size.isEmpty() ? QSize(1, 1) : size; + int format = pixelFormat(); + + if (nonEmptySize == m_bufferSize || format == -1) + return; + + Q_SCREEN_CRITICALERROR( + screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, &format), + "Failed to set window format"); + + if (m_bufferSize.isValid()) { + // destroy buffers first, if resized + Q_SCREEN_CRITICALERROR(screen_destroy_window_buffers(m_window), + "Failed to destroy window buffers"); + } int val[2] = { nonEmptySize.width(), nonEmptySize.height() }; Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val), "Failed to set window buffer size"); - // Create window buffers if they do not exist - if (m_bufferSize.isEmpty()) { - val[0] = pixelFormat(); - if (val[0] == -1) // The platform GL context was not set yet on the window, so we can't procede - return; - - Q_SCREEN_CRITICALERROR( - screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val), - "Failed to set window format"); + Q_SCREEN_CRITICALERROR(screen_create_window_buffers(m_window, MAX_BUFFER_COUNT), + "Failed to create window buffers"); - Q_SCREEN_CRITICALERROR(screen_create_window_buffers(m_window, MAX_BUFFER_COUNT), - "Failed to create window buffers"); + // check if there are any buffers available + int bufferCount = 0; + Q_SCREEN_CRITICALERROR( + screen_get_window_property_iv(m_window, SCREEN_PROPERTY_RENDER_BUFFER_COUNT, &bufferCount), + "Failed to query render buffer count"); - // check if there are any buffers available - int bufferCount = 0; - Q_SCREEN_CRITICALERROR( - screen_get_window_property_iv(m_window, SCREEN_PROPERTY_RENDER_BUFFER_COUNT, &bufferCount), - "Failed to query render buffer count"); - - if (bufferCount != MAX_BUFFER_COUNT) { - qFatal("QQnxWindow: invalid buffer count. Expected = %d, got = %d. You might experience problems.", - MAX_BUFFER_COUNT, bufferCount); - } + if (bufferCount != MAX_BUFFER_COUNT) { + qFatal("QQnxWindow: invalid buffer count. Expected = %d, got = %d.", + MAX_BUFFER_COUNT, bufferCount); } // Set the transparency. According to QNX technical support, setting the window diff --git a/src/plugins/platforms/windows/qplatformfunctions_wince.h b/src/plugins/platforms/windows/qplatformfunctions_wince.h index 30fc66563e..65ce466086 100644 --- a/src/plugins/platforms/windows/qplatformfunctions_wince.h +++ b/src/plugins/platforms/windows/qplatformfunctions_wince.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -293,8 +293,8 @@ inline void OleUninitialize() inline DWORD GetGlyphOutline( HDC /*hdc*/, UINT /*uChar*/, INT /*fuFormat*/, GLYPHMETRICS * /*lpgm*/, DWORD /*cjBuffer*/, LPVOID /*pvBuffer*/, CONST MAT2 * /*lpmat2*/ ) { - qFatal("GetGlyphOutline not supported under Windows CE. Please try using freetype fontrendering, by" - "passing -platform windows:freetype as arguments to the application."); + qFatal("GetGlyphOutline() not supported under Windows CE. Please try using freetype font-rendering, by " + "passing the command line argument -platform windows:fontengine=freetype to the application."); return GDI_ERROR; } diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index e7e4028079..eaa4eca84e 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -711,6 +711,8 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() minorDot = version.size(); result.version = (version.mid(0, majorDot).toInt() << 8) + version.mid(majorDot + 1, minorDot - majorDot - 1).toInt(); + } else { + result.version = 0x0200; } result.profile = QSurfaceFormat::NoProfile; if (result.version < 0x0300) { diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 1579797f85..57d6bc580b 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -94,14 +94,23 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI , m_gc_window(0) { Q_XCB_NOOP(connection()); - m_xcb_image = xcb_image_create_native(xcb_connection(), - size.width(), - size.height(), - XCB_IMAGE_FORMAT_Z_PIXMAP, - depth, - 0, - ~0, - 0); + + const xcb_setup_t *setup = xcb_get_setup(xcb_connection()); + xcb_format_t *fmt = xcb_setup_pixmap_formats(setup); + xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(setup); + for (; fmt != fmtend; ++fmt) + if (fmt->depth == depth) + break; + + Q_ASSERT(fmt != fmtend); + + m_xcb_image = xcb_image_create(size.width(), size.height(), + XCB_IMAGE_FORMAT_Z_PIXMAP, + fmt->scanline_pad, + fmt->depth, fmt->bits_per_pixel, 0, + QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST : XCB_IMAGE_ORDER_LSB_FIRST, + XCB_IMAGE_ORDER_MSB_FIRST, + 0, ~0, 0); const int segmentSize = m_xcb_image->stride * m_xcb_image->height; if (!segmentSize) @@ -209,10 +218,13 @@ void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &s // at least 16384 bytes. That should be enough for quite large images. Q_ASSERT(rows_per_put > 0); + // Convert the image to the native byte order. + xcb_image_t *converted_image = xcb_image_native(xcb_connection(), m_xcb_image, 1); + while (height > 0) { int rows = std::min(height, rows_per_put); - xcb_image_t *subimage = xcb_image_subimage(m_xcb_image, src_x, src_y, width, rows, + xcb_image_t *subimage = xcb_image_subimage(converted_image, src_x, src_y, width, rows, 0, 0, 0); xcb_image_put(xcb_connection(), window, @@ -228,6 +240,9 @@ void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &s target_y += rows; height -= rows; } + + if (converted_image != m_xcb_image) + xcb_image_destroy(converted_image); } Q_XCB_NOOP(connection()); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 66b8401ea2..f5f6c712c5 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -93,10 +93,37 @@ QT_BEGIN_NAMESPACE #ifdef XCB_USE_XLIB +static const char * const xcbConnectionErrors[] = { + "No error", /* Error 0 */ + "I/O error", /* XCB_CONN_ERROR */ + "Unsupported extension used", /* XCB_CONN_CLOSED_EXT_NOTSUPPORTED */ + "Out of memory", /* XCB_CONN_CLOSED_MEM_INSUFFICIENT */ + "Maximum allowed requested length exceeded", /* XCB_CONN_CLOSED_REQ_LEN_EXCEED */ + "Failed to parse display string", /* XCB_CONN_CLOSED_PARSE_ERR */ + "No such screen on display", /* XCB_CONN_CLOSED_INVALID_SCREEN */ + "Error during FD passing" /* XCB_CONN_CLOSED_FDPASSING_FAILED */ +}; + static int nullErrorHandler(Display *, XErrorEvent *) { return 0; } + +static int ioErrorHandler(Display *dpy) +{ + xcb_connection_t *conn = XGetXCBConnection(dpy); + if (conn != NULL) { + /* Print a message with a textual description of the error */ + int code = xcb_connection_has_error(conn); + const char *str = "Unknown error"; + int arrayLength = sizeof(xcbConnectionErrors) / sizeof(xcbConnectionErrors[0]); + if (code >= 0 && code < arrayLength) + str = xcbConnectionErrors[code]; + + qWarning("The X11 connection broke: %s (code %d)", str, code); + } + return _XDefaultIOError(dpy); +} #endif QXcbScreen* QXcbConnection::findOrCreateScreen(QList<QXcbScreen *>& newScreens, @@ -284,6 +311,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra m_connection = XGetXCBConnection(dpy); XSetEventQueueOwner(dpy, XCBOwnsEventQueue); XSetErrorHandler(nullErrorHandler); + XSetIOErrorHandler(ioErrorHandler); m_xlib_display = dpy; } #else diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 92b24f4722..69601f44d4 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -663,23 +663,17 @@ void QXcbKeyboard::clearXKBConfig() memset(&xkb_names, 0, sizeof(xkb_names)); } -void QXcbKeyboard::printKeymapError(const QString &error) const +void QXcbKeyboard::printKeymapError(const char *error) const { - qWarning() << "Qt: " << error; - // check if XKB config root is a valid path - const QDir xkbRoot = qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT") - ? QString::fromLocal8Bit(qgetenv("QT_XKB_CONFIG_ROOT")) - : DFLT_XKB_CONFIG_ROOT; - if (!xkbRoot.exists() || xkbRoot.dirName() != "xkb") { - qWarning() << "Set QT_XKB_CONFIG_ROOT to provide a valid XKB configuration data path, current search paths: " - << xkbRoot.path() << ". Use ':' as separator to provide several search paths."; - return; + qWarning() << error; + if (xkb_context) { + qWarning() << "Current XKB configuration data search paths are: "; + for (unsigned int i = 0; i < xkb_context_num_include_paths(xkb_context); ++i) + qWarning() << xkb_context_include_path_get(xkb_context, i); } - qWarning() << "_XKB_RULES_NAMES property contains:" << "\nrules : " << xkb_names.rules << - "\nmodel : " << xkb_names.model << "\nlayout : " << xkb_names.layout << - "\nvariant : " << xkb_names.variant << "\noptions : " << xkb_names.options << - "\nIf this looks like a valid keyboard layout information then you might need to " - "update XKB configuration data on the system (http://cgit.freedesktop.org/xkeyboard-config/)."; + qWarning() << "Use QT_XKB_CONFIG_ROOT environmental variable to provide an additional search path, " + "add ':' as separator to provide several search paths and/or make sure that XKB configuration data " + "directory contains recent enough contents, to update please see http://cgit.freedesktop.org/xkeyboard-config/ ."; } void QXcbKeyboard::updateKeymap() @@ -696,7 +690,7 @@ void QXcbKeyboard::updateKeymap() xkb_context = xkb_context_new((xkb_context_flags)0); } if (!xkb_context) { - printKeymapError("Failed to create XKB context!"); + printKeymapError("Qt: Failed to create XKB context!"); m_config = false; return; } @@ -731,8 +725,7 @@ void QXcbKeyboard::updateKeymap() if (xkb_keymap) { new_state = xkb_state_new(xkb_keymap); } else { - // failed to compile from RMLVO, give a verbose error message - printKeymapError("Qt: Failed to compile a keymap!"); + printKeymapError("Failed to compile a keymap!"); m_config = false; return; } @@ -863,7 +856,7 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const return QList<int>(); QList<int> result; - int baseQtKey = keysymToQtKey(sym, modifiers, keysymToUnicode(sym)); + int baseQtKey = keysymToQtKey(sym, modifiers, lookupString(kb_state, event->nativeScanCode())); result += (baseQtKey + modifiers); // The base key is _always_ valid, of course xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(xkb_keymap, "Shift"); @@ -910,7 +903,7 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const continue; Qt::KeyboardModifiers mods = modifiers & ~neededMods; - qtKey = keysymToQtKey(sym, mods, keysymToUnicode(sym)); + qtKey = keysymToQtKey(sym, mods, lookupString(kb_state, event->nativeScanCode())); if (qtKey == baseQtKey) continue; @@ -986,10 +979,10 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) , xkb_context(0) , xkb_keymap(0) , xkb_state(0) - , core_device_id(0) { memset(&xkb_names, 0, sizeof(xkb_names)); #ifndef QT_NO_XKB + core_device_id = 0; if (connection->hasXKB()) { updateVModMapping(); updateVModToRModMapping(); @@ -1326,7 +1319,8 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod } Qt::KeyboardModifiers modifiers = translateModifiers(state); - QString string = keysymToUnicode(sym); + + QString string = lookupString(xkb_state, code); int count = string.size(); string.truncate(count); @@ -1389,16 +1383,12 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod } } -QString QXcbKeyboard::keysymToUnicode(xcb_keysym_t sym) const +QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const { QByteArray chars; - int bytes; - chars.resize(7); - bytes = xkb_keysym_to_utf8(sym, chars.data(), chars.size()); - if (bytes == -1) - qWarning("QXcbKeyboard::handleKeyEvent - buffer too small"); - chars.resize(bytes-1); - + chars.resize(1 + xkb_state_key_get_utf8(state, code, 0, 0)); + // equivalent of XLookupString + xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); return QString::fromUtf8(chars); } diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 36ce1ea2f0..11b7429aca 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -48,10 +48,7 @@ #include <xkbcommon/xkbcommon.h> #ifndef QT_NO_XKB -// note: extern won't be needed from libxkbcommon 0.4.1 and above -extern "C" { #include <xkbcommon/xkbcommon-x11.h> -} #endif #include <QEvent> @@ -79,9 +76,9 @@ public: void updateXKBMods(); quint32 xkbModMask(quint16 state); void updateXKBStateFromCore(quint16 state); +#ifndef QT_NO_XKB // when XKEYBOARD is present on the X server int coreDeviceId() const { return core_device_id; } -#ifndef QT_NO_XKB void updateXKBState(xcb_xkb_state_notify_event_t *state); #endif @@ -89,10 +86,10 @@ protected: void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time); void resolveMaskConflicts(); - QString keysymToUnicode(xcb_keysym_t sym) const; + QString lookupString(struct xkb_state *state, xcb_keycode_t code) const; int keysymToQtKey(xcb_keysym_t keysym) const; int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const; - void printKeymapError(const QString &error) const; + void printKeymapError(const char *error) const; void readXKBConfig(); void clearXKBConfig(); @@ -134,9 +131,11 @@ private: xkb_mod_index_t mod5; }; _xkb_mods xkb_mods; +#ifndef QT_NO_XKB // when XKEYBOARD is present on the X server _mod_masks vmod_masks; int core_device_id; +#endif }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index bed6eb59dc..5a2002f1d4 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1174,7 +1174,7 @@ void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) void QXcbWindow::setTransparentForMouseEvents(bool transparent) { - if (transparent == m_transparent) + if (!connection()->hasXFixes() || transparent == m_transparent) return; xcb_rectangle_t rectangle; diff --git a/src/plugins/platformthemes/gtk2/gtk2.pro b/src/plugins/platformthemes/gtk2/gtk2.pro index bb02192f91..73c156f82b 100644 --- a/src/plugins/platformthemes/gtk2/gtk2.pro +++ b/src/plugins/platformthemes/gtk2/gtk2.pro @@ -1,6 +1,7 @@ TARGET = qgtk2 PLUGIN_TYPE = platformthemes +PLUGIN_EXTENDS = - PLUGIN_CLASS_NAME = QGtk2ThemePlugin load(qt_plugin) |