From 35319684d3eb0a06a94d474558d91228912d3012 Mon Sep 17 00:00:00 2001 From: Ken Thomases Date: Mon, 7 Jan 2013 14:44:36 -0600 Subject: [PATCH] winemac: Convert main thread to Cocoa main loop on process attach. --- dlls/winemac.drv/Makefile.in | 3 +- dlls/winemac.drv/cocoa_main.m | 122 ++++++++++++++++++++++++++++++++ dlls/winemac.drv/macdrv_cocoa.h | 6 +- dlls/winemac.drv/macdrv_main.c | 14 ++-- 4 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 dlls/winemac.drv/cocoa_main.m diff --git a/dlls/winemac.drv/Makefile.in b/dlls/winemac.drv/Makefile.in index 38d8f7e7190..a388b9ba107 100644 --- a/dlls/winemac.drv/Makefile.in +++ b/dlls/winemac.drv/Makefile.in @@ -10,6 +10,7 @@ C_SRCS = \ OBJC_SRCS = \ cocoa_app.m \ - cocoa_display.m + cocoa_display.m \ + cocoa_main.m @MAKE_DLL_RULES@ diff --git a/dlls/winemac.drv/cocoa_main.m b/dlls/winemac.drv/cocoa_main.m new file mode 100644 index 00000000000..d9200364454 --- /dev/null +++ b/dlls/winemac.drv/cocoa_main.m @@ -0,0 +1,122 @@ +/* + * MACDRV Cocoa initialization code + * + * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc. + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#import + +#include "macdrv_cocoa.h" +#import "cocoa_app.h" + + +/* Condition values for an NSConditionLock. Used to signal between run_cocoa_app + and macdrv_start_cocoa_app so the latter knows when the former is running + the application event loop. */ +enum { + COCOA_APP_NOT_RUNNING, + COCOA_APP_RUNNING, +}; + + +/*********************************************************************** + * run_cocoa_app + * + * Transforms the main thread from merely idling in its run loop to + * being a Cocoa application running its event loop. + * + * This will be the perform callback of a custom run loop source that + * will be scheduled in the main thread's run loop from a secondary + * thread by macdrv_start_cocoa_app. This function communicates that + * it has successfully started the application by changing the condition + * of a shared NSConditionLock, passed in via the info parameter. + * + * This function never returns. It's the new permanent home of the + * main thread. + */ +static void run_cocoa_app(void* info) +{ + NSConditionLock* lock = info; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [WineApplication sharedApplication]; + [NSApp setDelegate:(WineApplication*)NSApp]; + + /* Retain the lock while we're using it, so macdrv_start_cocoa_app() + doesn't deallocate it in the middle of us unlocking it. */ + [lock retain]; + [lock lock]; + [lock unlockWithCondition:COCOA_APP_RUNNING]; + [lock release]; + + [pool release]; + + /* Never returns */ + [NSApp run]; +} + + +/*********************************************************************** + * macdrv_start_cocoa_app + * + * Tells the main thread to transform itself into a Cocoa application. + * + * Returns 0 on success, non-zero on failure. + */ +int macdrv_start_cocoa_app(void) +{ + int ret = -1; + CFRunLoopSourceRef source; + NSConditionLock* lock; + NSDate* timeLimit; + CFRunLoopSourceContext source_context = { 0 }; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + /* Make sure Cocoa is in multi-threading mode by detaching a + do-nothing thread. */ + [NSThread detachNewThreadSelector:@selector(self) + toTarget:[NSThread class] + withObject:nil]; + + lock = [[NSConditionLock alloc] initWithCondition:COCOA_APP_NOT_RUNNING]; + timeLimit = [NSDate dateWithTimeIntervalSinceNow:5]; + + source_context.info = lock; + source_context.perform = run_cocoa_app; + source = CFRunLoopSourceCreate(NULL, 0, &source_context); + + if (source && lock && timeLimit) + { + CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopCommonModes); + CFRunLoopSourceSignal(source); + CFRunLoopWakeUp(CFRunLoopGetMain()); + + if ([lock lockWhenCondition:COCOA_APP_RUNNING beforeDate:timeLimit]) + { + [lock unlock]; + ret = 0; + } + } + + if (source) + CFRelease(source); + [lock release]; + [pool release]; + return ret; +} diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 720073eb140..932aa906241 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -1,7 +1,7 @@ /* * MACDRV Cocoa interface declarations * - * Copyright 2011, 2012 Ken Thomases for CodeWeavers Inc. + * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -104,6 +104,10 @@ }; +/* main */ +extern int macdrv_start_cocoa_app(void) DECLSPEC_HIDDEN; + + /* display */ extern int macdrv_get_displays(struct macdrv_display** displays, int* count) DECLSPEC_HIDDEN; extern void macdrv_free_displays(struct macdrv_display* displays) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index 17aebf671ec..9ee249d8b95 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -3,6 +3,7 @@ * * Copyright 1998 Patrik Stridvall * Copyright 2000 Alexandre Julliard + * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,11 +21,10 @@ */ #include "config.h" -#include +#include "macdrv.h" + +WINE_DEFAULT_DEBUG_CHANNEL(macdrv); -#include "windef.h" -#include "winbase.h" -#include "winreg.h" /*********************************************************************** * MACDRV initialisation routine @@ -36,7 +36,11 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) switch(reason) { case DLL_PROCESS_ATTACH: - /* Do attach */ + if (macdrv_start_cocoa_app()) + { + ERR("Failed to start Cocoa app main loop\n"); + ret = FALSE; + } break; case DLL_THREAD_DETACH: /* do thread detach */