File: mac_icon.cpp

package info (click to toggle)
boinc 8.0.4%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 106,832 kB
  • sloc: cpp: 167,537; php: 111,699; pascal: 56,262; ansic: 49,284; xml: 18,762; python: 7,938; javascript: 6,538; sh: 5,719; makefile: 2,183; java: 2,041; objc: 1,867; perl: 1,843; sql: 830; lisp: 47; csh: 30
file content (247 lines) | stat: -rw-r--r-- 9,452 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2008 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.

// THIS CODE IS OBSOLETE! A better way to add an icon to science applications
// (or any Mac executable, including command-line tools) is:
// [1] Select the application in the Finder
// [2] Get Info (command-I) for the selected application
// [3] Click on the file's current icon in the top left corner of the Get Info window
// [4] Paste (command-v) the desired icon.
//
// To copy an icon from a different file:
// [a] Get Info for the source file
// [b] Click on the file's  icon in the top left corner of the Get Info window
// [c] Copy (command-c) the icon.


/* Mac-specific code to display custom icon for science application (optional)
   adapted from code written by Bernd Machenschalk.  Used with permission of the
   Einstein@home project.

    To use this code:
    1. Create a *.icns file using "/Developer/Applications/utilities/Icon Composer.app"
    2. Convert the *.icns file to an app_icon.h file as follows: in Terminal, run
      "MakeAppIcon_h <source_file> <dest_file>".  (The MakeAppIcon_h command-line utility
      is built by the Mac boinc XCode project.)
    3. In the science application's main(), #include "app_icon.h" and call:
        setMacIcon(argv[0], MacAppIconData, sizeof(MacAppIconData));
    4. Science application must link with Carbon.framework.
*/

#include <Carbon/Carbon.h>
#include <sys/stat.h>

#include "boinc_api.h"
#include "filesys.h"
#include "common_defs.h"

#define RESIDICON -16455

char MacPListData[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n<dict>\n"
"\t<key>NSUIElement</key>\n\t<string>1</string>\n</dict>\n</plist>\n";


/* checks for an OS error, reports the line number and returns */
#define CHECK_OSERR(e) {\
  if (e) {\
    fprintf(stderr,"MacOS Error %d occurred in %s line %d\n",e,__FILE__,__LINE__);\
    return(e); } }

// Adds the specified resource to the file given as an argument.
int setMacRsrcForFile(char *filename, char *rsrcData, long rsrcSize,
                            OSType rsrcType, int rsrcID, ConstStringPtr rsrcName) {
    OSErr oserr;                    /* stores an OS error code */
//    FSSpec fsspec;                  /* FileSpec */
    HFSUniStr255 forkName;          /* Unicode name of resource fork "RESOURCE_FORK" */
    FSRef fsref;                    /* File Reference */
    FSCatalogInfo catalogInfo;      /* For setting custom icon bit in Finder Info */
    short rref;                     /* Resource Reference */
    Handle hand;
    int retry;

    /* get finder spec for this file */
    CHECK_OSERR((int)FSPathMakeRef((StringPtr)filename, &fsref, NULL));
//    CHECK_OSERR(FSGetCatalogInfo(&fsref, nil, NULL, NULL, &fsspec, NULL));

    /* Open the resource fork for writing, create it if it does not exist.
        On a dual-processor system, the other cpu may have the resource fork
        open for writing, so if we fail we wait and retry.
    */
    for (retry=0;retry<5;retry++) {
//        rref = FSpOpenResFile(&fsspec, fsRdWrPerm);
        rref = FSOpenResFile(&fsref, fsRdWrPerm);
        oserr = ResError();
        if (oserr == eofErr) { /* EOF, resource fork/file not found */
            // If we set file type and signature to non-NULL, it makes OS mistakenly
            // identify file as a classic application instead of a UNIX executable.
//            FSpCreateResFile(&fsref, 0, 0, smRoman);
            oserr = FSGetResourceForkName(&forkName);
            if (oserr == noErr) {
                oserr = FSCreateResourceFork(&fsref, forkName.length, forkName.unicode, 0);
            }
            oserr = ResError();
            if (oserr == noErr) {
//                rref = FSpOpenResFile(&fsspec, fsRdWrPerm);
                rref = FSOpenResFile(&fsref, fsRdWrPerm);
                oserr = ResError();
            }
        }
        // We may not have permissions to set resources in debug runs
        if ((oserr == noErr) || (oserr == wrPermErr) || (oserr == permErr))
            break;
        sleep (1);
    };

    if (oserr)
        return oserr; // give up after 5 seconds

    /* add the resource if not already present */
    if (!GetResource(rsrcType, rsrcID)) { /* if resource not found */
        oserr = PtrToHand(rsrcData, &hand, rsrcSize);
        if (!oserr)
            AddResource(hand, rsrcType, rsrcID, rsrcName);
    }

    /* add this to the file on disk */
    CloseResFile(rref);
    CHECK_OSERR(ResError());

    if (rsrcType == 'icns') {
        /* set custom icon flag */
        CHECK_OSERR(FSGetCatalogInfo(&fsref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL));
        ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= kHasCustomIcon;
        CHECK_OSERR( FSSetCatalogInfo(&fsref, kFSCatInfoFinderInfo, &catalogInfo));
    }
    return(0);
}


