~ubuntu-branches/ubuntu/precise/gcompris/precise

« back to all changes in this revision

Viewing changes to macosx/main.c

  • Committer: Bazaar Package Importer
  • Author(s): Yann Dirson
  • Date: 2010-06-27 22:51:30 UTC
  • mfrom: (1.1.16 upstream) (5.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100627225130-mf7h4m5r8m7bd9fb
Tags: 9.3-1
* New upstream release.
* Drop GTK_DISABLE_DEPRECATED patch, useless for now.
* Provide RELEASE_NOTE_9.3.txt downloaded from sourceforge.
* New voice package for Asturian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    Platypus - create MacOS X application bundles that execute scripts
3
 
        This is the executable that goes into Platypus apps
4
 
    Copyright (C) 2003, 2008 Sveinbjorn Thordarson <sveinbt@hi.is>
5
 
 
6
 
    This program is free software; you can redistribute it and/or modify
7
 
    it under the terms of the GNU General Public License as published by
8
 
    the Free Software Foundation; either version 2 of the License, or
9
 
    (at your option) any later version.
10
 
 
11
 
    This program is distributed in the hope that it will be useful,
12
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
    GNU General Public License for more details.
15
 
 
16
 
    You should have received a copy of the GNU General Public License
17
 
    along with this program; if not, write to the Free Software
18
 
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 
 
20
 
    main.c - main program file
21
 
 
22
 
*/
23
 
 
24
 
///////////////////////////////////////
25
 
// Includes
26
 
///////////////////////////////////////
27
 
#pragma mark Includes
28
 
 
29
 
// Apple stuff
30
 
#include <Carbon/Carbon.h>
31
 
#include <CoreFoundation/CoreFoundation.h>
32
 
 
33
 
// Unix stuff
34
 
#include <string.h>
35
 
#include <unistd.h>
36
 
#include <sys/wait.h>
37
 
#include <pthread.h>
38
 
 
39
 
///////////////////////////////////////
40
 
// Definitions
41
 
///////////////////////////////////////
42
 
#pragma mark Definitions
43
 
 
44
 
// name length limits
45
 
#define kMaxPathLength 1024
46
 
 
47
 
// names of files bundled with app
48
 
#define kScriptFileName "script"
49
 
#define kOpenDocFileName "openDoc"
50
 
 
51
 
// custom carbon events
52
 
#define kEventClassRedFatalAlert 911
53
 
#define kEventKindX11Failed 911
54
 
 
55
 
//maximum arguments the script accepts
56
 
#define kMaxArgumentsToScript 252
57
 
 
58
 
///////////////////////////////////////
59
 
// Prototypes
60
 
///////////////////////////////////////
61
 
#pragma mark Prototypes
62
 
 
63
 
static void *Execute(void *arg);
64
 
static void *OpenDoc(void *arg);
65
 
static OSErr ExecuteScript(char *script, pid_t *pid);
66
 
 
67
 
static void  GetParameters(void);
68
 
static char* GetScript(void);
69
 
static char* GetOpenDoc(void);
70
 
 
71
 
OSErr LoadMenuBar(char *appName);
72
 
 
73
 
static OSStatus FSMakePath(FSSpec file, char *path, long maxPathSize);
74
 
static void RedFatalAlert(Str255 errorString, Str255 expStr);
75
 
static short DoesFileExist(char *path);
76
 
 
77
 
static OSErr AppQuitAEHandler(const AppleEvent *theAppleEvent,
78
 
                              AppleEvent *reply, long refCon);
79
 
static OSErr AppOpenDocAEHandler(const AppleEvent *theAppleEvent,
80
 
                                 AppleEvent *reply, long refCon);
81
 
static OSErr AppOpenAppAEHandler(const AppleEvent *theAppleEvent,
82
 
                                 AppleEvent *reply, long refCon);
83
 
static OSStatus X11FailedHandler(EventHandlerCallRef theHandlerCall,
84
 
                                 EventRef theEvent, void *userData);
85
 
 
86
 
///////////////////////////////////////
87
 
// Globals
88
 
///////////////////////////////////////
89
 
#pragma mark Globals
90
 
 
91
 
// process id of forked process
92
 
pid_t pid = 0;
93
 
 
94
 
// thread id of threads that start scripts
95
 
pthread_t odtid = 0, tid = 0;
96
 
 
97
 
// indicator of whether the script has completed executing
98
 
short taskDone = true;
99
 
 
100
 
// execution parameters
101
 
char scriptPath[kMaxPathLength];
102
 
char openDocPath[kMaxPathLength];
103
 
 
104
 
//arguments to the script
105
 
char *arguments[kMaxArgumentsToScript+3];
106
 
char *fileArgs[kMaxArgumentsToScript];
107
 
short numArgs = 0;
108
 
 
109
 
extern char **environ;
110
 
 
111
 
#pragma mark -
112
 
 
113
 
///////////////////////////////////////
114
 
// Program entrance point
115
 
///////////////////////////////////////
116
 
int main(int argc, char* argv[])
117
 
{
118
 
    OSErr err = noErr;
119
 
    EventTypeSpec events = { kEventClassRedFatalAlert, kEventKindX11Failed };
120
 
 
121
 
        // Deprecated
122
 
    //InitCursor();
123
 
 
124
 
    //install Apple Event handlers
125
 
    err += AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
126
 
                                 NewAEEventHandlerUPP(AppQuitAEHandler),
127
 
                                 0, false);
128
 
    err += AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
129
 
                                 NewAEEventHandlerUPP(AppOpenDocAEHandler),
130
 
                                 0, false);
