2 * MACDRV Cocoa initialization code
4 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
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.
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.
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
21 #import <AppKit/AppKit.h>
22 #include <mach/mach.h>
23 #include <mach/mach_time.h>
25 #include "macdrv_cocoa.h"
29 /* Condition values for an NSConditionLock. Used to signal between run_cocoa_app
30 and macdrv_start_cocoa_app so the latter knows when the former is running
31 the application event loop. */
33 COCOA_APP_NOT_RUNNING,
38 struct cocoa_app_startup_info {
39 NSConditionLock* lock;
40 unsigned long long tickcount;
46 /***********************************************************************
49 * Transforms the main thread from merely idling in its run loop to
50 * being a Cocoa application running its event loop.
52 * This will be the perform callback of a custom run loop source that
53 * will be scheduled in the main thread's run loop from a secondary
54 * thread by macdrv_start_cocoa_app. This function communicates that
55 * it has successfully started the application by changing the condition
56 * of a shared NSConditionLock, passed in via the info parameter.
58 * This function never returns. It's the new permanent home of the
61 static void run_cocoa_app(void* info)
63 struct cocoa_app_startup_info* startup_info = info;
64 NSConditionLock* lock = startup_info->lock;
65 BOOL created_app = FALSE;
67 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
71 [WineApplication sharedApplication];
75 if ([NSApp respondsToSelector:@selector(setWineController:)])
77 WineApplicationController* controller = [WineApplicationController sharedController];
78 [NSApp setWineController:controller];
79 [controller computeEventTimeAdjustmentFromTicks:startup_info->tickcount uptime:startup_info->uptime_ns];
80 startup_info->success = TRUE;
83 /* Retain the lock while we're using it, so macdrv_start_cocoa_app()
84 doesn't deallocate it in the middle of us unlocking it. */
87 [lock unlockWithCondition:COCOA_APP_RUNNING];
92 if (created_app && startup_info->success)
100 /***********************************************************************
101 * macdrv_start_cocoa_app
103 * Tells the main thread to transform itself into a Cocoa application.
105 * Returns 0 on success, non-zero on failure.
107 int macdrv_start_cocoa_app(unsigned long long tickcount)
110 CFRunLoopSourceRef source;
111 struct cocoa_app_startup_info startup_info;
112 uint64_t uptime_mach = mach_absolute_time();
113 mach_timebase_info_data_t mach_timebase;
115 CFRunLoopSourceContext source_context = { 0 };
117 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
119 /* Make sure Cocoa is in multi-threading mode by detaching a
120 do-nothing thread. */
121 [NSThread detachNewThreadSelector:@selector(self)
122 toTarget:[NSThread class]
125 startup_info.lock = [[NSConditionLock alloc] initWithCondition:COCOA_APP_NOT_RUNNING];
126 startup_info.tickcount = tickcount;
127 startup_info.success = FALSE;
129 mach_timebase_info(&mach_timebase);
130 startup_info.uptime_ns = uptime_mach * mach_timebase.numer / mach_timebase.denom;
132 timeLimit = [NSDate dateWithTimeIntervalSinceNow:5];
134 source_context.info = &startup_info;
135 source_context.perform = run_cocoa_app;
136 source = CFRunLoopSourceCreate(NULL, 0, &source_context);
138 if (source && startup_info.lock && timeLimit)
140 CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopCommonModes);
141 CFRunLoopSourceSignal(source);
142 CFRunLoopWakeUp(CFRunLoopGetMain());
144 if ([startup_info.lock lockWhenCondition:COCOA_APP_RUNNING beforeDate:timeLimit])
146 [startup_info.lock unlock];
147 ret = !startup_info.success;
153 [startup_info.lock release];