static char * PersistentFGets(char *buf, size_t buflen, FILE *f) {
    char *p = buf;
    size_t len = buflen;
    size_t datalen = 0;

    *buf = '\0';
    while (datalen < (buflen - 1)) {
        fgets(p, len, f);
        if (feof(f)) break;
        if (ferror(f) && (errno != EINTR)) break;
        if (strchr(buf, '\n')) break;
        datalen = strlen(buf);
        p = buf + datalen;
        len -= datalen;
    }
    return (buf[0] ? buf : NULL);
}


void getPathToThisApp(char* pathBuf, size_t bufSize) {
    FILE *f;
    char buf[MAXPATHLEN], *c;
    pid_t myPID = getpid();
    int i;
    struct stat stat_buf;

    strlcpy(pathBuf, GRAPHICS_APP_FILENAME, bufSize);
    if (!stat(pathBuf, &stat_buf)) {
       // stat() returns zero on success
       return;
    }

    *pathBuf = 0;    // in case of failure

    // Before launching this project application, the BOINC client set the
    // current directory to the slot directory which contains this application
    // (or the soft-link to it.)  So all we need for the path to this
    // application is the file name.  We use the -c option so ps strips off
    // any command-line arguments for us.
    snprintf(buf, sizeof(buf), "ps -wcp %d -o command=", myPID);
    f = popen(buf,  "r");
    if (!f)
        return;
    PersistentFGets(pathBuf, bufSize, f);  // Skip over line of column headings
    PersistentFGets(pathBuf, bufSize, f);  // Get the UNIX command which ran us
    pclose(f);

    c = strstr(pathBuf, " -");
    if (c)
        *c = 0;     // Strip off any command-line arguments

    for (i=strlen(pathBuf)-1; i>=0; --i) {
        if (pathBuf[i] <= ' ')
            pathBuf[i] = 0;  // Strip off trailing spaces, newlines, etc.
        else
            break;
    }
}

// Adds plst resource 0 to the file given as an argument.  This
// identifies the application to the OS as an NSUIElement, so
// that the application does not show in the Dock and it has no
// menu bar.
int setMacPList() {
    int rc;
    char path[1024], resolvedPath[1024];
    const char plistStr[] = "Application PList";
    CFStringRef plistCFStr = CFStringCreateWithCString(kCFAllocatorDefault, plistStr, kCFStringEncodingMacRoman);
    ConstStringPtr rsrcName = CFStringGetPascalStringPtr(plistCFStr, kCFStringEncodingMacRoman);
    if (!rsrcName) {
        return -2;
    }

    // If resource already exists, don't call getPathToThisApp()
    // which leaves a zombie process.
    if (GetResource('plst', 0)) {
        return 0;
    }

    getPathToThisApp(path, sizeof(path));
    if (path[0] == 0)
        return -1; // Should never happen

    setMacRsrcForFile(path, MacPListData, sizeof(MacPListData), 'plst', 0, rsrcName);
    boinc_resolve_filename(path, resolvedPath, sizeof(resolvedPath));
    rc = setMacRsrcForFile(resolvedPath, MacPListData, sizeof(MacPListData), 'plst', 0, rsrcName);

    CFRelease(plistCFStr);
    return rc;
}


// Adds icns resource to the file given as an argument.
// If the file is a soft link, also adds icns resource to the resolved flle.
// Typically called from a main() with argv[0] to attach resources to itself */
int setMacIcon(char *filename, char *iconData, long iconSize) {
    int rc;
    char path[1024];
    const char iconStr[] = "Application icons";
    CFStringRef iconCFStr = CFStringCreateWithCString(kCFAllocatorDefault, iconStr, kCFStringEncodingMacRoman);
    ConstStringPtr rsrcName = CFStringGetPascalStringPtr(iconCFStr, kCFStringEncodingMacRoman);  // FIXME: How to release this?
    if (!rsrcName) {
        return -2;
    }

    setMacRsrcForFile(filename, iconData, iconSize, 'icns', RESIDICON, rsrcName);
    boinc_resolve_filename(filename, path, sizeof(path));
    rc = setMacRsrcForFile(path, iconData, iconSize, 'icns', RESIDICON, rsrcName);

    CFRelease(iconCFStr);
    return rc;
}