131
 
    err += AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
132
 
                                 NewAEEventHandlerUPP(AppOpenAppAEHandler),
133
 
                                 0, false);
134
 
    err += InstallEventHandler(GetApplicationEventTarget(),
135
 
                               NewEventHandlerUPP(X11FailedHandler), 1,
136
 
                               &events, NULL, NULL);
137
 
 
138
 
    if (err) RedFatalAlert("\pInitialization Error",
139
 
                           "\pError initing Apple Event handlers.");
140
 
 
141
 
    //create the menu bar
142
 
    if ((err = LoadMenuBar(NULL))) RedFatalAlert("\pInitialization Error",
143
 
                                               "\pError loading MenuBar.nib.");
144
 
 
145
 
    GetParameters(); //load data from files containing exec settings
146
 
 
147
 
    RunApplicationEventLoop(); //Run the event loop
148
 
    return 0;
149
 
}
150
 
 
151
 
#pragma mark -
152
 
 
153
 
///////////////////////////////////
154
 
// Execution thread starts here
155
 
///////////////////////////////////
156
 
static void *Execute (void *arg)
157
 
{
158
 
    EventRef event;
159
 
 
160
 
    taskDone = false;
161
 
    if (ExecuteScript(scriptPath, &pid) == (OSErr)11) {
162
 
        CreateEvent(NULL, kEventClassRedFatalAlert, kEventKindX11Failed, 0,
163
 
                    kEventAttributeNone, &event);
164
 
        PostEventToQueue(GetMainEventQueue(), event, kEventPriorityStandard);
165
 
    }
166
 
    else ExitToShell();
167
 
    return 0;
168
 
}
169
 
 
170
 
///////////////////////////////////
171
 
// Open additional documents thread starts here
172
 
///////////////////////////////////
173
 
static void *OpenDoc (void *arg)
174
 
{
175
 
    ExecuteScript(openDocPath, NULL);
176
 
    return 0;
177
 
}
178
 
 
179
 
///////////////////////////////////////
180
 
// Run a script via the system command
181
 
///////////////////////////////////////
182
 
static OSErr ExecuteScript (char *script, pid_t *pid)
183
 
