wbemprox: Return an empty object if the path is NULL or empty.
[wine] / dlls / winemac.drv / cocoa_app.m
1 /*
2  * MACDRV Cocoa application class
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 "cocoa_app.h"
22 #import "cocoa_event.h"
23 #import "cocoa_window.h"
24
25
26 int macdrv_err_on;
27
28
29 @implementation WineApplication
30
31     - (id) init
32     {
33         self = [super init];
34         if (self != nil)
35         {
36             eventQueues = [[NSMutableArray alloc] init];
37             eventQueuesLock = [[NSLock alloc] init];
38
39             keyWindows = [[NSMutableArray alloc] init];
40
41             if (!eventQueues || !eventQueuesLock || !keyWindows)
42             {
43                 [self release];
44                 return nil;
45             }
46         }
47         return self;
48     }
49
50     - (void) dealloc
51     {
52         [keyWindows release];
53         [eventQueues release];
54         [eventQueuesLock release];
55         [super dealloc];
56     }
57
58     - (void) transformProcessToForeground
59     {
60         if ([self activationPolicy] != NSApplicationActivationPolicyRegular)
61         {
62             NSMenu* mainMenu;
63             NSMenu* submenu;
64             NSString* bundleName;
65             NSString* title;
66             NSMenuItem* item;
67
68             [self setActivationPolicy:NSApplicationActivationPolicyRegular];
69             [self activateIgnoringOtherApps:YES];
70
71             mainMenu = [[[NSMenu alloc] init] autorelease];
72
73             submenu = [[[NSMenu alloc] initWithTitle:@"Wine"] autorelease];
74             bundleName = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString*)kCFBundleNameKey];
75             if ([bundleName length])
76                 title = [NSString stringWithFormat:@"Quit %@", bundleName];
77             else
78                 title = @"Quit";
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];
85
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];
95
96             [self setMainMenu:mainMenu];
97             [self setWindowsMenu:submenu];
98         }
99     }
100
101     - (BOOL) registerEventQueue:(WineEventQueue*)queue
102     {
103         [eventQueuesLock lock];
104         [eventQueues addObject:queue];
105         [eventQueuesLock unlock];
106         return TRUE;
107     }
108
109     - (void) unregisterEventQueue:(WineEventQueue*)queue
110     {
111         [eventQueuesLock lock];
112         [eventQueues removeObjectIdenticalTo:queue];
113         [eventQueuesLock unlock];
114     }
115
116     - (void) computeEventTimeAdjustmentFromTicks:(unsigned long long)tickcount uptime:(uint64_t)uptime_ns
117     {
118         eventTimeAdjustment = (tickcount / 1000.0) - (uptime_ns / (double)NSEC_PER_SEC);
119     }
120
121     - (double) ticksForEventTime:(NSTimeInterval)eventTime
122     {
123         return (eventTime + eventTimeAdjustment) * 1000;
124     }
125
126     /* Invalidate old focus offers across all queues. */
127     - (void) invalidateGotFocusEvents
128     {
129         WineEventQueue* queue;
130
131         windowFocusSerial++;
132
133         [eventQueuesLock lock];
134         for (queue in eventQueues)
135         {
136             [queue discardEventsMatchingMask:event_mask_for_type(WINDOW_GOT_FOCUS)
137                                    forWindow:nil];
138         }
139         [eventQueuesLock unlock];
140     }
141
142     - (void) windowGotFocus:(WineWindow*)window
143     {
144         macdrv_event event;
145
146         [NSApp invalidateGotFocusEvents];
147
148         event.type = WINDOW_GOT_FOCUS;
149         event.window = (macdrv_window)[window retain];
150         event.window_got_focus.serial = windowFocusSerial;
151         if (triedWindows)
152             event.window_got_focus.tried_windows = [triedWindows retain];
153         else
154             event.window_got_focus.tried_windows = [[NSMutableSet alloc] init];
155         [window.queue postEvent:&event];
156     }
157
158     - (void) windowRejectedFocusEvent:(const macdrv_event*)event
159     {
160         if (event->window_got_focus.serial == windowFocusSerial)
161         {
162             triedWindows = (NSMutableSet*)event->window_got_focus.tried_windows;
163             [triedWindows addObject:(WineWindow*)event->window];
164             for (NSWindow* window in [keyWindows arrayByAddingObjectsFromArray:[self orderedWindows]])
165             {
166                 if (![triedWindows containsObject:window] && [window canBecomeKeyWindow])
167                 {
168                     [window makeKeyWindow];
169                     break;
170                 }
171             }
172             triedWindows = nil;
173         }
174     }
175
176
177     /*
178      * ---------- NSApplicationDelegate methods ----------
179      */
180     - (void)applicationDidResignActive:(NSNotification *)notification
181     {
182         macdrv_event event;
183         WineEventQueue* queue;
184
185         [self invalidateGotFocusEvents];
186
187         event.type = APP_DEACTIVATED;
188         event.window = NULL;
189
190         [eventQueuesLock lock];
191         for (queue in eventQueues)
192             [queue postEvent:&event];
193         [eventQueuesLock unlock];
194     }
195
196     - (void)applicationWillFinishLaunching:(NSNotification *)notification
197     {
198         NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
199
200         [nc addObserverForName:NSWindowDidBecomeKeyNotification
201                         object:nil
202                          queue:nil
203                     usingBlock:^(NSNotification *note){
204             NSWindow* window = [note object];
205             [keyWindows removeObjectIdenticalTo:window];
206             [keyWindows insertObject:window atIndex:0];
207         }];
208
209         [nc addObserverForName:NSWindowWillCloseNotification
210                         object:nil
211                          queue:[NSOperationQueue mainQueue]
212                     usingBlock:^(NSNotification *note){
213             NSWindow* window = [note object];
214             [keyWindows removeObjectIdenticalTo:window];
215         }];
216     }
217
218 @end
219
220 /***********************************************************************
221  *              OnMainThread
222  *
223  * Run a block on the main thread synchronously.
224  */
225 void OnMainThread(dispatch_block_t block)
226 {
227     dispatch_sync(dispatch_get_main_queue(), block);
228 }
229
230 /***********************************************************************
231  *              OnMainThreadAsync
232  *
233  * Run a block on the main thread asynchronously.
234  */
235 void OnMainThreadAsync(dispatch_block_t block)
236 {
237     dispatch_async(dispatch_get_main_queue(), block);
238 }
239
240 /***********************************************************************
241  *              LogError
242  */
243 void LogError(const char* func, NSString* format, ...)
244 {
245     va_list args;
246     va_start(args, format);
247     LogErrorv(func, format, args);
248     va_end(args);
249 }
250
251 /***********************************************************************
252  *              LogErrorv
253  */
254 void LogErrorv(const char* func, NSString* format, va_list args)
255 {
256     NSString* message = [[NSString alloc] initWithFormat:format arguments:args];
257     fprintf(stderr, "err:%s:%s", func, [message UTF8String]);
258     [message release];
259 }
260
261 /***********************************************************************
262  *              macdrv_window_rejected_focus
263  *
264  * Pass focus to the next window that hasn't already rejected this same
265  * WINDOW_GOT_FOCUS event.
266  */
267 void macdrv_window_rejected_focus(const macdrv_event *event)
268 {
269     OnMainThread(^{
270         [NSApp windowRejectedFocusEvent:event];
271     });
272 }