explorerframe: Avoid signed-unsigned integer comparisons.
[wine] / dlls / winemac.drv / cocoa_main.m
1 /*
2  * MACDRV Cocoa initialization code
3  *
4  * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #import <AppKit/AppKit.h>
22
23 #include "macdrv_cocoa.h"
24 #import "cocoa_app.h"
25
26
27 /* Condition values for an NSConditionLock. Used to signal between run_cocoa_app
28    and macdrv_start_cocoa_app so the latter knows when the former is running
29    the application event loop. */
30 enum {
31     COCOA_APP_NOT_RUNNING,
32     COCOA_APP_RUNNING,
33 };
34
35
36 /***********************************************************************
37  *              run_cocoa_app
38  *
39  * Transforms the main thread from merely idling in its run loop to
40  * being a Cocoa application running its event loop.
41  *
42  * This will be the perform callback of a custom run loop source that
43  * will be scheduled in the main thread's run loop from a secondary
44  * thread by macdrv_start_cocoa_app.  This function communicates that
45  * it has successfully started the application by changing the condition
46  * of a shared NSConditionLock, passed in via the info parameter.
47  *
48  * This function never returns.  It's the new permanent home of the
49  * main thread.
50  */
51 static void run_cocoa_app(void* info)
52 {
53     NSConditionLock* lock = info;
54
55     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
56
57     [WineApplication sharedApplication];
58     [NSApp setDelegate:(WineApplication*)NSApp];
59
60     /* Retain the lock while we're using it, so macdrv_start_cocoa_app()
61        doesn't deallocate it in the middle of us unlocking it. */
62     [lock retain];
63     [lock lock];
64     [lock unlockWithCondition:COCOA_APP_RUNNING];
65     [lock release];
66
67     [pool release];
68
69     /* Never returns */
70     [NSApp run];
71 }
72
73
74 /***********************************************************************
75  *              macdrv_start_cocoa_app
76  *
77  * Tells the main thread to transform itself into a Cocoa application.
78  *
79  * Returns 0 on success, non-zero on failure.
80  */
81 int macdrv_start_cocoa_app(void)
82 {
83     int ret = -1;
84     CFRunLoopSourceRef source;
85     NSConditionLock* lock;
86     NSDate* timeLimit;
87     CFRunLoopSourceContext source_context = { 0 };
88
89     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
90
91     /* Make sure Cocoa is in multi-threading mode by detaching a
92        do-nothing thread. */
93     [NSThread detachNewThreadSelector:@selector(self)
94                              toTarget:[NSThread class]
95                            withObject:nil];
96
97     lock = [[NSConditionLock alloc] initWithCondition:COCOA_APP_NOT_RUNNING];
98     timeLimit = [NSDate dateWithTimeIntervalSinceNow:5];
99
100     source_context.info = lock;
101     source_context.perform = run_cocoa_app;
102     source = CFRunLoopSourceCreate(NULL, 0, &source_context);
103
104     if (source && lock && timeLimit)
105     {
106         CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopCommonModes);
107         CFRunLoopSourceSignal(source);
108         CFRunLoopWakeUp(CFRunLoopGetMain());
109
110         if ([lock lockWhenCondition:COCOA_APP_RUNNING beforeDate:timeLimit])
111         {
112             [lock unlock];
113             ret = 0;
114         }
115     }
116
117     if (source)
118         CFRelease(source);
119     [lock release];
120     [pool release];
121     return ret;
122 }