mirror of https://github.com/procxx/kepka.git
SPMediaKeyTap solution for macOS media keys added.
This commit is contained in:
parent
eb939fa4b0
commit
fd6a312abc
|
@ -34,7 +34,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
|
|||
## Build instructions
|
||||
|
||||
* [Visual Studio 2015][msvc]
|
||||
* [Xcode 7][xcode]
|
||||
* [Xcode 8][xcode]
|
||||
* [GYP/CMake on GNU/Linux][cmake]
|
||||
|
||||
## Projects in Telegram solution
|
||||
|
|
|
@ -0,0 +1,703 @@
|
|||
diff --git a/configure b/configure
|
||||
index cb8d78f..cadb3f0 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -511,7 +511,8 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
- if ! /usr/bin/xcrun -find xcrun >/dev/null 2>&1; then
|
||||
+ # Patch: Fix Qt for working with Xcode 8.
|
||||
+ if ! /usr/bin/xcrun -find xcodebuild >/dev/null 2>&1; then
|
||||
echo >&2
|
||||
echo " Xcode not set up properly. You may need to confirm the license" >&2
|
||||
echo " agreement by running /usr/bin/xcodebuild without arguments." >&2
|
||||
diff --git a/mkspecs/common/g++-macx.conf b/mkspecs/common/g++-macx.conf
|
||||
index 086510d..ae4f81a 100644
|
||||
--- a/mkspecs/common/g++-macx.conf
|
||||
+++ b/mkspecs/common/g++-macx.conf
|
||||
@@ -14,7 +14,8 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2
|
||||
QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2
|
||||
QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO += -g -gdwarf-2
|
||||
|
||||
-QMAKE_LFLAGS_STATIC_LIB += -all_load
|
||||
+# Patch: Don't remember :(
|
||||
+#QMAKE_LFLAGS_STATIC_LIB += -all_load
|
||||
|
||||
QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvmgcc42
|
||||
|
||||
diff --git a/mkspecs/features/mac/default_pre.prf b/mkspecs/features/mac/default_pre.prf
|
||||
index 0cc8cd6..ca9725b 100644
|
||||
--- a/mkspecs/features/mac/default_pre.prf
|
||||
+++ b/mkspecs/features/mac/default_pre.prf
|
||||
@@ -12,7 +12,9 @@ isEmpty(QMAKE_XCODE_DEVELOPER_PATH) {
|
||||
error("Xcode is not installed in $${QMAKE_XCODE_DEVELOPER_PATH}. Please use xcode-select to choose Xcode installation path.")
|
||||
|
||||
# Make sure Xcode is set up properly
|
||||
- isEmpty($$list($$system("/usr/bin/xcrun -find xcrun 2>/dev/null"))): \
|
||||
+
|
||||
+ # Patch: Fix Qt for working with Xcode 8.
|
||||
+ isEmpty($$list($$system("/usr/bin/xcrun -find xcodebuild 2>/dev/null"))): \
|
||||
error("Xcode not set up properly. You may need to confirm the license agreement by running /usr/bin/xcodebuild.")
|
||||
}
|
||||
|
||||
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
|
||||
index bb79a13..5d595bc 100644
|
||||
--- a/src/gui/image/qbmphandler.cpp
|
||||
+++ b/src/gui/image/qbmphandler.cpp
|
||||
@@ -220,6 +220,10 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
|
||||
int blue_scale = 0;
|
||||
int alpha_scale = 0;
|
||||
|
||||
+ // Patch: Backport a fix for bmp reader.
|
||||
+ if (!d->isSequential())
|
||||
+ d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
|
||||
+
|
||||
if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) {
|
||||
if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
|
||||
return false;
|
||||
@@ -307,8 +311,9 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
|
||||
image.setDotsPerMeterX(bi.biXPelsPerMeter);
|
||||
image.setDotsPerMeterY(bi.biYPelsPerMeter);
|
||||
|
||||
- if (!d->isSequential())
|
||||
- d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
|
||||
+ // Patch: Backport a fix for bmp reader.
|
||||
+ //if (!d->isSequential())
|
||||
+ // d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
|
||||
|
||||
if (ncols > 0) { // read color table
|
||||
uchar rgb[4];
|
||||
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
|
||||
index ebff950..4300ca4 100644
|
||||
--- a/src/gui/painting/qpaintengine_p.h
|
||||
+++ b/src/gui/painting/qpaintengine_p.h
|
||||
@@ -87,8 +87,18 @@ public:
|
||||
if (hasSystemTransform) {
|
||||
if (systemTransform.type() <= QTransform::TxTranslate)
|
||||
systemClip.translate(qRound(systemTransform.dx()), qRound(systemTransform.dy()));
|
||||
- else
|
||||
+ // Patch: Transform the system clip region back from device pixels to device-independent pixels before
|
||||
+ // applying systemTransform, which already has transform from device-independent pixels to device pixels.
|
||||
+ else {
|
||||
+#ifdef Q_OS_MAC
|
||||
+ QTransform scaleTransform;
|
||||
+ const qreal invDevicePixelRatio = 1. / pdev->devicePixelRatio();
|
||||
+ scaleTransform.scale(invDevicePixelRatio, invDevicePixelRatio);
|
||||
+ systemClip = systemTransform.map(scaleTransform.map(systemClip));
|
||||
+#else
|
||||
systemClip = systemTransform.map(systemClip);
|
||||
+#endif
|
||||
+ }
|
||||
}
|
||||
|
||||
// Make sure we're inside the viewport.
|
||||
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
|
||||
index 4879ae5..3251354 100644
|
||||
--- a/src/gui/text/qtextlayout.cpp
|
||||
+++ b/src/gui/text/qtextlayout.cpp
|
||||
@@ -654,6 +654,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
|
||||
while (oldPos < len && !attributes[oldPos].graphemeBoundary)
|
||||
oldPos++;
|
||||
} else {
|
||||
+ // Patch: Skip to the end of the current word, not to the start of the next one.
|
||||
+ while (oldPos < len && attributes[oldPos].whiteSpace)
|
||||
+ oldPos++;
|
||||
if (oldPos < len && d->atWordSeparator(oldPos)) {
|
||||
oldPos++;
|
||||
while (oldPos < len && d->atWordSeparator(oldPos))
|
||||
@@ -662,8 +665,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
|
||||
while (oldPos < len && !d->atSpace(oldPos) && !d->atWordSeparator(oldPos))
|
||||
oldPos++;
|
||||
}
|
||||
- while (oldPos < len && d->atSpace(oldPos))
|
||||
- oldPos++;
|
||||
+ // Patch: Skip to the end of the current word, not to the start of the next one.
|
||||
+ //while (oldPos < len && d->atSpace(oldPos))
|
||||
+ // oldPos++;
|
||||
}
|
||||
|
||||
return oldPos;
|
||||
@@ -1602,6 +1606,9 @@ namespace {
|
||||
int currentPosition;
|
||||
glyph_t previousGlyph;
|
||||
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ QFontEngine *previousGlyphFontEngine;
|
||||
+
|
||||
QFixed minw;
|
||||
QFixed softHyphenWidth;
|
||||
QFixed rightBearing;
|
||||
@@ -1634,13 +1641,17 @@ namespace {
|
||||
if (currentPosition > 0 &&
|
||||
logClusters[currentPosition - 1] < glyphs.numGlyphs) {
|
||||
previousGlyph = currentGlyph(); // needed to calculate right bearing later
|
||||
+
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ previousGlyphFontEngine = fontEngine;
|
||||
}
|
||||
}
|
||||
|
||||
- inline void adjustRightBearing(glyph_t glyph)
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ inline void adjustRightBearing(QFontEngine *engine, glyph_t glyph)
|
||||
{
|
||||
qreal rb;
|
||||
- fontEngine->getGlyphBearings(glyph, 0, &rb);
|
||||
+ engine->getGlyphBearings(glyph, 0, &rb);
|
||||
rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
|
||||
}
|
||||
|
||||
@@ -1648,13 +1659,16 @@ namespace {
|
||||
{
|
||||
if (currentPosition <= 0)
|
||||
return;
|
||||
- adjustRightBearing(currentGlyph());
|
||||
+
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ adjustRightBearing(fontEngine, currentGlyph());
|
||||
}
|
||||
|
||||
inline void adjustPreviousRightBearing()
|
||||
{
|
||||
if (previousGlyph > 0)
|
||||
- adjustRightBearing(previousGlyph);
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ adjustRightBearing(previousGlyphFontEngine, previousGlyph);
|
||||
}
|
||||
|
||||
inline void resetRightBearing()
|
||||
diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h
|
||||
index cbe42c3..b273db7 100644
|
||||
--- a/src/gui/text/qtextlayout.h
|
||||
+++ b/src/gui/text/qtextlayout.h
|
||||
@@ -194,6 +194,9 @@ private:
|
||||
QRectF *brect, int tabstops, int* tabarray, int tabarraylen,
|
||||
QPainter *painter);
|
||||
QTextEngine *d;
|
||||
+
|
||||
+ // Patch: Give access to the internal api.
|
||||
+ friend class TextBlock;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
|
||||
index ca7afb7..25ae500 100644
|
||||
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
|
||||
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
|
||||
@@ -256,6 +256,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
|
||||
|
||||
fd->foundryName = QStringLiteral("CoreText");
|
||||
fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
|
||||
+
|
||||
+ // Patch: Fix open sans semibold loading.
|
||||
+ QCFString _displayName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute);
|
||||
+ if (_displayName == QStringLiteral("Open Sans Semibold")) {
|
||||
+ fd->familyName = _displayName;
|
||||
+ }
|
||||
+
|
||||
fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
|
||||
fd->weight = QFont::Normal;
|
||||
fd->style = QFont::StyleNormal;
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
index 92358ec..694fee7 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
@@ -213,7 +213,8 @@ static void cleanupCocoaApplicationDelegate()
|
||||
if (reflectionDelegate) {
|
||||
if ([reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)])
|
||||
return [reflectionDelegate applicationShouldTerminate:sender];
|
||||
- return NSTerminateNow;
|
||||
+ // Patch: Don't terminate if reflectionDelegate does not respond to that selector, just use the default.
|
||||
+ //return NSTerminateNow;
|
||||
}
|
||||
|
||||
if ([self canQuit]) {
|
||||
@@ -289,6 +290,11 @@ static void cleanupCocoaApplicationDelegate()
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
+ // Patch: We need to receive this notification in the delegate as well.
|
||||
+ if (reflectionDelegate
|
||||
+ && [reflectionDelegate respondsToSelector:@selector(applicationDidFinishLaunching:)])
|
||||
+ [reflectionDelegate applicationDidFinishLaunching:aNotification];
|
||||
+
|
||||
Q_UNUSED(aNotification);
|
||||
inLaunch = false;
|
||||
// qt_release_apple_event_handler();
|
||||
@@ -411,7 +417,9 @@ static void cleanupCocoaApplicationDelegate()
|
||||
{
|
||||
Q_UNUSED(replyEvent);
|
||||
NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
|
||||
- QWindowSystemInterface::handleFileOpenEvent(QUrl(QCFString::toQString(urlString)));
|
||||
+
|
||||
+ // Patch: Fix opening of an external url by a protocol handler.
|
||||
+ QWindowSystemInterface::handleFileOpenEvent(QUrl::fromNSURL([NSURL URLWithString:urlString]));
|
||||
}
|
||||
|
||||
- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
|
||||
index 9fd05a6..dea6072 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
|
||||
@@ -402,14 +402,24 @@ void QCocoaIntegration::updateScreens()
|
||||
}
|
||||
siblings << screen;
|
||||
}
|
||||
+
|
||||
+ // Patch: Backport crash fix from Qt 5.6.1.
|
||||
+ // Set virtual siblings list. All screens in mScreens are siblings, because we ignored the
|
||||
+ // mirrors. Note that some of the screens we update the siblings list for here may be deleted
|
||||
+ // below, but update anyway to keep the to-be-deleted screens out of the siblings list.
|
||||
+ foreach (QCocoaScreen* screen, mScreens)
|
||||
+ screen->setVirtualSiblings(siblings);
|
||||
+
|
||||
// Now the leftovers in remainingScreens are no longer current, so we can delete them.
|
||||
foreach (QCocoaScreen* screen, remainingScreens) {
|
||||
mScreens.removeOne(screen);
|
||||
delete screen;
|
||||
}
|
||||
+
|
||||
+ // Patch: Backport crash fix from Qt 5.6.1.
|
||||
// All screens in mScreens are siblings, because we ignored the mirrors.
|
||||
- foreach (QCocoaScreen* screen, mScreens)
|
||||
- screen->setVirtualSiblings(siblings);
|
||||
+ //foreach (QCocoaScreen* screen, mScreens)
|
||||
+ // screen->setVirtualSiblings(siblings);
|
||||
}
|
||||
|
||||
QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
|
||||
index e46eaff..c62db53 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
|
||||
@@ -382,6 +382,12 @@ bool QCocoaKeyMapper::updateKeyboard()
|
||||
keyboardInputLocale = QLocale::c();
|
||||
keyboardInputDirection = Qt::LeftToRight;
|
||||
}
|
||||
+
|
||||
+ // Patch: Backport a fix for layout-independent keyboard shortcuts.
|
||||
+ const auto newMode = keyboard_mode;
|
||||
+ deleteLayouts();
|
||||
+ keyboard_mode = newMode;
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -464,7 +470,8 @@ QList<int> QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const
|
||||
Qt::KeyboardModifiers neededMods = ModsTbl[i];
|
||||
int key = kbItem->qtKey[i];
|
||||
if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) {
|
||||
- ret << int(key + (keyMods & ~neededMods));
|
||||
+ // Patch: Backport a fix for layout-independent keyboard shortcuts.
|
||||
+ ret << int(key + neededMods);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
index 83c960d..3b9f8d4 100755
|
||||
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
@@ -102,7 +102,10 @@ QT_USE_NAMESPACE
|
||||
QCocoaSystemTrayIcon *systray;
|
||||
NSStatusItem *item;
|
||||
QCocoaMenu *menu;
|
||||
- bool menuVisible;
|
||||
+
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ bool menuVisible, iconSelected;
|
||||
+
|
||||
QIcon icon;
|
||||
QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
|
||||
}
|
||||
@@ -124,6 +127,10 @@ QT_USE_NAMESPACE
|
||||
QT_MANGLE_NAMESPACE(QNSStatusItem) *parent;
|
||||
}
|
||||
-(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent;
|
||||
+
|
||||
+// Patch: Nice macOS tray icon support.
|
||||
+-(void)updateIconSelection;
|
||||
+
|
||||
-(void)menuTrackingDone:(NSNotification*)notification;
|
||||
-(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton;
|
||||
@end
|
||||
@@ -187,6 +194,19 @@ void QCocoaSystemTrayIcon::cleanup()
|
||||
m_sys = 0;
|
||||
}
|
||||
|
||||
+// Patch: Nice macOS tray icon support.
|
||||
+namespace {
|
||||
+
|
||||
+qreal getDevicePixelRatio() {
|
||||
+ qreal result = 1.0;
|
||||
+ foreach (QScreen *screen, QGuiApplication::screens()) {
|
||||
+ result = qMax(result, screen->devicePixelRatio());
|
||||
+ }
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
{
|
||||
if (!m_sys)
|
||||
@@ -194,13 +214,17 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
|
||||
m_sys->item->icon = icon;
|
||||
|
||||
- const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible;
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ //const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible;
|
||||
|
||||
CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
||||
- const short scale = hgt - 4;
|
||||
+
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ const short scale = hgt * getDevicePixelRatio();
|
||||
|
||||
QPixmap pm = m_sys->item->icon.pixmap(QSize(scale, scale),
|
||||
- menuVisible ? QIcon::Selected : QIcon::Normal);
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ m_sys->item->iconSelected ? QIcon::Selected : QIcon::Normal);
|
||||
if (pm.isNull()) {
|
||||
pm = QPixmap(scale, scale);
|
||||
pm.fill(Qt::transparent);
|
||||
@@ -322,15 +346,13 @@ QT_END_NAMESPACE
|
||||
return self;
|
||||
}
|
||||
|
||||
--(void)menuTrackingDone:(NSNotification*)notification
|
||||
+// Patch: Nice macOS tray icon support.
|
||||
+-(void)updateIconSelection
|
||||
{
|
||||
- Q_UNUSED(notification);
|
||||
- down = NO;
|
||||
-
|
||||
CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
||||
- const short scale = hgt - 4;
|
||||
-
|
||||
- QPixmap pm = parent->icon.pixmap(QSize(scale, scale), QIcon::Normal);
|
||||
+ const short scale = hgt * getDevicePixelRatio();
|
||||
+ QPixmap pm = parent->icon.pixmap(QSize(scale, scale),
|
||||
+ parent->iconSelected ? QIcon::Selected : QIcon::Normal);
|
||||
if (pm.isNull()) {
|
||||
pm = QPixmap(scale, scale);
|
||||
pm.fill(Qt::transparent);
|
||||
@@ -338,9 +360,19 @@ QT_END_NAMESPACE
|
||||
NSImage *nsaltimage = static_cast<NSImage *>(qt_mac_create_nsimage(pm));
|
||||
[self setImage: nsaltimage];
|
||||
[nsaltimage release];
|
||||
+}
|
||||
+
|
||||
+-(void)menuTrackingDone:(NSNotification*)notification
|
||||
+{
|
||||
+ Q_UNUSED(notification);
|
||||
+ down = NO;
|
||||
|
||||
parent->menuVisible = false;
|
||||
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ parent->iconSelected = false;
|
||||
+ [self updateIconSelection];
|
||||
+
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@@ -350,18 +382,9 @@ QT_END_NAMESPACE
|
||||
int clickCount = [mouseEvent clickCount];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
- CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
||||
- const short scale = hgt - 4;
|
||||
-
|
||||
- QPixmap pm = parent->icon.pixmap(QSize(scale, scale),
|
||||
- parent->menuVisible ? QIcon::Selected : QIcon::Normal);
|
||||
- if (pm.isNull()) {
|
||||
- pm = QPixmap(scale, scale);
|
||||
- pm.fill(Qt::transparent);
|
||||
- }
|
||||
- NSImage *nsaltimage = static_cast<NSImage *>(qt_mac_create_nsimage(pm));
|
||||
- [self setImage: nsaltimage];
|
||||
- [nsaltimage release];
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ parent->iconSelected = (clickCount != 2) && parent->menu;
|
||||
+ [self updateIconSelection];
|
||||
|
||||
if (clickCount == 2) {
|
||||
[self menuTrackingDone:nil];
|
||||
@@ -380,6 +403,10 @@ QT_END_NAMESPACE
|
||||
{
|
||||
Q_UNUSED(mouseEvent);
|
||||
[self menuTrackingDone:nil];
|
||||
+
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ parent->iconSelected = false;
|
||||
+ [self updateIconSelection];
|
||||
}
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)mouseEvent
|
||||
@@ -391,6 +418,10 @@ QT_END_NAMESPACE
|
||||
{
|
||||
Q_UNUSED(mouseEvent);
|
||||
[self menuTrackingDone:nil];
|
||||
+
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ parent->iconSelected = false;
|
||||
+ [self updateIconSelection];
|
||||
}
|
||||
|
||||
- (void)otherMouseDown:(NSEvent *)mouseEvent
|
||||
@@ -405,7 +436,8 @@ QT_END_NAMESPACE
|
||||
}
|
||||
|
||||
-(void)drawRect:(NSRect)rect {
|
||||
- [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down];
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:parent->menu ? down : NO];
|
||||
[super drawRect:rect];
|
||||
}
|
||||
@end
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
index 4d0458a..fde238a 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
@@ -167,7 +167,8 @@ static bool isMouseEvent(NSEvent *ev)
|
||||
if (!self.window.delegate)
|
||||
return; // Already detached, pending NSAppKitDefined event
|
||||
|
||||
- if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) {
|
||||
+ // Patch: Fix events loss if the window was minimized or hidden.
|
||||
+ if (pw && pw->frameStrutEventsEnabled() && pw->m_synchedWindowState != Qt::WindowMinimized && pw->m_isExposed && isMouseEvent(theEvent)) {
|
||||
NSPoint loc = [theEvent locationInWindow];
|
||||
NSRect windowFrame = [self.window legacyConvertRectFromScreen:[self.window frame]];
|
||||
NSRect contentFrame = [[self.window contentView] frame];
|
||||
@@ -914,6 +915,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath)
|
||||
[m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""];
|
||||
}
|
||||
|
||||
+// Patch: Nice macOS window icon.
|
||||
+namespace {
|
||||
+
|
||||
+qreal getDevicePixelRatio() {
|
||||
+ qreal result = 1.0;
|
||||
+ foreach (QScreen *screen, QGuiApplication::screens()) {
|
||||
+ result = qMax(result, screen->devicePixelRatio());
|
||||
+ }
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
{
|
||||
QCocoaAutoReleasePool pool;
|
||||
@@ -929,7 +943,10 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
if (icon.isNull()) {
|
||||
[iconButton setImage:nil];
|
||||
} else {
|
||||
- QPixmap pixmap = icon.pixmap(QSize(22, 22));
|
||||
+ // Patch: Nice macOS window icon.
|
||||
+ CGFloat hgt = 16. * getDevicePixelRatio();
|
||||
+ QPixmap pixmap = icon.pixmap(QSize(hgt, hgt));
|
||||
+
|
||||
NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap));
|
||||
[iconButton setImage:image];
|
||||
[image release];
|
||||
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
|
||||
index a18ee7f..1f91feb 100644
|
||||
--- a/src/plugins/platforms/cocoa/qnsview.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qnsview.mm
|
||||
@@ -393,7 +393,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
|
||||
[self notifyWindowStateChanged:newState];
|
||||
// NSWindowDidOrderOnScreenAndFinishAnimatingNotification is private API, and not
|
||||
// emitted in 10.6, so we bring back the old behavior for that case alone.
|
||||
- if (newState == Qt::WindowNoState && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6)
|
||||
+
|
||||
+ // Patch: Fix macOS window show after window was hidden.
|
||||
+ if (newState == Qt::WindowNoState/* && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6*/)
|
||||
m_platformWindow->exposeWindow();
|
||||
} else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) {
|
||||
m_platformWindow->obscureWindow();
|
||||
@@ -1300,7 +1302,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
|
||||
if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
|
||||
// On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin.
|
||||
- if (phase == NSEventPhaseMayBegin)
|
||||
+
|
||||
+ // Patch: Actual begin should be treated as begin as well.
|
||||
+ if (phase == NSEventPhaseMayBegin || phase == NSEventPhaseBegan)
|
||||
ph = Qt::ScrollBegin;
|
||||
} else
|
||||
#endif
|
||||
@@ -1366,14 +1370,22 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
|
||||
quint32 nativeVirtualKey = [nsevent keyCode];
|
||||
|
||||
QChar ch = QChar::ReplacementCharacter;
|
||||
- int keyCode = Qt::Key_unknown;
|
||||
- if ([characters length] != 0) {
|
||||
- if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0))
|
||||
- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
|
||||
- else
|
||||
- ch = QChar([characters characterAtIndex:0]);
|
||||
- keyCode = [self convertKeyCode:ch];
|
||||
- }
|
||||
+
|
||||
+ // Patch: Backport a fix for layout-independent shortcuts.
|
||||
+ if ([characters length] != 0) // https://bugreports.qt.io/browse/QTBUG-42584
|
||||
+ ch = QChar([characters characterAtIndex:0]);
|
||||
+ else if ([charactersIgnoringModifiers length] != 0 && ((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)))
|
||||
+ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
|
||||
+
|
||||
+ int keyCode = [self convertKeyCode:ch];
|
||||
+ //int keyCode = Qt::Key_unknown;
|
||||
+ //if ([characters length] != 0) {
|
||||
+ // if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0))
|
||||
+ // ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
|
||||
+ // else
|
||||
+ // ch = QChar([characters characterAtIndex:0]);
|
||||
+ // keyCode = [self convertKeyCode:ch];
|
||||
+ //}
|
||||
|
||||
// we will send a key event unless the input method sets m_sendKeyEvent to false
|
||||
m_sendKeyEvent = true;
|
||||
@@ -1437,6 +1449,11 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
|
||||
&& qtKey == Qt::Key_Period) {
|
||||
[self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
|
||||
return YES;
|
||||
+
|
||||
+ // Patch: Allow us to handle Ctrl+Tab and Ctrl+Backtab in the app.
|
||||
+ } else if ([nsevent modifierFlags] & NSControlKeyMask && (qtKey == Qt::Key_Tab || qtKey == Qt::Key_Backtab)) {
|
||||
+ [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
|
||||
+ return YES;
|
||||
}
|
||||
}
|
||||
return [super performKeyEquivalent:nsevent];
|
||||
diff --git a/src/tools/qlalr/lalr.cpp b/src/tools/qlalr/lalr.cpp
|
||||
index c680764..e2a7aaf 100644
|
||||
--- a/src/tools/qlalr/lalr.cpp
|
||||
+++ b/src/tools/qlalr/lalr.cpp
|
||||
@@ -246,11 +246,13 @@ void Grammar::buildExtendedGrammar ()
|
||||
non_terminals.insert (accept_symbol);
|
||||
}
|
||||
|
||||
-struct _Nullable: public std::unary_function<Name, bool>
|
||||
+// Patch: Fix building with the new SDK.
|
||||
+struct __Nullable: public std::unary_function<Name, bool>
|
||||
{
|
||||
Automaton *_M_automaton;
|
||||
|
||||
- _Nullable (Automaton *aut):
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ __Nullable (Automaton *aut):
|
||||
_M_automaton (aut) {}
|
||||
|
||||
bool operator () (Name name) const
|
||||
@@ -308,7 +310,8 @@ void Automaton::buildNullables ()
|
||||
|
||||
for (RulePointer rule = _M_grammar->rules.begin (); rule != _M_grammar->rules.end (); ++rule)
|
||||
{
|
||||
- NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (_Nullable (this)));
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (__Nullable (this)));
|
||||
|
||||
if (nn == rule->rhs.end ())
|
||||
changed |= nullables.insert (rule->lhs).second;
|
||||
@@ -643,7 +646,8 @@ void Automaton::buildIncludesDigraph ()
|
||||
if (! _M_grammar->isNonTerminal (*A))
|
||||
continue;
|
||||
|
||||
- NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (_Nullable (this)));
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (__Nullable (this)));
|
||||
if (first_not_nullable != rule->rhs.end ())
|
||||
continue;
|
||||
|
||||
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
|
||||
index 7396808..87b4978 100644
|
||||
--- a/src/widgets/kernel/qwidget.cpp
|
||||
+++ b/src/widgets/kernel/qwidget.cpp
|
||||
@@ -7983,7 +7983,8 @@ bool QWidget::event(QEvent *event)
|
||||
case QEvent::KeyPress: {
|
||||
QKeyEvent *k = (QKeyEvent *)event;
|
||||
bool res = false;
|
||||
- if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
|
||||
+ // Patch: Allow us to handle Ctrl+Tab and Ctrl+Backtab in the app.
|
||||
+ if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { //### Add MetaModifier?
|
||||
if (k->key() == Qt::Key_Backtab
|
||||
|| (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
|
||||
res = focusNextPrevChild(false);
|
||||
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm
|
||||
index 0845a5e..5735cb6 100644
|
||||
--- a/src/widgets/styles/qmacstyle_mac.mm
|
||||
+++ b/src/widgets/styles/qmacstyle_mac.mm
|
||||
@@ -3667,9 +3667,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
|
||||
|
||||
NSBezierPath *pushButtonFocusRingPath;
|
||||
if (bdi.kind == kThemeBevelButton)
|
||||
- pushButtonFocusRingPath = [NSBezierPath bezierPathWithRect:focusRect];
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ pushButtonFocusRingPath = [NSBezierPath bezierPathWithRect:NSRectFromCGRect(focusRect)];
|
||||
else
|
||||
- pushButtonFocusRingPath = [NSBezierPath bezierPathWithRoundedRect:focusRect xRadius:4 yRadius:4];
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ pushButtonFocusRingPath = [NSBezierPath bezierPathWithRoundedRect:NSRectFromCGRect(focusRect) xRadius:4 yRadius:4];
|
||||
qt_drawFocusRingOnPath(cg, pushButtonFocusRingPath);
|
||||
}
|
||||
|
||||
diff --git a/src/widgets/util/qsystemtrayicon_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp
|
||||
index f98aeaf..00c0734 100644
|
||||
--- a/src/widgets/util/qsystemtrayicon_qpa.cpp
|
||||
+++ b/src/widgets/util/qsystemtrayicon_qpa.cpp
|
||||
@@ -99,13 +99,18 @@ void QSystemTrayIconPrivate::updateIcon_sys()
|
||||
|
||||
void QSystemTrayIconPrivate::updateMenu_sys()
|
||||
{
|
||||
- if (qpa_sys && menu) {
|
||||
- if (!menu->platformMenu()) {
|
||||
- QPlatformMenu *platformMenu = qpa_sys->createMenu();
|
||||
- if (platformMenu)
|
||||
- menu->setPlatformMenu(platformMenu);
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ if (qpa_sys) {
|
||||
+ if (menu) {
|
||||
+ if (!menu->platformMenu()) {
|
||||
+ QPlatformMenu *platformMenu = qpa_sys->createMenu();
|
||||
+ if (platformMenu)
|
||||
+ menu->setPlatformMenu(platformMenu);
|
||||
+ }
|
||||
+ qpa_sys->updateMenu(menu->platformMenu());
|
||||
+ } else {
|
||||
+ qpa_sys->updateMenu(0);
|
||||
}
|
||||
- qpa_sys->updateMenu(menu->platformMenu());
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
|
||||
index 75f3059..980f2be 100644
|
||||
--- a/src/widgets/widgets/qwidgetlinecontrol.cpp
|
||||
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
|
||||
@@ -1867,7 +1867,8 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
|
||||
|
||||
if (unknown && !isReadOnly()) {
|
||||
QString t = event->text();
|
||||
- if (!t.isEmpty() && t.at(0).isPrint()) {
|
||||
+ // Patch: Enable ZWJ and ZWNJ characters to be in text input.
|
||||
+ if (!t.isEmpty() && (t.at(0).isPrint() || t.at(0).unicode() == 0x200C || t.at(0).unicode() == 0x200D)) {
|
||||
insert(t);
|
||||
#ifndef QT_NO_COMPLETER
|
||||
complete(event->key());
|
||||
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
|
||||
index 96438a0..b0b7206 100644
|
||||
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
|
||||
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
|
||||
@@ -1342,7 +1342,8 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
|
||||
process:
|
||||
{
|
||||
QString text = e->text();
|
||||
- if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
|
||||
+ // Patch: Enable ZWJ and ZWNJ characters to be in text input.
|
||||
+ if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t') || text.at(0).unicode() == 0x200C || text.at(0).unicode() == 0x200D)) {
|
||||
if (overwriteMode
|
||||
// no need to call deleteChar() if we have a selection, insertText
|
||||
// does it already
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,17 @@
|
|||
diff --git a/configure b/configure
|
||||
index 7651e29..11e6f90 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -527,7 +527,8 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
- if ! /usr/bin/xcrun -find xcrun >/dev/null 2>&1; then
|
||||
+ # Patch: Fix Qt for working with Xcode 8.
|
||||
+ if ! /usr/bin/xcrun -find xcodebuild >/dev/null 2>&1; then
|
||||
echo >&2
|
||||
echo " Xcode not set up properly. You may need to confirm the license" >&2
|
||||
echo " agreement by running /usr/bin/xcodebuild without arguments." >&2
|
||||
diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf
|
||||
index eec9e1f..ec3015e 100644
|
||||
--- a/mkspecs/common/msvc-desktop.conf
|
||||
|
@ -16,6 +30,21 @@ index eec9e1f..ec3015e 100644
|
|||
QMAKE_CFLAGS_YACC =
|
||||
QMAKE_CFLAGS_LTCG = -GL
|
||||
QMAKE_CFLAGS_SSE2 = -arch:SSE2
|
||||
diff --git a/mkspecs/features/mac/default_pre.prf b/mkspecs/features/mac/default_pre.prf
|
||||
index 0cc8cd6..ca9725b 100644
|
||||
--- a/mkspecs/features/mac/default_pre.prf
|
||||
+++ b/mkspecs/features/mac/default_pre.prf
|
||||
@@ -12,7 +12,9 @@ isEmpty(QMAKE_XCODE_DEVELOPER_PATH) {
|
||||
error("Xcode is not installed in $${QMAKE_XCODE_DEVELOPER_PATH}. Please use xcode-select to choose Xcode installation path.")
|
||||
|
||||
# Make sure Xcode is set up properly
|
||||
- isEmpty($$list($$system("/usr/bin/xcrun -find xcrun 2>/dev/null"))): \
|
||||
+
|
||||
+ # Patch: Fix Qt for working with Xcode 8.
|
||||
+ isEmpty($$list($$system("/usr/bin/xcrun -find xcodebuild 2>/dev/null"))): \
|
||||
error("Xcode not set up properly. You may need to confirm the license agreement by running /usr/bin/xcodebuild.")
|
||||
}
|
||||
|
||||
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
|
||||
index f1a6019..81ff6ef 100644
|
||||
--- a/src/corelib/io/qfilesystemengine_win.cpp
|
||||
|
@ -11250,7 +11279,7 @@ index faea54b..7d85080 100644
|
|||
|
||||
contains(QT_CONFIG, xcb-plugin): SUBDIRS += compose
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
index caa8884..b083e65 100644
|
||||
index caa8884..72941e4 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
@@ -210,7 +210,8 @@ QT_END_NAMESPACE
|
||||
|
@ -11263,6 +11292,23 @@ index caa8884..b083e65 100644
|
|||
}
|
||||
|
||||
if ([self canQuit]) {
|
||||
@@ -287,11 +288,15 @@ QT_END_NAMESPACE
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
+ // We need to catch that notification in delegate.
|
||||
+ if (reflectionDelegate
|
||||
+ && [reflectionDelegate respondsToSelector:@selector(applicationDidFinishLaunching:)])
|
||||
+ [reflectionDelegate applicationDidFinishLaunching:aNotification];
|
||||
+
|
||||
Q_UNUSED(aNotification);
|
||||
inLaunch = false;
|
||||
// qt_release_apple_event_handler();
|
||||
|
||||
-
|
||||
// Insert code here to initialize your application
|
||||
}
|
||||
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
|
||||
index 5a199de..5622728 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
diff --git a/src/3rdparty/libwebp/src/dec/vp8l.c b/src/3rdparty/libwebp/src/dec/vp8l.c
|
||||
index ea0254d..953ff01 100644
|
||||
--- a/src/3rdparty/libwebp/src/dec/vp8l.c
|
||||
+++ b/src/3rdparty/libwebp/src/dec/vp8l.c
|
||||
@@ -12,7 +12,7 @@
|
||||
// Authors: Vikas Arora (vikaas.arora@gmail.com)
|
||||
// Jyrki Alakuijala (jyrki@google.com)
|
||||
|
||||
-#include <stdio.h>
|
||||
+// Patch: Backport of a crash fix.
|
||||
#include <stdlib.h>
|
||||
#include "./alphai.h"
|
||||
#include "./vp8li.h"
|
||||
@@ -740,6 +740,10 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
|
||||
const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
|
||||
const int mask = hdr->huffman_mask_;
|
||||
assert(htree_group != NULL);
|
||||
+
|
||||
+ // Patch: Backport of a crash fix.
|
||||
+ assert(pos < end);
|
||||
+
|
||||
assert(last_row <= height);
|
||||
assert(Is8bOptimizable(hdr));
|
||||
|
||||
@@ -830,6 +834,10 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
||||
(hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
|
||||
const int mask = hdr->huffman_mask_;
|
||||
assert(htree_group != NULL);
|
||||
+
|
||||
+ // Patch: Backport of a crash fix.
|
||||
+ assert(src < src_end);
|
||||
+
|
||||
assert(src_last <= src_end);
|
||||
|
||||
while (!br->eos_ && src < src_last) {
|
||||
@@ -1294,6 +1302,11 @@ int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
|
||||
assert(dec->action_ == READ_DATA);
|
||||
assert(last_row <= dec->height_);
|
||||
|
||||
+ // Patch: Backport of a crash fix.
|
||||
+ if (dec->last_pixel_ == dec->width_ * dec->height_) {
|
||||
+ return 1; // done
|
||||
+ }
|
||||
+
|
||||
// Decode (with special row processing).
|
||||
return alph_dec->use_8b_decode ?
|
||||
DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
|
|
@ -33,10 +33,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include <IOKit/hidsystem/ev_keymap.h>
|
||||
|
||||
#include <SPMediaKeyTap.h>
|
||||
|
||||
using Platform::Q2NSString;
|
||||
using Platform::NSlang;
|
||||
using Platform::NS2QString;
|
||||
|
||||
bool handleMediaKeyEvent(NSEvent *e);
|
||||
|
||||
@interface qVisualize : NSObject {
|
||||
}
|
||||
|
||||
|
@ -81,11 +85,16 @@ using Platform::NS2QString;
|
|||
@end
|
||||
|
||||
@interface ApplicationDelegate : NSObject<NSApplicationDelegate> {
|
||||
|
||||
SPMediaKeyTap *keyTap;
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag;
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)aNotification;
|
||||
- (void)receiveWakeNote:(NSNotification*)note;
|
||||
- (void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -99,6 +108,15 @@ ApplicationDelegate *_sharedDelegate = nil;
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
keyTap = [[SPMediaKeyTap alloc] initWithDelegate:self];
|
||||
if ([SPMediaKeyTap usesGlobalMediaKeyTap]) {
|
||||
[keyTap startWatchingMediaKeys];
|
||||
} else {
|
||||
LOG(("Media key monitoring disabled"));
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)aNotification {
|
||||
if (App::app()) App::app()->checkLocalTime();
|
||||
}
|
||||
|
@ -107,6 +125,12 @@ ApplicationDelegate *_sharedDelegate = nil;
|
|||
if (App::app()) App::app()->checkLocalTime();
|
||||
}
|
||||
|
||||
- (void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)e {
|
||||
if (e && [e type] == NSSystemDefined && [e subtype] == SPSystemDefinedEventMediaKeys) {
|
||||
handleMediaKeyEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ObserverHelper : NSObject {
|
||||
|
@ -173,6 +197,9 @@ PsMacWindowPrivate::PsMacWindowPrivate() : data(new PsMacWindowData(this)) {
|
|||
[[NSDistributedNotificationCenter defaultCenter] addObserver:data->observerHelper selector:@selector(screenIsLocked:) name:Q2NSString(strNotificationAboutScreenLocked()) object:nil];
|
||||
[[NSDistributedNotificationCenter defaultCenter] addObserver:data->observerHelper selector:@selector(screenIsUnlocked:) name:Q2NSString(strNotificationAboutScreenUnlocked()) object:nil];
|
||||
|
||||
// Register defaults for the whitelist of apps that want to use media keys
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:[SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers], kMediaKeyUsingBundleIdentifiersDefaultsKey, nil]];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,6 +252,43 @@ void objc_activateWnd(WId winId) {
|
|||
[wnd orderFront:wnd];
|
||||
}
|
||||
|
||||
bool handleMediaKeyEvent(NSEvent *e) {
|
||||
int keyCode = (([e data1] & 0xFFFF0000) >> 16);
|
||||
int keyFlags = ([e data1] & 0x0000FFFF);
|
||||
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
|
||||
int keyRepeat = (keyFlags & 0x1);
|
||||
|
||||
switch (keyCode) {
|
||||
case NX_KEYTYPE_PLAY:
|
||||
if (keyState == 0) { // Play pressed and released
|
||||
if (Media::Player::exists()) {
|
||||
Media::Player::instance()->playPause();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case NX_KEYTYPE_FAST:
|
||||
if (keyState == 0) { // Next pressed and released
|
||||
if (Media::Player::exists()) {
|
||||
Media::Player::instance()->next();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case NX_KEYTYPE_REWIND:
|
||||
if (keyState == 0) { // Previous pressed and released
|
||||
if (Media::Player::exists()) {
|
||||
Media::Player::instance()->previous();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PsMacWindowPrivate::enableShadow(WId winId) {
|
||||
// [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask];
|
||||
// [[(NSView*)winId window] setHasShadow:YES];
|
||||
|
@ -232,39 +296,10 @@ void PsMacWindowPrivate::enableShadow(WId winId) {
|
|||
|
||||
bool PsMacWindowPrivate::filterNativeEvent(void *event) {
|
||||
NSEvent *e = static_cast<NSEvent*>(event);
|
||||
if (e && [e type] == NSSystemDefined && [e subtype] == 8) {
|
||||
int keyCode = (([e data1] & 0xFFFF0000) >> 16);
|
||||
int keyFlags = ([e data1] & 0x0000FFFF);
|
||||
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
|
||||
int keyRepeat = (keyFlags & 0x1);
|
||||
|
||||
switch (keyCode) {
|
||||
case NX_KEYTYPE_PLAY:
|
||||
if (keyState == 0) { // Play pressed and released
|
||||
if (Media::Player::exists()) {
|
||||
Media::Player::instance()->playPause();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case NX_KEYTYPE_FAST:
|
||||
if (keyState == 0) { // Next pressed and released
|
||||
if (Media::Player::exists()) {
|
||||
Media::Player::instance()->next();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case NX_KEYTYPE_REWIND:
|
||||
if (keyState == 0) { // Previous pressed and released
|
||||
if (Media::Player::exists()) {
|
||||
Media::Player::instance()->previous();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
if (e && [e type] == NSSystemDefined && [e subtype] == SPSystemDefinedEventMediaKeys) {
|
||||
// If event tap is not installed, handle events that reach the app instead
|
||||
if (![SPMediaKeyTap usesGlobalMediaKeyTap]) {
|
||||
return handleMediaKeyEvent(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
30
Telegram/ThirdParty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
vendored
Normal file
30
Telegram/ThirdParty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SPInvocationGrabber : NSObject {
|
||||
id _object;
|
||||
NSInvocation *_invocation;
|
||||
int frameCount;
|
||||
char **frameStrings;
|
||||
BOOL backgroundAfterForward;
|
||||
BOOL onMainAfterForward;
|
||||
BOOL waitUntilDone;
|
||||
}
|
||||
-(id)initWithObject:(id)obj;
|
||||
-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
|
||||
@property (readonly, retain, nonatomic) id object;
|
||||
@property (readonly, retain, nonatomic) NSInvocation *invocation;
|
||||
@property BOOL backgroundAfterForward;
|
||||
@property BOOL onMainAfterForward;
|
||||
@property BOOL waitUntilDone;
|
||||
-(void)invoke; // will release object and invocation
|
||||
-(void)printBacktrace;
|
||||
-(void)saveBacktrace;
|
||||
@end
|
||||
|
||||
@interface NSObject (SPInvocationGrabbing)
|
||||
-(id)grab;
|
||||
-(id)invokeAfter:(NSTimeInterval)delta;
|
||||
-(id)nextRunloop;
|
||||
-(id)inBackground;
|
||||
-(id)onMainAsync:(BOOL)async;
|
||||
@end
|
127
Telegram/ThirdParty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
vendored
Normal file
127
Telegram/ThirdParty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
#import "NSObject+SPInvocationGrabbing.h"
|
||||
#import <execinfo.h>
|
||||
|
||||
#pragma mark Invocation grabbing
|
||||
@interface SPInvocationGrabber ()
|
||||
@property (readwrite, retain, nonatomic) id object;
|
||||
@property (readwrite, retain, nonatomic) NSInvocation *invocation;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SPInvocationGrabber
|
||||
- (id)initWithObject:(id)obj
|
||||
{
|
||||
return [self initWithObject:obj stacktraceSaving:YES];
|
||||
}
|
||||
|
||||
-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack
|
||||
{
|
||||
self.object = obj;
|
||||
|
||||
if(saveStack)
|
||||
[self saveBacktrace];
|
||||
|
||||
return self;
|
||||
}
|
||||
-(void)dealloc
|
||||
{
|
||||
free(frameStrings);
|
||||
self.object = nil;
|
||||
self.invocation = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
@synthesize invocation = _invocation, object = _object;
|
||||
|
||||
@synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone;
|
||||
- (void)runInBackground
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@try {
|
||||
[self invoke];
|
||||
}
|
||||
@finally {
|
||||
[pool drain];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)anInvocation {
|
||||
[anInvocation retainArguments];
|
||||
anInvocation.target = _object;
|
||||
self.invocation = anInvocation;
|
||||
|
||||
if(backgroundAfterForward)
|
||||
[NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil];
|
||||
else if(onMainAfterForward)
|
||||
[self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone];
|
||||
}
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector {
|
||||
NSMethodSignature *signature = [super methodSignatureForSelector:inSelector];
|
||||
if (signature == NULL)
|
||||
signature = [_object methodSignatureForSelector:inSelector];
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
- (void)invoke
|
||||
{
|
||||
|
||||
@try {
|
||||
[_invocation invoke];
|
||||
}
|
||||
@catch (NSException * e) {
|
||||
NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e);
|
||||
[self printBacktrace];
|
||||
printf("\n");
|
||||
[e raise];
|
||||
}
|
||||
|
||||
self.invocation = nil;
|
||||
self.object = nil;
|
||||
}
|
||||
|
||||
-(void)saveBacktrace
|
||||
{
|
||||
void *backtraceFrames[128];
|
||||
frameCount = backtrace(&backtraceFrames[0], 128);
|
||||
frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount);
|
||||
}
|
||||
-(void)printBacktrace
|
||||
{
|
||||
for(int x = 3; x < frameCount; x++) {
|
||||
if(frameStrings[x] == NULL) { break; }
|
||||
printf("%s\n", frameStrings[x]);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSObject (SPInvocationGrabbing)
|
||||
-(id)grab
|
||||
{
|
||||
return [[[SPInvocationGrabber alloc] initWithObject:self] autorelease];
|
||||
}
|
||||
-(id)invokeAfter:(NSTimeInterval)delta
|
||||
{
|
||||
id grabber = [self grab];
|
||||
[NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO];
|
||||
return grabber;
|
||||
}
|
||||
- (id)nextRunloop
|
||||
{
|
||||
return [self invokeAfter:0];
|
||||
}
|
||||
-(id)inBackground
|
||||
{
|
||||
SPInvocationGrabber *grabber = [self grab];
|
||||
grabber.backgroundAfterForward = YES;
|
||||
return grabber;
|
||||
}
|
||||
-(id)onMainAsync:(BOOL)async
|
||||
{
|
||||
SPInvocationGrabber *grabber = [self grab];
|
||||
grabber.onMainAfterForward = YES;
|
||||
grabber.waitUntilDone = !async;
|
||||
return grabber;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,43 @@
|
|||
#include <Cocoa/Cocoa.h>
|
||||
#import <IOKit/hidsystem/ev_keymap.h>
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
// http://overooped.com/post/2593597587/mediakeys
|
||||
|
||||
#define SPSystemDefinedEventMediaKeys 8
|
||||
|
||||
@interface SPMediaKeyTap : NSObject {
|
||||
EventHandlerRef _app_switching_ref;
|
||||
EventHandlerRef _app_terminating_ref;
|
||||
CFMachPortRef _eventPort;
|
||||
CFRunLoopSourceRef _eventPortSource;
|
||||
CFRunLoopRef _tapThreadRL;
|
||||
BOOL _shouldInterceptMediaKeyEvents;
|
||||
id _delegate;
|
||||
// The app that is frontmost in this list owns media keys
|
||||
NSMutableArray *_mediaKeyAppList;
|
||||
}
|
||||
+ (NSArray*)defaultMediaKeyUserBundleIdentifiers;
|
||||
|
||||
-(id)initWithDelegate:(id)delegate;
|
||||
|
||||
+(BOOL)usesGlobalMediaKeyTap;
|
||||
-(void)startWatchingMediaKeys;
|
||||
-(void)stopWatchingMediaKeys;
|
||||
-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event;
|
||||
@end
|
||||
|
||||
@interface NSObject (SPMediaKeyTapDelegate)
|
||||
-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
|
||||
@end
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey;
|
||||
extern NSString *kIgnoreMediaKeysDefaultsKey;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,347 @@
|
|||
// Copyright (c) 2010 Spotify AB
|
||||
#import "SPMediaKeyTap.h"
|
||||
#import "SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h" // https://gist.github.com/511181, in submodule
|
||||
|
||||
@interface SPMediaKeyTap ()
|
||||
-(BOOL)shouldInterceptMediaKeyEvents;
|
||||
-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting;
|
||||
-(void)startWatchingAppSwitching;
|
||||
-(void)stopWatchingAppSwitching;
|
||||
-(void)eventTapThread;
|
||||
@end
|
||||
static SPMediaKeyTap *singleton = nil;
|
||||
|
||||
static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData);
|
||||
static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData);
|
||||
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon);
|
||||
|
||||
// Inspired by http://gist.github.com/546311
|
||||
|
||||
@implementation SPMediaKeyTap
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Setup and teardown
|
||||
-(id)initWithDelegate:(id)delegate
|
||||
{
|
||||
_delegate = delegate;
|
||||
[self startWatchingAppSwitching];
|
||||
singleton = self;
|
||||
_mediaKeyAppList = [NSMutableArray new];
|
||||
_tapThreadRL=nil;
|
||||
_eventPort=nil;
|
||||
_eventPortSource=nil;
|
||||
return self;
|
||||
}
|
||||
-(void)dealloc
|
||||
{
|
||||
[self stopWatchingMediaKeys];
|
||||
[self stopWatchingAppSwitching];
|
||||
[_mediaKeyAppList release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(void)startWatchingAppSwitching
|
||||
{
|
||||
// Listen to "app switched" event, so that we don't intercept media keys if we
|
||||
// weren't the last "media key listening" app to be active
|
||||
EventTypeSpec eventType = { kEventClassApplication, kEventAppFrontSwitched };
|
||||
OSStatus err = InstallApplicationEventHandler(NewEventHandlerUPP(appSwitched), 1, &eventType, self, &_app_switching_ref);
|
||||
assert(err == noErr);
|
||||
|
||||
eventType.eventKind = kEventAppTerminated;
|
||||
err = InstallApplicationEventHandler(NewEventHandlerUPP(appTerminated), 1, &eventType, self, &_app_terminating_ref);
|
||||
assert(err == noErr);
|
||||
}
|
||||
-(void)stopWatchingAppSwitching
|
||||
{
|
||||
if(!_app_switching_ref) return;
|
||||
RemoveEventHandler(_app_switching_ref);
|
||||
_app_switching_ref = NULL;
|
||||
}
|
||||
|
||||
-(void)startWatchingMediaKeys
|
||||
{
|
||||
// Prevent having multiple mediaKeys threads
|
||||
[self stopWatchingMediaKeys];
|
||||
|
||||
[self setShouldInterceptMediaKeyEvents:YES];
|
||||
|
||||
// Add an event tap to intercept the system defined media key events
|
||||
_eventPort = CGEventTapCreate(kCGSessionEventTap,
|
||||
kCGHeadInsertEventTap,
|
||||
kCGEventTapOptionDefault,
|
||||
CGEventMaskBit(NX_SYSDEFINED),
|
||||
tapEventCallback,
|
||||
self);
|
||||
assert(_eventPort != NULL);
|
||||
|
||||
_eventPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0);
|
||||
assert(_eventPortSource != NULL);
|
||||
|
||||
// Let's do this in a separate thread so that a slow app doesn't lag the event tap
|
||||
[NSThread detachNewThreadSelector:@selector(eventTapThread) toTarget:self withObject:nil];
|
||||
}
|
||||
-(void)stopWatchingMediaKeys
|
||||
{
|
||||
// TODO<nevyn>: Shut down thread, remove event tap port and source
|
||||
|
||||
if(_tapThreadRL){
|
||||
CFRunLoopStop(_tapThreadRL);
|
||||
_tapThreadRL=nil;
|
||||
}
|
||||
|
||||
if(_eventPort){
|
||||
CFMachPortInvalidate(_eventPort);
|
||||
CFRelease(_eventPort);
|
||||
_eventPort=nil;
|
||||
}
|
||||
|
||||
if(_eventPortSource){
|
||||
CFRelease(_eventPortSource);
|
||||
_eventPortSource=nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
+(BOOL)usesGlobalMediaKeyTap
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// breaking in gdb with a key tap inserted sometimes locks up all mouse and keyboard input forever, forcing reboot
|
||||
return NO;
|
||||
#else
|
||||
// XXX(nevyn): MediaKey event tap doesn't work on 10.4, feel free to figure out why if you have the energy.
|
||||
return
|
||||
![[NSUserDefaults standardUserDefaults] boolForKey:kIgnoreMediaKeysDefaultsKey]
|
||||
&& floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/;
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (NSArray*)defaultMediaKeyUserBundleIdentifiers
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
[[NSBundle mainBundle] bundleIdentifier], // your app
|
||||
@"com.spotify.client",
|
||||
@"com.apple.iTunes",
|
||||
@"com.apple.QuickTimePlayerX",
|
||||
@"com.apple.quicktimeplayer",
|
||||
@"com.apple.iWork.Keynote",
|
||||
@"com.apple.iPhoto",
|
||||
@"org.videolan.vlc",
|
||||
@"com.apple.Aperture",
|
||||
@"com.plexsquared.Plex",
|
||||
@"com.soundcloud.desktop",
|
||||
@"org.niltsh.MPlayerX",
|
||||
@"com.ilabs.PandorasHelper",
|
||||
@"com.mahasoftware.pandabar",
|
||||
@"com.bitcartel.pandorajam",
|
||||
@"org.clementine-player.clementine",
|
||||
@"fm.last.Last.fm",
|
||||
@"fm.last.Scrobbler",
|
||||
@"com.beatport.BeatportPro",
|
||||
@"com.Timenut.SongKey",
|
||||
@"com.macromedia.fireworks", // the tap messes up their mouse input
|
||||
@"at.justp.Theremin",
|
||||
@"ru.ya.themblsha.YandexMusic",
|
||||
@"com.jriver.MediaCenter18",
|
||||
@"com.jriver.MediaCenter19",
|
||||
@"com.jriver.MediaCenter20",
|
||||
@"co.rackit.mate",
|
||||
@"com.ttitt.b-music",
|
||||
@"com.beardedspice.BeardedSpice",
|
||||
@"com.plug.Plug",
|
||||
@"com.plug.Plug2",
|
||||
@"com.netease.163music",
|
||||
@"org.quodlibet.quodlibet",
|
||||
nil
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
-(BOOL)shouldInterceptMediaKeyEvents
|
||||
{
|
||||
BOOL shouldIntercept = NO;
|
||||
@synchronized(self) {
|
||||
shouldIntercept = _shouldInterceptMediaKeyEvents;
|
||||
}
|
||||
return shouldIntercept;
|
||||
}
|
||||
|
||||
-(void)pauseTapOnTapThread:(BOOL)yeahno
|
||||
{
|
||||
CGEventTapEnable(self->_eventPort, yeahno);
|
||||
}
|
||||
-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting
|
||||
{
|
||||
BOOL oldSetting;
|
||||
@synchronized(self) {
|
||||
oldSetting = _shouldInterceptMediaKeyEvents;
|
||||
_shouldInterceptMediaKeyEvents = newSetting;
|
||||
}
|
||||
if(_tapThreadRL && oldSetting != newSetting) {
|
||||
id grab = [self grab];
|
||||
[grab pauseTapOnTapThread:newSetting];
|
||||
NSTimer *timer = [NSTimer timerWithTimeInterval:0 invocation:[grab invocation] repeats:NO];
|
||||
CFRunLoopAddTimer(_tapThreadRL, (CFRunLoopTimerRef)timer, kCFRunLoopCommonModes);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
#pragma mark -
|
||||
#pragma mark Event tap callbacks
|
||||
|
||||
// Note: method called on background thread
|
||||
|
||||
static CGEventRef tapEventCallback2(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
||||
{
|
||||
SPMediaKeyTap *self = refcon;
|
||||
|
||||
if(type == kCGEventTapDisabledByTimeout) {
|
||||
NSLog(@"Media key event tap was disabled by timeout");
|
||||
CGEventTapEnable(self->_eventPort, TRUE);
|
||||
return event;
|
||||
} else if(type == kCGEventTapDisabledByUserInput) {
|
||||
// Was disabled manually by -[pauseTapOnTapThread]
|
||||
return event;
|
||||
}
|
||||
NSEvent *nsEvent = nil;
|
||||
@try {
|
||||
nsEvent = [NSEvent eventWithCGEvent:event];
|
||||
}
|
||||
@catch (NSException * e) {
|
||||
NSLog(@"Strange CGEventType: %d: %@", type, e);
|
||||
assert(0);
|
||||
return event;
|
||||
}
|
||||
|
||||
if (type != NX_SYSDEFINED || [nsEvent subtype] != SPSystemDefinedEventMediaKeys)
|
||||
return event;
|
||||
|
||||
int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16);
|
||||
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND && keyCode != NX_KEYTYPE_PREVIOUS && keyCode != NX_KEYTYPE_NEXT)
|
||||
return event;
|
||||
|
||||
if (![self shouldInterceptMediaKeyEvents])
|
||||
return event;
|
||||
|
||||
[nsEvent retain]; // matched in handleAndReleaseMediaKeyEvent:
|
||||
[self performSelectorOnMainThread:@selector(handleAndReleaseMediaKeyEvent:) withObject:nsEvent waitUntilDone:NO];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
||||
{
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
CGEventRef ret = tapEventCallback2(proxy, type, event, refcon);
|
||||
[pool drain];
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// event will have been retained in the other thread
|
||||
-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event {
|
||||
[event autorelease];
|
||||
|
||||
[_delegate mediaKeyTap:self receivedMediaKeyEvent:event];
|
||||
}
|
||||
|
||||
|
||||
-(void)eventTapThread
|
||||
{
|
||||
_tapThreadRL = CFRunLoopGetCurrent();
|
||||
CFRunLoopAddSource(_tapThreadRL, _eventPortSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopRun();
|
||||
}
|
||||
|
||||
#pragma mark Task switching callbacks
|
||||
|
||||
NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey = @"SPApplicationsNeedingMediaKeys";
|
||||
NSString *kIgnoreMediaKeysDefaultsKey = @"SPIgnoreMediaKeys";
|
||||
|
||||
|
||||
|
||||
-(void)mediaKeyAppListChanged
|
||||
{
|
||||
if([_mediaKeyAppList count] == 0) return;
|
||||
|
||||
/*NSLog(@"--");
|
||||
int i = 0;
|
||||
for (NSValue *psnv in _mediaKeyAppList) {
|
||||
ProcessSerialNumber psn; [psnv getValue:&psn];
|
||||
NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary(
|
||||
&psn,
|
||||
kProcessDictionaryIncludeAllInformationMask
|
||||
) autorelease];
|
||||
NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey];
|
||||
NSLog(@"%d: %@", i++, bundleIdentifier);
|
||||
}*/
|
||||
|
||||
ProcessSerialNumber mySerial, topSerial;
|
||||
GetCurrentProcess(&mySerial);
|
||||
[[_mediaKeyAppList objectAtIndex:0] getValue:&topSerial];
|
||||
|
||||
Boolean same;
|
||||
OSErr err = SameProcess(&mySerial, &topSerial, &same);
|
||||
[self setShouldInterceptMediaKeyEvents:(err == noErr && same)];
|
||||
|
||||
}
|
||||
-(void)appIsNowFrontmost:(ProcessSerialNumber)psn
|
||||
{
|
||||
NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)];
|
||||
|
||||
NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary(
|
||||
&psn,
|
||||
kProcessDictionaryIncludeAllInformationMask
|
||||
) autorelease];
|
||||
NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey];
|
||||
|
||||
NSArray *whitelistIdentifiers = [[NSUserDefaults standardUserDefaults] arrayForKey:kMediaKeyUsingBundleIdentifiersDefaultsKey];
|
||||
if(![whitelistIdentifiers containsObject:bundleIdentifier]) return;
|
||||
|
||||
[_mediaKeyAppList removeObject:psnv];
|
||||
[_mediaKeyAppList insertObject:psnv atIndex:0];
|
||||
[self mediaKeyAppListChanged];
|
||||
}
|
||||
-(void)appTerminated:(ProcessSerialNumber)psn
|
||||
{
|
||||
NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)];
|
||||
[_mediaKeyAppList removeObject:psnv];
|
||||
[self mediaKeyAppListChanged];
|
||||
}
|
||||
|
||||
static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData)
|
||||
{
|
||||
SPMediaKeyTap *self = (id)userData;
|
||||
|
||||
ProcessSerialNumber newSerial;
|
||||
GetFrontProcess(&newSerial);
|
||||
|
||||
[self appIsNowFrontmost:newSerial];
|
||||
|
||||
return CallNextEventHandler(nextHandler, evt);
|
||||
}
|
||||
|
||||
static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData)
|
||||
{
|
||||
SPMediaKeyTap *self = (id)userData;
|
||||
|
||||
ProcessSerialNumber deadPSN;
|
||||
|
||||
GetEventParameter(
|
||||
evt,
|
||||
kEventParamProcessID,
|
||||
typeProcessSerialNumber,
|
||||
NULL,
|
||||
sizeof(deadPSN),
|
||||
NULL,
|
||||
&deadPSN
|
||||
);
|
||||
|
||||
|
||||
[self appTerminated:deadPSN];
|
||||
return CallNextEventHandler(nextHandler, evt);
|
||||
}
|
||||
|
||||
@end
|
|
@ -27,7 +27,9 @@
|
|||
'libs_loc': '../../../Libraries',
|
||||
'src_loc': '../SourceFiles',
|
||||
'res_loc': '../Resources',
|
||||
'minizip_loc': '../ThirdParty/minizip',
|
||||
'third_party_loc': '../ThirdParty',
|
||||
'minizip_loc': '<(third_party_loc)/minizip',
|
||||
'sp_media_key_tap_loc': '<(third_party_loc)/SPMediaKeyTap',
|
||||
'style_files': [
|
||||
'<(res_loc)/basic.style',
|
||||
'<(res_loc)/basic_types.style',
|
||||
|
@ -85,6 +87,7 @@
|
|||
'<(libs_loc)/ffmpeg',
|
||||
'<(libs_loc)/openal-soft/include',
|
||||
'<(minizip_loc)',
|
||||
'<(sp_media_key_tap_loc)',
|
||||
],
|
||||
'sources': [
|
||||
'<@(qrc_files)',
|
||||
|
@ -530,6 +533,11 @@
|
|||
'<(src_loc)/window/slide_animation.h',
|
||||
'<(src_loc)/window/top_bar_widget.cpp',
|
||||
'<(src_loc)/window/top_bar_widget.h',
|
||||
|
||||
'<(sp_media_key_tap_loc)/SPMediaKeyTap.m',
|
||||
'<(sp_media_key_tap_loc)/SPMediaKeyTap.h',
|
||||
'<(sp_media_key_tap_loc)/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m',
|
||||
'<(sp_media_key_tap_loc)/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h',
|
||||
],
|
||||
'conditions': [
|
||||
[ '"<(official_build_target)" != ""', {
|
||||
|
@ -570,6 +578,10 @@
|
|||
'<(src_loc)/platform/mac/main_window_mac.h',
|
||||
'<(src_loc)/platform/mac/notifications_manager_mac.mm',
|
||||
'<(src_loc)/platform/mac/notifications_manager_mac.h',
|
||||
'<(sp_media_key_tap_loc)/SPMediaKeyTap.m',
|
||||
'<(sp_media_key_tap_loc)/SPMediaKeyTap.h',
|
||||
'<(sp_media_key_tap_loc)/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m',
|
||||
'<(sp_media_key_tap_loc)/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h',
|
||||
],
|
||||
}],
|
||||
[ '"<(build_win)" != "1"', {
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
],
|
||||
},
|
||||
'qt_version%': '<(qt_version)',
|
||||
'qt_loc_unix': '/usr/local/tdesktop/Qt-<(qt_version)',
|
||||
'conditions': [
|
||||
[ 'build_win', {
|
||||
'qt_lib_prefix': '<(ld_lib_prefix)',
|
||||
|
@ -65,11 +66,7 @@
|
|||
'qcocoa',
|
||||
],
|
||||
}],
|
||||
[ 'build_macold', {
|
||||
'qt_loc_unix': '/usr/local/Qt-<(qt_version)'
|
||||
}],
|
||||
[ 'build_mac and not build_macold', {
|
||||
'qt_loc_unix': '/usr/local/tdesktop/Qt-<(qt_version)',
|
||||
'qt_libs': [
|
||||
'<@(qt_libs)',
|
||||
'Qt5Core',
|
||||
|
@ -78,7 +75,6 @@
|
|||
],
|
||||
}],
|
||||
[ 'build_linux', {
|
||||
'qt_loc_unix': '/usr/local/tdesktop/Qt-<(qt_version)',
|
||||
'qt_lib_prefix': 'lib',
|
||||
'qt_lib_debug_postfix': '.a',
|
||||
'qt_lib_release_postfix': '.a',
|
||||
|
|
|
@ -65,7 +65,7 @@ Building
|
|||
|
||||
|
||||
# Build patched Qt
|
||||
cd "$srcdir/Libraries/QtStatic"
|
||||
cd "$qtdir"
|
||||
./configure -prefix "$srcdir/qt" -release -opensource -confirm-license -qt-zlib \
|
||||
-qt-libpng -qt-libjpeg -qt-freetype -qt-harfbuzz -qt-pcre -qt-xcb \
|
||||
-qt-xkbcommon-x11 -no-opengl -no-gtkstyle -static -nomake examples -nomake tests
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
Choose a folder for the future build, for example **/Users/user/TBuild** There you will have two folders, **Libraries** for third-party libs and **tdesktop** (or **tdesktop-master**) for the app.
|
||||
|
||||
**IMPORTANT** You are required to build and install Qt 5.6.0 from the [Xcode 7](building-xcode.md) instructions first.
|
||||
|
||||
###Clone source code
|
||||
|
||||
By git – in Terminal go to **/Users/user/TBuild** and run
|
||||
|
@ -165,8 +163,8 @@ Then in Terminal go to **/Users/user/TBuild/Libraries/ffmpeg** and run
|
|||
|
||||
In Terminal go to **/Users/user/TBuild/Libraries** and run:
|
||||
|
||||
git clone git://code.qt.io/qt/qt5.git QtStatic
|
||||
cd QtStatic
|
||||
git clone git://code.qt.io/qt/qt5.git qt5_3_2
|
||||
cd qt5_3_2
|
||||
git checkout 5.3
|
||||
perl init-repository --module-subset=qtbase,qtimageformats
|
||||
git checkout v5.3.2
|
||||
|
@ -175,19 +173,19 @@ In Terminal go to **/Users/user/TBuild/Libraries** and run:
|
|||
|
||||
#####Apply the patch
|
||||
|
||||
From **/Users/user/TBuild/Libraries/QtStatic/qtbase**, run:
|
||||
From **/Users/user/TBuild/Libraries/qt5_3_2/qtbase**, run:
|
||||
|
||||
git apply ../../../tdesktop/Telegram/Patches/qtbase_5_3_2.diff
|
||||
|
||||
From **/Users/user/TBuild/Libraries/QtStatic/qtimageformats**, run:
|
||||
From **/Users/user/TBuild/Libraries/qt5_3_2/qtimageformats**, run:
|
||||
|
||||
git apply ../../../tdesktop/Telegram/Patches/qtimageformats_5_3_2.diff
|
||||
|
||||
#####Building library
|
||||
|
||||
Go to **/Users/user/TBuild/Libraries/QtStatic** and run:
|
||||
Go to **/Users/user/TBuild/Libraries/qt5_3_2** and run:
|
||||
|
||||
./configure -debug-and-release -force-debug-info -opensource -confirm-license -static -opengl desktop -nomake examples -nomake tests -platform macx-g++
|
||||
./configure -prefix "/usr/local/tdesktop/Qt-5.3.2" -debug-and-release -force-debug-info -opensource -confirm-license -static -opengl desktop -nomake examples -nomake tests -platform macx-g++
|
||||
make -j4
|
||||
sudo make -j4 install
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
##Build instructions for Xcode 7.2.1
|
||||
##Build instructions for Xcode 8.0
|
||||
|
||||
###Prepare folder
|
||||
|
||||
|
|
Loading…
Reference in New Issue