ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

macosx-taskbar.mm

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 // Disable symbol overrides so that we can use system headers
00024 #define FORBIDDEN_SYMBOL_ALLOW_ALL
00025 #include "common/scummsys.h"
00026 
00027 #if defined(MACOSX) && defined(USE_TASKBAR)
00028 
00029 #include "backends/taskbar/macosx/macosx-taskbar.h"
00030 #include "common/config-manager.h"
00031 #include "common/file.h"
00032 #include "backends/platform/sdl/macosx/macosx-compat.h"
00033 #include <AppKit/NSApplication.h>
00034 #include <AppKit/NSImage.h>
00035 #include <Foundation/NSString.h>
00036 #include <Foundation/NSDictionary.h>
00037 #include <Foundation/NSArray.h>
00038 #include <Foundation/NSUserDefaults.h>
00039 #include <AppKit/NSImageView.h>
00040 #include <AppKit/NSColor.h>
00041 #include <AppKit/NSBezierPath.h>
00042 #include <CoreFoundation/CFString.h>
00043 
00044 // NSDockTile was introduced with Mac OS X 10.5.
00045 // Try provide backward compatibility by avoiding NSDockTile symbols.
00046 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
00047 typedef id NSDockTilePtr;
00048 #else
00049 #include <AppKit/NSDockTile.h>
00050 typedef NSDockTile * NSDockTilePtr;
00051 #endif
00052 
00053 NSDockTilePtr _dockTile;
00054 NSImageView *_applicationIconView;
00055 NSImageView *_overlayIconView;
00056 
00057 // Using a NSProgressIndicator as a sub-view of the NSDockTile view does not work properly.
00058 // The progress indicator is grayed out and display no progress. So instead the bar is drawn
00059 // manually, which is a bit more work :(
00060 
00061 MacOSXTaskbarManager::MacOSXTaskbarManager() : _progress(-1.0) {
00062     if ([NSApp respondsToSelector:@selector(dockTile)])
00063         _dockTile = [NSApp dockTile];
00064     _applicationIconView = nil;
00065     _overlayIconView = nil;
00066 }
00067 
00068 MacOSXTaskbarManager::~MacOSXTaskbarManager() {
00069     clearApplicationIconView();
00070 }
00071 
00072 void MacOSXTaskbarManager::initApplicationIconView() {
00073     if (_dockTile == nil)
00074         return;
00075     if (_applicationIconView == nil) {
00076         _applicationIconView = [[NSImageView alloc] init];
00077         [_applicationIconView setImage:[NSApp applicationIconImage]];
00078         [_dockTile performSelector:@selector(setContentView:) withObject:_applicationIconView];
00079     }
00080 }
00081 
00082 void MacOSXTaskbarManager::clearApplicationIconView() {
00083     if (_dockTile == nil)
00084         return;
00085     [_dockTile performSelector:@selector(setContentView:) withObject:nil];
00086     [_applicationIconView release];
00087     _applicationIconView = nil;
00088 }
00089 
00090 void MacOSXTaskbarManager::initOverlayIconView() {
00091     if (_dockTile == nil)
00092         return;
00093     if (_overlayIconView == nil) {
00094         const double overlaySize = 0.75;
00095         initApplicationIconView();
00096         NSSize size = [_applicationIconView frame].size;
00097         _overlayIconView = [[NSImageView alloc] initWithFrame:NSMakeRect(size.width * (1.0-overlaySize), 0.0f, size.width * overlaySize, size.height * overlaySize)];
00098         [_overlayIconView setImageAlignment:NSImageAlignBottomRight];
00099         [_applicationIconView addSubview:_overlayIconView];
00100         [_overlayIconView release];
00101     }
00102 }
00103 
00104 void MacOSXTaskbarManager::clearOverlayIconView() {
00105     if (_progress < 0.0)
00106         clearApplicationIconView();
00107     else
00108         [_overlayIconView removeFromSuperview];
00109     _overlayIconView = nil;
00110 }
00111 
00112 void MacOSXTaskbarManager::setOverlayIcon(const Common::String &name, const Common::String &description) {
00113     if (_dockTile == nil)
00114         return;
00115 
00116     if (name.empty()) {
00117         clearOverlayIconView();
00118         [_dockTile performSelector:@selector(display)];
00119         return;
00120     }
00121 
00122     Common::String path = getIconPath(name);
00123     if (path.empty())
00124         return;
00125 
00126     initOverlayIconView();
00127 
00128     CFStringRef imageFile = CFStringCreateWithCString(0, path.c_str(), kCFStringEncodingASCII);
00129     NSImage *image = [[NSImage alloc] initWithContentsOfFile:(NSString *)imageFile];
00130     [_overlayIconView setImage:image];
00131     [image release];
00132     CFRelease(imageFile);
00133 
00134     [_dockTile performSelector:@selector(display)];
00135 }
00136 
00137 void MacOSXTaskbarManager::setProgressValue(int completed, int total) {
00138     if (_dockTile == nil)
00139         return;
00140 
00141     if (total > 0)
00142         _progress = (double)completed / (double)total;
00143     else if (_progress < 0)
00144         _progress = 0.0;
00145 
00146      NSImage *mainIcon = [[NSApp applicationIconImage] copy];
00147     double barSize = [mainIcon size].width;
00148     double progressSize = barSize * _progress;
00149     [mainIcon lockFocus];
00150     [[NSColor colorWithDeviceRed:(40.0/255.0) green:(120.0/255.0) blue:(255.0/255.0) alpha:0.78] set];
00151     [NSBezierPath fillRect:NSMakeRect(0, 0, progressSize, 11)];
00152     [[NSColor colorWithDeviceRed:(241.0/255.0) green:(241.0/255.0) blue:(241.0/255.0) alpha:0.78] set];
00153     [NSBezierPath fillRect:NSMakeRect(progressSize, 0, barSize-progressSize, 11)];
00154     [mainIcon unlockFocus];
00155 
00156     initApplicationIconView();
00157     [_applicationIconView setImage:mainIcon];
00158     [mainIcon release];
00159 
00160     [_dockTile performSelector:@selector(display)];
00161 }
00162 
00163 void MacOSXTaskbarManager::setProgressState(TaskbarProgressState state) {
00164     if (_dockTile == nil)
00165         return;
00166 
00167     // Only support two states: visible and not visible.
00168     if (state == kTaskbarNoProgress) {
00169         _progress = -1.0;
00170         if (_overlayIconView == nil)
00171             clearApplicationIconView();
00172         else if (_applicationIconView != nil)
00173             [_applicationIconView setImage:[NSApp applicationIconImage]];
00174         return;
00175     }
00176 
00177     setProgressValue(-1, -1);
00178 }
00179 
00180 void MacOSXTaskbarManager::setCount(int count) {
00181     if (_dockTile == nil)
00182         return;
00183 
00184     if (count > 0)
00185         [_dockTile performSelector:@selector(setBadgeLabel:) withObject:[NSString stringWithFormat:@"%d", count]];
00186     else
00187         [_dockTile performSelector:@selector(setBadgeLabel:) withObject:nil];
00188 }
00189 
00190 void MacOSXTaskbarManager::notifyError() {
00191     if (_dockTile == nil)
00192         return;
00193 
00194     // NSImageNameCaution was introduced in 10.6.
00195     // For compatibility with older systems we should use something else (e.g. overlay label
00196     // or our own icon).
00197     //initOverlayIconView();
00198     //[_overlayIconView setImage:[NSImage imageNamed:NSImageNameCaution]];
00199     //[_dockTile performSelector:@selector(display)];
00200 }
00201 
00202 void MacOSXTaskbarManager::clearError() {
00203     if (_dockTile == nil)
00204         return;
00205 
00206     clearOverlayIconView();
00207     [_dockTile performSelector:@selector(display)];
00208     return;
00209 }
00210 
00211 Common::String MacOSXTaskbarManager::getIconPath(const Common::String& target) {
00212     // We first try to look for a iconspath configuration variable then
00213     // fallback to the extra path
00214     //
00215     // Icons can be either in a subfolder named "icons" or directly in the path
00216 
00217     Common::String iconsPath = ConfMan.get("iconspath");
00218     Common::String extraPath = ConfMan.get("extrapath");
00219 
00220 #define TRY_ICON_PATH(path) { \
00221 Common::FSNode node((path)); \
00222 if (node.exists()) \
00223 return (path); \
00224 }
00225 
00226     if (!iconsPath.empty()) {
00227         TRY_ICON_PATH(iconsPath + "/" + target + ".png");
00228         TRY_ICON_PATH(iconsPath + "/" + ConfMan.get("gameid") + ".png");
00229         TRY_ICON_PATH(iconsPath + "/icons/" + target + ".png");
00230         TRY_ICON_PATH(iconsPath + "/icons/" + ConfMan.get("gameid") + ".png");
00231     }
00232 
00233     if (!extraPath.empty()) {
00234         TRY_ICON_PATH(extraPath + "/" + target + ".png");
00235         TRY_ICON_PATH(extraPath + "/" + ConfMan.get("gameid") + ".png");
00236         TRY_ICON_PATH(extraPath + "/icons/" + target + ".png");
00237         TRY_ICON_PATH(extraPath + "/icons/" + ConfMan.get("gameid") + ".png");
00238     }
00239 
00240     return "";
00241 }
00242 
00243 void MacOSXTaskbarManager::addRecent(const Common::String &name, const Common::String &description) {
00244     //warning("[MacOSXTaskbarManager::addRecent] Adding recent list entry: %s (%s)", name.c_str(), description.c_str());
00245 
00246     if (_dockTile == nil)
00247         return;
00248 
00249     // Store the game, description and icon in user preferences.
00250     // The NSDockTilePlugin will retrieve them there to list them in the dock tile menu.
00251 
00252     CFStringRef gameName = CFStringCreateWithCString(0, name.c_str(), kCFStringEncodingASCII);
00253     CFStringRef desc = CFStringCreateWithCString(0, description.c_str(), kCFStringEncodingASCII);
00254 
00255     // First build the dictionary for this game.
00256     NSMutableDictionary *dict = [[NSMutableDictionary  alloc] init];
00257     [dict setObject:(NSString *)gameName forKey:@"game"];
00258     [dict setObject:(NSString *)desc forKey:@"description"];
00259 
00260     // Icon
00261     Common::String iconPath = getIconPath(name);
00262     if (!iconPath.empty()) {
00263         CFStringRef icon = CFStringCreateWithCString(0, iconPath.c_str(), kCFStringEncodingASCII);
00264         [dict setObject:(NSString *)icon forKey:@"icon"];
00265         CFRelease(icon);
00266     }
00267 
00268     // Retrieve the current list of recent items and update it.
00269     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
00270     NSArray *oldArray = [defaults arrayForKey:@"recentGames"];
00271     if (oldArray == nil) {
00272         [defaults setObject:[NSArray arrayWithObject:dict] forKey:@"recentGames"];
00273     } else {
00274         NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:oldArray];
00275         // Insert the new game at the start
00276         [newArray insertObject:dict atIndex:0];
00277         // If the game was already present in the array, remove it
00278         for (unsigned int i = 1 ; i < [newArray count] ; ++i) {
00279             NSDictionary *oldDict = [newArray objectAtIndex:i];
00280             if (oldDict == nil)
00281                 continue;
00282             NSString *oldGame = [oldDict valueForKey:@"game"];
00283             if (oldGame != nil && [oldGame isEqualToString:(NSString*)gameName]) {
00284                 [newArray removeObjectAtIndex:i];
00285                 break;
00286             }
00287         }
00288         // And make sure we limit the size of the array to 5 games
00289         if ([newArray count] > 5)
00290             [newArray removeLastObject];
00291         [defaults setObject:newArray forKey:@"recentGames"];
00292         [newArray release];
00293     }
00294 
00295     // Finally release the dictionary
00296     [dict release];
00297     CFRelease(gameName);
00298     CFRelease(desc);
00299 }
00300 
00301 
00302 
00303 #endif


Generated on Sat Feb 16 2019 05:00:57 for ResidualVM by doxygen 1.7.1
curved edge   curved edge