{
184
 
    pid_t wpid = 0, p = 0;
185
 
    int status, i;
186
 
 
187
 
    if (! pid) pid = &p;
188
 
 
189
 
    // Generate the array of argument strings before we do any executing
190
 
    arguments[0] = script;
191
 
    for (i = 0; i < numArgs; i++) arguments[i + 1] = fileArgs[i];
192
 
    arguments[i + 1] = NULL;
193
 
 
194
 
    *pid = fork(); //open fork
195
 
 
196
 
    if (*pid == (pid_t)-1) exit(13); //error
197
 
    else if (*pid == 0) { //child process started
198
 
        execve(arguments[0], arguments, environ);
199
 
        exit(13); //if we reach this point, there's an error
200
 
    }
201
 
 
202
 
    wpid = waitpid(*pid, &status, 0); //wait while child process finishes
203
 
 
204
 
    if (wpid == (pid_t)-1) return wpid;
205
 
    return (OSErr)WEXITSTATUS(status);
206
 
}
207
 
 
208
 
#pragma mark -
209
 
 
210
 
///////////////////////////////////////
211
 
// This function loads all the neccesary settings
212
 
// from config files in the Resources folder
213
 
///////////////////////////////////////
214
 
static void GetParameters (void)
215
 
{
216
 
    char *str;
217
 
    if (! (str = (char *)GetScript())) //get path to script to be executed
218
 
        RedFatalAlert("\pInitialization Error",
219
 
                      "\pError getting script from application bundle.");
220
 
    strcpy((char *)&scriptPath, str);
221
 
 
222
 
    if (! (str = (char *)GetOpenDoc())) //get path to openDoc
223
 
        RedFatalAlert("\pInitialization Error",
224
 
                      "\pError getting openDoc from application bundle.");
225
 
    strcpy((char *)&openDocPath, str);
226
 
}
227
 
 
228
 
///////////////////////////////////////
229
 
// Get path to the script in Resources folder
230
 
///////////////////////////////////////
231
 
static char* GetScript (void)
232
 
{
233
 
    CFStringRef fileName;
234
 
    CFBundleRef appBundle;
235
 
    CFURLRef scriptFileURL;
236
 
    FSRef fileRef;
237
 
    FSSpec fileSpec;
238
 
    char *path;
239
 
 
240
 
    //get CF URL for script
241
 
    if (! (appBundle = CFBundleGetMainBundle())) return NULL;
242
 
    if (! (fileName = CFStringCreateWithCString(NULL, kScriptFileName,
243
 
                                                kCFStringEncodingASCII)))
244
 
        return NULL;
245
 
    if (! (scriptFileURL = CFBundleCopyResourceURL(appBundle, fileName, NULL,
246
 
                                                   NULL))) return NULL;
247
 
 
248
 
    //Get file reference from Core Foundation URL
249
 
    if (! CFURLGetFSRef(scriptFileURL, &fileRef)) return NULL;
250
 
 
251
 
    //dispose of the CF variables
252
 
    CFRelease(scriptFileURL);
253
 
    CFRelease(fileName);
254
 
 
255
 
    //convert FSRef to FSSpec
256
 
    if (FSGetCatalogInfo(&fileRef, kFSCatInfoNone, NULL, NULL, &fileSpec,
257
 
                         NULL)) return NULL;
258
 
 
259
 
    //create path string
260
 
    if (! (path = malloc(kMaxPathLength))) return NULL;
261
 
    if (FSMakePath(fileSpec, path, kMaxPathLength)) return NULL;
262
 
    if (! DoesFileExist(path)) return NULL;
263
 
 
264
 
    return path;
265
 
}
266
 
 
267
 
///////////////////////////////////////
268
 
// Gets the path to openDoc in Resources folder
269
 
///////////////////////////////////////
270
 
static char* GetOpenDoc (void)
271
 
