2 * MACDRV Cocoa application class
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
22 #import "cocoa_event.h"
23 #import "cocoa_window.h"
29 @implementation WineApplication
36 eventQueues = [[NSMutableArray alloc] init];
37 eventQueuesLock = [[NSLock alloc] init];
39 keyWindows = [[NSMutableArray alloc] init];
41 if (!eventQueues || !eventQueuesLock || !keyWindows)
53 [eventQueues release];
54 [eventQueuesLock release];
58 - (void) transformProcessToForeground
60 if ([self activationPolicy] != NSApplicationActivationPolicyRegular)
68 [self setActivationPolicy:NSApplicationActivationPolicyRegular];
69 [self activateIgnoringOtherApps:YES];
71 mainMenu = [[[NSMenu alloc] init] autorelease];
73 submenu = [[[NSMenu alloc] initWithTitle:@"Wine"] autorelease];
74 bundleName = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString*)kCFBundleNameKey];
75 if ([bundleName length])
76 title = [NSString stringWithFormat:@"Quit %@", bundleName];
79 item = [submenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
80 [item setKeyEquivalentModifierMask:NSCommandKeyMask | NSAlternateKeyMask];
81 item = [[[NSMenuItem alloc] init] autorelease];
82 [item setTitle:@"Wine"];
83 [item setSubmenu:submenu];
84 [mainMenu addItem:item];
86 submenu = [[[NSMenu alloc] initWithTitle:@"Window"] autorelease];
87 [submenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@""];
88 [submenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
89 [submenu addItem:[NSMenuItem separatorItem]];
90 [submenu addItemWithTitle:@"Bring All to Front" action:@selector(arrangeInFront:) keyEquivalent:@""];
91 item = [[[NSMenuItem alloc] init] autorelease];
92 [item setTitle:@"Window"];
93 [item setSubmenu:submenu];
94 [mainMenu addItem:item];
96 [self setMainMenu:mainMenu];
97 [self setWindowsMenu:submenu];
101 - (BOOL) registerEventQueue:(WineEventQueue*)queue
103 [eventQueuesLock lock];
104 [eventQueues addObject:queue];
105 [eventQueuesLock unlock];
109 - (void) unregisterEventQueue:(WineEventQueue*)queue
111 [eventQueuesLock lock];
112 [eventQueues removeObjectIdenticalTo:queue];
113 [eventQueuesLock unlock];
116 - (void) computeEventTimeAdjustmentFromTicks:(unsigned long long)tickcount uptime:(uint64_t)uptime_ns
118 eventTimeAdjustment = (tickcount / 1000.0) - (uptime_ns / (double)NSEC_PER_SEC);
121 - (double) ticksForEventTime:(NSTimeInterval)eventTime
123 return (eventTime + eventTimeAdjustment) * 1000;
126 /* Invalidate old focus offers across all queues. */
127 - (void) invalidateGotFocusEvents
129 WineEventQueue* queue;
133 [eventQueuesLock lock];
134 for (queue in eventQueues)
136 [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_GOT_FOCUS)
139 [eventQueuesLock unlock];
142 - (void) windowGotFocus:(WineWindow*)window
146 [NSApp invalidateGotFocusEvents];
148 event.type = WINDOW_GOT_FOCUS;
149 event.window = (macdrv_window)[window retain];
150 event.window_got_focus.serial = windowFocusSerial;
152 event.window_got_focus.tried_windows = [triedWindows retain];
154 event.window_got_focus.tried_windows = [[NSMutableSet alloc] init];
155 [window.queue postEvent:&event];
158 - (void) windowRejectedFocusEvent:(const macdrv_event*)event
160 if (event->window_got_focus.serial == windowFocusSerial)
162 triedWindows = (NSMutableSet*)event->window_got_focus.tried_windows;
163 [triedWindows addObject:(WineWindow*)event->window];
164 for (NSWindow* window in [keyWindows arrayByAddingObjectsFromArray:[self orderedWindows]])
166 if (![triedWindows containsObject:window] && [window canBecomeKeyWindow])
168 [window makeKeyWindow];
178 * ---------- NSApplicationDelegate methods ----------
180 - (void)applicationDidResignActive:(NSNotification *)notification
183 WineEventQueue* queue;
185 [self invalidateGotFocusEvents];
187 event.type = APP_DEACTIVATED;
190 [eventQueuesLock lock];
191 for (queue in eventQueues)
192 [queue postEvent:&event];
193 [eventQueuesLock unlock];
196 - (void)applicationWillFinishLaunching:(NSNotification *)notification
198 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
200 [nc addObserverForName:NSWindowDidBecomeKeyNotification
203 usingBlock:^(NSNotification *note){
204 NSWindow* window = [note object];
205 [keyWindows removeObjectIdenticalTo:window];
206 [keyWindows insertObject:window atIndex:0];
209 [nc addObserverForName:NSWindowWillCloseNotification
211 queue:[NSOperationQueue mainQueue]
212 usingBlock:^(NSNotification *note){
213 NSWindow* window = [note object];
214 [keyWindows removeObjectIdenticalTo:window];
220 /***********************************************************************
223 * Run a block on the main thread synchronously.
225 void OnMainThread(dispatch_block_t block)
227 dispatch_sync(dispatch_get_main_queue(), block);
230 /***********************************************************************
233 * Run a block on the main thread asynchronously.
235 void OnMainThreadAsync(dispatch_block_t block)
237 dispatch_async(dispatch_get_main_queue(), block);
240 /***********************************************************************
243 void LogError(const char* func, NSString* format, ...)
246 va_start(args, format);
247 LogErrorv(func, format, args);
251 /***********************************************************************
254 void LogErrorv(const char* func, NSString* format, va_list args)
256 NSString* message = [[NSString alloc] initWithFormat:format arguments:args];
257 fprintf(stderr, "err:%s:%s", func, [message UTF8String]);
261 /***********************************************************************
262 * macdrv_window_rejected_focus
264 * Pass focus to the next window that hasn't already rejected this same
265 * WINDOW_GOT_FOCUS event.
267 void macdrv_window_rejected_focus(const macdrv_event *event)
270 [NSApp windowRejectedFocusEvent:event];