aboutsummaryrefslogtreecommitdiff
path: root/backends
diff options
context:
space:
mode:
authorThierry Crozat2014-01-26 20:40:36 +0000
committerThierry Crozat2014-02-23 21:54:47 +0000
commit6d7fcdd2b544fa4eb29988bd627af94aa8238d6c (patch)
tree0636a564e386edaff384bd9bdc47266bc8dbcd74 /backends
parent6673472a2266373a96959c741dc922b40e975179 (diff)
downloadscummvm-rg350-6d7fcdd2b544fa4eb29988bd627af94aa8238d6c.tar.gz
scummvm-rg350-6d7fcdd2b544fa4eb29988bd627af94aa8238d6c.tar.bz2
scummvm-rg350-6d7fcdd2b544fa4eb29988bd627af94aa8238d6c.zip
OSX: Implement TaskbarManager for Mac OS X
This implements count badge, progress bar, and icon overlay. It uses the NSDockTile API which is available since OS X 10.5. The code compiles and run on older system but without doing anything.
Diffstat (limited to 'backends')
-rw-r--r--backends/module.mk3
-rw-r--r--backends/platform/sdl/macosx/macosx.cpp11
-rw-r--r--backends/platform/sdl/macosx/macosx.h1
-rw-r--r--backends/taskbar/macosx/macosx-taskbar.h57
-rw-r--r--backends/taskbar/macosx/macosx-taskbar.mm238
5 files changed, 309 insertions, 1 deletions
diff --git a/backends/module.mk b/backends/module.mk
index 1222d9a363..34e2928419 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -97,7 +97,8 @@ ifdef MACOSX
MODULE_OBJS += \
midi/coreaudio.o \
midi/coremidi.o \
- updates/macosx/macosx-updates.o
+ updates/macosx/macosx-updates.o \
+ taskbar/macosx/macosx-taskbar.o
endif
ifdef WIN32
diff --git a/backends/platform/sdl/macosx/macosx.cpp b/backends/platform/sdl/macosx/macosx.cpp
index 301dc44b7b..924e33b6e3 100644
--- a/backends/platform/sdl/macosx/macosx.cpp
+++ b/backends/platform/sdl/macosx/macosx.cpp
@@ -31,6 +31,7 @@
#include "backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h"
#include "backends/platform/sdl/macosx/appmenu_osx.h"
#include "backends/updates/macosx/macosx-updates.h"
+#include "backends/taskbar/macosx/macosx-taskbar.h"
#include "common/archive.h"
#include "common/config-manager.h"
@@ -45,6 +46,16 @@ OSystem_MacOSX::OSystem_MacOSX()
OSystem_POSIX("Library/Preferences/ScummVM Preferences") {
}
+void OSystem_MacOSX::init() {
+#if defined(USE_TASKBAR)
+ // Initialize taskbar manager
+ _taskbarManager = new MacOSXTaskbarManager();
+#endif
+
+ // Invoke parent implementation of this method
+ OSystem_POSIX::init();
+}
+
void OSystem_MacOSX::initBackend() {
// Create the mixer manager
if (_mixer == 0) {
diff --git a/backends/platform/sdl/macosx/macosx.h b/backends/platform/sdl/macosx/macosx.h
index e5a72bf393..50cef60353 100644
--- a/backends/platform/sdl/macosx/macosx.h
+++ b/backends/platform/sdl/macosx/macosx.h
@@ -35,6 +35,7 @@ public:
virtual Common::String getSystemLanguage() const;
+ virtual void init();
virtual void initBackend();
virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
virtual void setupIcon();
diff --git a/backends/taskbar/macosx/macosx-taskbar.h b/backends/taskbar/macosx/macosx-taskbar.h
new file mode 100644
index 0000000000..5d5b9d02cd
--- /dev/null
+++ b/backends/taskbar/macosx/macosx-taskbar.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BACKEND_MACOSX_TASKBAR_H
+#define BACKEND_MACOSX_TASKBAR_H
+
+#if defined(MACOSX) && defined(USE_TASKBAR)
+
+#include "common/str.h"
+#include "common/taskbar.h"
+
+class MacOSXTaskbarManager : public Common::TaskbarManager {
+public:
+ MacOSXTaskbarManager();
+ virtual ~MacOSXTaskbarManager();
+
+ virtual void setOverlayIcon(const Common::String &name, const Common::String &description);
+ virtual void setProgressValue(int completed, int total);
+ virtual void setProgressState(TaskbarProgressState state);
+ virtual void setCount(int count);
+ virtual void notifyError();
+ virtual void clearError();
+
+private:
+ Common::String getIconPath(const Common::String&);
+
+ void initApplicationIconView();
+ void clearApplicationIconView();
+
+ void initOverlayIconView();
+ void clearOverlayIconView();
+
+ double _progress;
+};
+
+#endif
+
+#endif // BACKEND_MACOSX_TASKBAR_H
diff --git a/backends/taskbar/macosx/macosx-taskbar.mm b/backends/taskbar/macosx/macosx-taskbar.mm
new file mode 100644
index 0000000000..ae087dfb85
--- /dev/null
+++ b/backends/taskbar/macosx/macosx-taskbar.mm
@@ -0,0 +1,238 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "common/scummsys.h"
+
+#if defined(MACOSX) && defined(USE_TASKBAR)
+
+// NSDockTile was introduced with Mac OS X 10.5.
+// Try provide backward compatibility by avoiding NSDockTile symbols.
+
+// TODO: Implement recent list, maybe as a custom menu on dock tile when app is not running
+// See Dock Tile plug-in at https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/CreatingaDockTilePlug-in/CreatingaDockTilePlug-in.html
+
+#include "backends/taskbar/macosx/macosx-taskbar.h"
+#include "common/config-manager.h"
+#include "common/file.h"
+
+#include <AppKit/NSApplication.h>
+#include <AppKit/NSImage.h>
+#include <Foundation/NSString.h>
+#include <AppKit/NSImageView.h>
+#include <AppKit/NSColor.h>
+#include <AppKit/NSBezierPath.h>
+#include <CoreFoundation/CFString.h>
+
+id _dockTile;
+NSImageView *_applicationIconView;
+NSImageView *_overlayIconView;
+
+// Using a NSProgressIndicator as a sub-view of the NSDockTile view does not work properly.
+// The progress indicator is grayed out and display no progress. So instead the bar is drawn
+// manually, which is a bit more work :(
+
+MacOSXTaskbarManager::MacOSXTaskbarManager() : _progress(-1.0) {
+ if ([NSApp respondsToSelector:@selector(dockTile)])
+ _dockTile = [NSApp dockTile];
+ _applicationIconView = nil;
+ _overlayIconView = nil;
+}
+
+MacOSXTaskbarManager::~MacOSXTaskbarManager() {
+ clearApplicationIconView();
+}
+
+void MacOSXTaskbarManager::initApplicationIconView() {
+ if (_dockTile == nil)
+ return;
+ if (_applicationIconView == nil) {
+ _applicationIconView = [[NSImageView alloc] init];
+ [_applicationIconView setImage:[NSApp applicationIconImage]];
+ [_dockTile performSelector:@selector(setContentView:) withObject:_applicationIconView];
+ }
+}
+
+void MacOSXTaskbarManager::clearApplicationIconView() {
+ if (_dockTile == nil)
+ return;
+ [_dockTile performSelector:@selector(setContentView:) withObject:nil];
+ [_applicationIconView release];
+ _applicationIconView = nil;
+}
+
+void MacOSXTaskbarManager::initOverlayIconView() {
+ if (_dockTile == nil)
+ return;
+ if (_overlayIconView == nil) {
+ const double overlaySize = 0.75;
+ initApplicationIconView();
+ NSSize size = [_applicationIconView frame].size;
+ _overlayIconView = [[NSImageView alloc] initWithFrame:NSMakeRect(size.width * (1.0-overlaySize), 0.0f, size.width * overlaySize, size.height * overlaySize)];
+ [_overlayIconView setImageAlignment:NSImageAlignBottomRight];
+ [_applicationIconView addSubview:_overlayIconView];
+ [_overlayIconView release];
+ }
+}
+
+void MacOSXTaskbarManager::clearOverlayIconView() {
+ if (_progress < 0.0)
+ clearApplicationIconView();
+ else
+ [_overlayIconView removeFromSuperview];
+ _overlayIconView = nil;
+}
+
+void MacOSXTaskbarManager::setOverlayIcon(const Common::String &name, const Common::String &description) {
+ if (_dockTile == nil)
+ return;
+
+ if (name.empty()) {
+ clearOverlayIconView();
+ [_dockTile performSelector:@selector(display)];
+ return;
+ }
+
+ Common::String path = getIconPath(name);
+ if (path.empty())
+ return;
+
+ initOverlayIconView();
+
+ CFStringRef imageFile = CFStringCreateWithCString(0, path.c_str(), kCFStringEncodingASCII);
+ NSImage* image = [[NSImage alloc] initWithContentsOfFile:(NSString *)imageFile];
+ [_overlayIconView setImage:image];
+ [image release];
+ CFRelease(imageFile);
+
+ [_dockTile performSelector:@selector(display)];
+}
+
+void MacOSXTaskbarManager::setProgressValue(int completed, int total) {
+ if (_dockTile == nil)
+ return;
+
+ if (total > 0)
+ _progress = (double)completed / (double)total;
+ else if (_progress < 0)
+ _progress = 0.0;
+
+ NSImage *mainIcon = [[NSApp applicationIconImage] copy];
+ double barSize = [mainIcon size].width;
+ double progressSize = barSize * _progress;
+ [mainIcon lockFocus];
+ [[NSColor colorWithDeviceRed:(40.0/255.0) green:(120.0/255.0) blue:(255.0/255.0) alpha:0.78] set];
+ [NSBezierPath fillRect:NSMakeRect(0, 0, progressSize, 11)];
+ [[NSColor colorWithDeviceRed:(241.0/255.0) green:(241.0/255.0) blue:(241.0/255.0) alpha:0.78] set];
+ [NSBezierPath fillRect:NSMakeRect(progressSize, 0, barSize-progressSize, 11)];
+ [mainIcon unlockFocus];
+
+ initApplicationIconView();
+ [_applicationIconView setImage:mainIcon];
+ [mainIcon release];
+
+ [_dockTile performSelector:@selector(display)];
+}
+
+void MacOSXTaskbarManager::setProgressState(TaskbarProgressState state) {
+ if (_dockTile == nil)
+ return;
+
+ // Only support two states: visible and not visible.
+ if (state == kTaskbarNoProgress) {
+ _progress = -1.0;
+ if (_overlayIconView == nil)
+ clearApplicationIconView();
+ else if (_applicationIconView != nil)
+ [_applicationIconView setImage:[NSApp applicationIconImage]];
+ return;
+ }
+
+ setProgressValue(-1, -1);
+}
+
+void MacOSXTaskbarManager::setCount(int count) {
+ if (_dockTile == nil)
+ return;
+
+ if (count > 0)
+ [_dockTile performSelector:@selector(setBadgeLabel:) withObject:[NSString stringWithFormat:@"%d", count]];
+ else
+ [_dockTile performSelector:@selector(setBadgeLabel:) withObject:nil];
+}
+
+void MacOSXTaskbarManager::notifyError() {
+ if (_dockTile == nil)
+ return;
+
+ // NSImageNameCaution was introduced in 10.6.
+ // For compatibility with older systems we should use something else (e.g. overlay label
+ // or our own icon).
+ //initOverlayIconView();
+ //[_overlayIconView setImage:[NSImage imageNamed:NSImageNameCaution]];
+ //[_dockTile performSelector:@selector(display)];
+}
+
+void MacOSXTaskbarManager::clearError() {
+ if (_dockTile == nil)
+ return;
+
+ clearOverlayIconView();
+ [_dockTile performSelector:@selector(display)];
+ return;
+}
+
+Common::String MacOSXTaskbarManager::getIconPath(const Common::String& target) {
+ // We first try to look for a iconspath configuration variable then
+ // fallback to the extra path
+ //
+ // Icons can be either in a subfolder named "icons" or directly in the path
+
+ Common::String iconsPath = ConfMan.get("iconspath");
+ Common::String extraPath = ConfMan.get("extrapath");
+
+#define TRY_ICON_PATH(path) { \
+Common::FSNode node((path)); \
+if (node.exists()) \
+return (path); \
+}
+
+ if (!iconsPath.empty()) {
+ TRY_ICON_PATH(iconsPath + "/" + target + ".png");
+ TRY_ICON_PATH(iconsPath + "/" + ConfMan.get("gameid") + ".png");
+ TRY_ICON_PATH(iconsPath + "/icons/" + target + ".png");
+ TRY_ICON_PATH(iconsPath + "/icons/" + ConfMan.get("gameid") + ".png");
+ }
+
+ if (!extraPath.empty()) {
+ TRY_ICON_PATH(extraPath + "/" + target + ".png");
+ TRY_ICON_PATH(extraPath + "/" + ConfMan.get("gameid") + ".png");
+ TRY_ICON_PATH(extraPath + "/icons/" + target + ".png");
+ TRY_ICON_PATH(extraPath + "/icons/" + ConfMan.get("gameid") + ".png");
+ }
+
+ return "";
+}
+
+
+#endif