{
272
 
    CFStringRef fileName;
273
 
    CFBundleRef appBundle;
274
 
    CFURLRef openDocFileURL;
275
 
    FSRef fileRef;
276
 
    FSSpec fileSpec;
277
 
    char *path;
278
 
 
279
 
    //get CF URL for openDoc
280
 
    if (! (appBundle = CFBundleGetMainBundle())) return NULL;
281
 
    if (! (fileName = CFStringCreateWithCString(NULL, kOpenDocFileName,
282
 
                                                kCFStringEncodingASCII)))
283
 
        return NULL;
284
 
    if (! (openDocFileURL = CFBundleCopyResourceURL(appBundle, fileName, NULL,
285
 
                                                    NULL))) return NULL;
286
 
 
287
 
    //Get file reference from Core Foundation URL
288
 
    if (! CFURLGetFSRef( openDocFileURL, &fileRef )) return NULL;
289
 
 
290
 
    //dispose of the CF variables
291
 
    CFRelease(openDocFileURL);
292
 
    CFRelease(fileName);
293
 
 
294
 
    //convert FSRef to FSSpec
295
 
    if (FSGetCatalogInfo(&fileRef, kFSCatInfoNone, NULL, NULL, &fileSpec,
296
 
                         NULL)) return NULL;
297
 
 
298
 
    //create path string
299
 
    if (! (path = malloc(kMaxPathLength))) return NULL;
300
 
    if (FSMakePath(fileSpec, path, kMaxPathLength)) return NULL;
301
 
    if (! DoesFileExist(path)) return NULL;
302
 
 
303
 
    return path;
304
 
}
305
 
 
306
 
#pragma mark -
307
 
 
308
 
/////////////////////////////////////
309
 
// Load menu bar from nib
310
 
/////////////////////////////////////
311
 
OSErr LoadMenuBar (char *appName)
312
 
{
313
 
    OSErr err;
314
 
    IBNibRef nibRef;
315
 
 
316
 
    if ((err = CreateNibReference(CFSTR("MenuBar"), &nibRef))) return err;
317
 
    if ((err = SetMenuBarFromNib(nibRef, CFSTR("MenuBar")))) return err;
318
 
    DisposeNibReference(nibRef);
319
 
 
320
 
    return noErr;
321
 
}
322
 
 
323
 
#pragma mark -
324
 
 
325
 
///////////////////////////////////////
326
 
// Generate path string from FSSpec record
327
 
///////////////////////////////////////
328
 
static OSStatus FSMakePath(FSSpec file, char *path, long maxPathSize)
329
 
{
330
 
    OSErr err = noErr;
331
 
    FSRef fileRef;
332
 
 
333
 
    //create file reference from file spec
334
 
    if ((err = FSpMakeFSRef(&file, &fileRef))) return err;
335
 
 
336
 
    // and then convert the FSRef to a path
337
 
    return FSRefMakePath(&fileRef, (UInt8 *)path, maxPathSize);
338
 
}
339
 
 
340
 
////////////////////////////////////////
341
 
// Standard red error alert, then exit application
342
 
////////////////////////////////////////
343
 
static void RedFatalAlert (Str255 errorString, Str255 expStr)
344
 
{
345
 
    StandardAlert(kAlertStopAlert, errorString,  expStr, NULL, NULL);
346
 
    ExitToShell();
347
 
}
348
 
 
349
 
///////////////////////////////////////
350
 
// Determines whether file exists at path or not
351
 
///////////////////////////////////////
352
 
static short DoesFileExist (char *path)
353
 
{
354
 
    if (access(path, F_OK) == -1) return false;
355
 
    return true;
356
 
}
357
 
 
358
 
#pragma mark -
359
 
 
360
 
///////////////////////////////////////
361
 
// Apple Event handler for Quit i.e. from
362
 
// the dock or Application menu item
363
 
///////////////////////////////////////
364
 
static OSErr AppQuitAEHandler(const AppleEvent *theAppleEvent,
365
 
                              AppleEvent *reply, long refCon)
366
 
