Skip to content

Commit 6555ba0

Browse files
Samuel Gaistmsorvig
authored andcommitted
Backport implementation of OS X QSystemTrayIcon from Qt 5
This patch aims to bring support of OS X >= 10.8 notification center and update the growl support code. [ChangeLog][OS X][Nofication] Added support for OS X 10.8 and upper notification center. Task-number: QTBUG-21830 Change-Id: Iad19c5e3a915e2caf15730a27ac762c9c11e493c Reviewed-by: Morten Johan Sørvig <[email protected]>
1 parent 97b85f4 commit 6555ba0

File tree

1 file changed

+110
-62
lines changed

1 file changed

+110
-62
lines changed

src/gui/util/qsystemtrayicon_mac.mm

Lines changed: 110 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@
9999
@class QT_MANGLE_NAMESPACE(QNSMenu);
100100
@class QT_MANGLE_NAMESPACE(QNSImageView);
101101

102-
@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject {
102+
@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject
103+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
104+
<NSUserNotificationCenterDelegate>
105+
#endif
106+
{
103107
NSStatusItem *item;
104108
QSystemTrayIcon *icon;
105109
QSystemTrayIconPrivate *iconPrivate;
@@ -112,6 +116,11 @@ -(NSStatusItem*)item;
112116
-(QRectF)geometry;
113117
- (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton;
114118
- (void)doubleClickSelector:(id)sender;
119+
120+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
121+
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification;
122+
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
123+
#endif
115124
@end
116125

117126
@interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView {
@@ -148,12 +157,27 @@ -(void)selectedAction:(id)item;
148157
QSystemTrayIconSys(QSystemTrayIcon *icon, QSystemTrayIconPrivate *d) {
149158
QMacCocoaAutoReleasePool pool;
150159
item = [[QT_MANGLE_NAMESPACE(QNSStatusItem) alloc] initWithIcon:icon iconPrivate:d];
160+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
161+
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
162+
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:item];
163+
}
164+
#endif
151165
}
152166
~QSystemTrayIconSys() {
153167
QMacCocoaAutoReleasePool pool;
154168
[[[item item] view] setHidden: YES];
169+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
170+
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
171+
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
172+
}
173+
#endif
155174
[item release];
156175
}
176+
177+
void emitMessageClicked() {
178+
emit [item icon]->messageClicked();
179+
}
180+
157181
QT_MANGLE_NAMESPACE(QNSStatusItem) *item;
158182
};
159183

@@ -233,70 +257,80 @@ -(void)selectedAction:(id)item;
233257

234258
void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon icon, int)
235259
{
260+
if (!sys)
261+
return;
262+
263+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
264+
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
265+
NSUserNotification *notification = [[NSUserNotification alloc] init];
266+
notification.title = [NSString stringWithUTF8String:title.toUtf8().data()];
267+
notification.informativeText = [NSString stringWithUTF8String:message.toUtf8().data()];
268+
269+
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
270+
271+
return;
272+
}
273+
#endif
236274