{
367
 
    #pragma unused (reply, refCon, theAppleEvent)
368
 
 
369
 
    while (numArgs > 0) free(fileArgs[numArgs--]);
370
 
 
371
 
    if (! taskDone && pid) { //kill the script process brutally
372
 
        kill(pid, 9);
373
 
        printf("Platypus App: PID %d killed brutally\n", pid);
374
 
    }
375
 
 
376
 
    pthread_cancel(tid);
377
 
    if (odtid) pthread_cancel(odtid);
378
 
 
379
 
    ExitToShell();
380
 
 
381
 
    return noErr;
382
 
}
383
 
 
384
 
/////////////////////////////////////
385
 
// Handler for docs dragged on app icon
386
 
/////////////////////////////////////
387
 
static OSErr AppOpenDocAEHandler(const AppleEvent *theAppleEvent,
388
 
                                 AppleEvent *reply, long refCon)
389
 
{
390
 
    #pragma unused (reply, refCon)
391
 
 
392
 
    OSErr err = noErr;
393
 
    AEDescList fileSpecList;
394
 
    AEKeyword keyword;
395
 
    DescType type;
396
 
 
397
 
    short i;
398
 
    long count, actualSize;
399
 
 
400
 
    FSSpec fileSpec;
401
 
    char path[kMaxPathLength];
402
 
 
403
 
    while (numArgs > 0) free(fileArgs[numArgs--]);
404
 
 
405
 
    //Read the AppleEvent
406
 
    err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList,
407
 
                         &fileSpecList);
408
 
 
409
 
    err = AECountItems(&fileSpecList, &count); //Count number of files
410
 
 
411
 
    for (i = 1; i <= count; i++) { //iteratively process each file
412
 
        //get fsspec from apple event
413
 
        if (! (err = AEGetNthPtr(&fileSpecList, i, typeFSS, &keyword, &type,
414
 
                                 (Ptr)&fileSpec, sizeof(FSSpec), &actualSize)))
415
 
        {
416
 
            //get path from file spec
417
 
            if ((err = FSMakePath(fileSpec, path,
418
 
                                  kMaxPathLength))) return err;
419
 
 
420
 
            if (numArgs == kMaxArgumentsToScript) break;
421
 
 
422
 
            if (! (fileArgs[numArgs] = malloc(kMaxPathLength))) return true;
423
 
 
424
 
            strcpy(fileArgs[numArgs++], (char *)&path);
425
 
        }
426
 
        else return err;
427
 
    }
428
 
 
429
 
    if (! taskDone) pthread_create(&odtid, NULL, OpenDoc, NULL);
430
 
    else pthread_create(&tid, NULL, Execute, NULL);
431
 
 
432
 
    return err;
433
 
}
434
 
 
435
 
///////////////////////////////
436
 
// Handler for clicking on app icon
437
 
///////////////////////////////
438
 
static OSErr AppOpenAppAEHandler(const AppleEvent *theAppleEvent,
439
 
                                 AppleEvent *reply, long refCon)
440
 
{
441
 
    #pragma unused (reply, refCon, theAppleEvent)
442
 
 
443
 
    // the app has been opened without any items dragged on to it
444
 
    pthread_create(&tid, NULL, Execute, NULL);
445
 
 
446
 
        return noErr;
447
 
}
448
 
 
449
 
//////////////////////////////////
450
 
// Handler for when X11 fails to start
451
 
//////////////////////////////////
452
 
static OSStatus X11FailedHandler(EventHandlerCallRef theHandlerCall,
453
 
                                 EventRef theEvent, void *userData)
454
 
{
455
 
    #pragma unused(theHanderCall, theEvent, userData)
456
 
 
457
 
    pthread_join(tid, NULL);
458
 
    if (odtid) pthread_join(odtid, NULL);
459
 
 
460
 
    RedFatalAlert("\pFailed to start X11",
461
 
                  "\pGimp.app requires Apple's X11.");
462
 
 
463
 
    return noErr;
464
 
}