237-
if(sys) {
238275
#ifdef QT_MAC_SYSTEMTRAY_USE_GROWL
239-
// Make sure that we have Growl installed on the machine we are running on.
240-
QCFType<CFURLRef> cfurl;
241-
OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator,
242-
CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
243-
if (status == kLSApplicationNotFoundErr)
244-
return;
245-
QCFType<CFBundleRef> bundle = CFBundleCreate(0, cfurl);
246-
247-
if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"),
248-
kCFCompareCaseInsensitive | kCFCompareBackwards) != kCFCompareEqualTo)
249-
return;
250-
QPixmap notificationIconPixmap;
251-
if(icon == QSystemTrayIcon::Information)
252-
notificationIconPixmap = QApplication::style()->standardPixmap(QStyle::SP_MessageBoxInformation);
253-
else if(icon == QSystemTrayIcon::Warning)
254-
notificationIconPixmap = QApplication::style()->standardPixmap(QStyle::SP_MessageBoxWarning);
255-
else if(icon == QSystemTrayIcon::Critical)
256-
notificationIconPixmap = QApplication::style()->standardPixmap(QStyle::SP_MessageBoxCritical);
257-
QTemporaryFile notificationIconFile;
258-
QString notificationType(QLatin1String("Notification")), notificationIcon, notificationApp(QApplication::applicationName());
259-
if(notificationApp.isEmpty())
260-
notificationApp = QLatin1String("Application");
261-
if(!notificationIconPixmap.isNull() && notificationIconFile.open()) {
262-
QImageWriter writer(&notificationIconFile, "PNG");
263-
if(writer.write(notificationIconPixmap.toImage()))
264-
notificationIcon = QLatin1String("image from location \"file://") + notificationIconFile.fileName() + QLatin1String("\"");
265-
}
266-
const QString script(QLatin1String(
267-
"tell application \"GrowlHelperApp\"\n"
268-
"-- Make a list of all the notification types (all)\n"
269-
"set the allNotificationsList to {\"") + notificationType + QLatin1String("\"}\n"
270-
271-
"-- Make a list of the notifications (enabled)\n"
272-
"set the enabledNotificationsList to {\"") + notificationType + QLatin1String("\"}\n"
273-
274-
"-- Register our script with growl.\n"
275-
"register as application \"") + notificationApp + QLatin1String("\" all notifications allNotificationsList default notifications enabledNotificationsList\n"
276-
277-
"-- Send a Notification...\n") +
278-
QLatin1String("notify with name \"") + notificationType +
279-
QLatin1String("\" title \"") + title +
280-
QLatin1String("\" description \"") + message +
281-
QLatin1String("\" application name \"") + notificationApp +
282-
QLatin1String("\" ") + notificationIcon +
283-
QLatin1String("\nend tell"));
284-
qt_mac_execute_apple_script(script, 0);
285-
#elif 0
286-
Q_Q(QSystemTrayIcon);
287-
NSView *v = [[sys->item item] view];
288-
NSWindow *w = [v window];
289-
w = [[sys->item item] window];
290-
qDebug() << w << v;
291-
QPoint p(qRound([w frame].origin.x), qRound([w frame].origin.y));
292-
qDebug() << p;
293-
QBalloonTip::showBalloon(icon, message, title, q, QPoint(0, 0), msecs);
276+
// Make sure that we have Growl installed on the machine we are running on.
277+
QCFType<CFURLRef> cfurl;
278+
OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator,
279+
CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
280+
if (status == kLSApplicationNotFoundErr)
281+
return;
282+
QCFType<CFBundleRef> bundle = CFBundleCreate(0, cfurl);
283+
284+
if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"),
285+
kCFCompareCaseInsensitive | kCFCompareBackwards) != kCFCompareEqualTo)
286+
return;
287+
288+
QPixmap notificationIconPixmap;
289+
if (icon == QSystemTrayIcon::Information)
290+
notificationIconPixmap = QApplication::style()->standardPixmap(QStyle::SP_MessageBoxInformation);
291+
else if (icon == QSystemTrayIcon::Warning)
292+
notificationIconPixmap = QApplication::style()->standardPixmap(QStyle::SP_MessageBoxWarning);
293+
else if (icon == QSystemTrayIcon::Critical)
294+
notificationIconPixmap = QApplication::style()->standardPixmap(QStyle::SP_MessageBoxCritical);
295+
296+
QTemporaryFile notificationIconFile;
297+
QString notificationType(QLatin1String("Notification")), notificationIcon, notificationApp(QApplication::applicationName());
298+
if (notificationApp.isEmpty())
299+
notificationApp = QLatin1String("Application");
300+
if (!notificationIconPixmap.isNull() && notificationIconFile.open()) {
301+
QImageWriter writer(&notificationIconFile, "PNG");
302+
if (writer.write(notificationIconPixmap.toImage()))
303+
notificationIcon = QLatin1String("image from location \"file://") + notificationIconFile.fileName() + QLatin1String("\"");
304+
}
305+
const QString script(QLatin1String(
306+
"tell application \"System Events\"\n"
307+
"set isRunning to (count of (every process whose bundle identifier is \"com.Growl.GrowlHelperApp\")) > 0\n"
308+
"end tell\n"
309+
"if isRunning\n"
310+
"tell application id \"com.Growl.GrowlHelperApp\"\n"
311+
"-- Make a list of all the notification types (all)\n"
312+
"set the allNotificationsList to {\"") + notificationType + QLatin1String("\"}\n"
313+
314+
"-- Make a list of the notifications (enabled)\n"
315+
"set the enabledNotificationsList to {\"") + notificationType + QLatin1String("\"}\n"
316+
317+
"-- Register our script with growl.\n"
318+
"register as application \"") + notificationApp + QLatin1String("\" all notifications allNotificationsList default notifications enabledNotificationsList\n"
319+
320+
"-- Send a Notification...\n") +
321+
QLatin1String("notify with name \"") + notificationType +
322+
QLatin1String("\" title \"") + title +
323+
QLatin1String("\" description \"") + message +
324+
QLatin1String("\" application name \"") + notificationApp +
325+
QLatin1String("\" ") + notificationIcon +
326+
QLatin1String("\nend tell\nend if"));
327+
qt_mac_execute_apple_script(script, 0);
294328
#else
295-
Q_UNUSED(icon);
296-
Q_UNUSED(title);
297-
Q_UNUSED(message);
329+
Q_UNUSED(icon);
330+
Q_UNUSED(title);
331+
Q_UNUSED(message);
298332
#endif
299-
}
333+
300334
}
301335
QT_END_NAMESPACE
302336

@@ -357,7 +391,7 @@ -(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton
357391
[nsaltimage release];
358392
}
359393

360-
if ((clickCount == 2)) {
394+
if (clickCount == 2) {
361395
[self menuTrackingDone:nil];
362396
[parent doubleClickSelector:self];
363397
} else {
@@ -475,6 +509,20 @@ - (void)doubleClickSelector:(id)sender {
475509
qtsystray_sendActivated(icon, QSystemTrayIcon::DoubleClick);
476510
}
477511

512+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
513+
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification {
514+
Q_UNUSED(center);
515+
Q_UNUSED(notification);
516+
return YES;
517+
}
518+
519+
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification {
520+
Q_UNUSED(center);
521+
Q_UNUSED(notification);
522+
emit iconPrivate->sys->emitMessageClicked();
523+
}
524+
#endif
525+
478526
@end
479527

480528
class QSystemTrayIconQMenu : public QMenu

0 commit comments

Comments
 (0)