Skip to content

Latest commit

 

History

History
454 lines (365 loc) · 14.2 KB

SDL_cocoaevents.m

File metadata and controls

454 lines (365 loc) · 14.2 KB
 
1
2
/*
Simple DirectMedia Layer
Jan 2, 2017
Jan 2, 2017
3
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_COCOA
#include "SDL_timer.h"
#include "SDL_cocoavideo.h"
#include "../../events/SDL_events_c.h"
#include "SDL_assert.h"
Jul 30, 2015
Jul 30, 2015
29
#include "SDL_hints.h"
30
31
32
33
34
35
36
37
38
/* This define was added in the 10.9 SDK. */
#ifndef kIOPMAssertPreventUserIdleDisplaySleep
#define kIOPMAssertPreventUserIdleDisplaySleep kIOPMAssertionTypePreventUserIdleDisplaySleep
#endif
@interface SDLApplication : NSApplication
- (void)terminate:(id)sender;
Oct 1, 2016
Oct 1, 2016
39
- (void)sendEvent:(NSEvent *)theEvent;
40
41
42
43
44
45
46
47
48
49
50
@end
@implementation SDLApplication
// Override terminate to handle Quit and System Shutdown smoothly.
- (void)terminate:(id)sender
{
SDL_SendQuit();
}
Oct 14, 2016
Oct 14, 2016
51
52
53
static SDL_bool s_bShouldHandleEventsInSDLApplication = SDL_FALSE;
static void Cocoa_DispatchEvent(NSEvent *theEvent)
Oct 1, 2016
Oct 1, 2016
54
55
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
Oct 14, 2016
Oct 14, 2016
56
Oct 1, 2016
Oct 1, 2016
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
switch ([theEvent type]) {
case NSLeftMouseDown:
case NSOtherMouseDown:
case NSRightMouseDown:
case NSLeftMouseUp:
case NSOtherMouseUp:
case NSRightMouseUp:
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged: /* usually middle mouse dragged */
case NSMouseMoved:
case NSScrollWheel:
Cocoa_HandleMouseEvent(_this, theEvent);
break;
case NSKeyDown:
case NSKeyUp:
case NSFlagsChanged:
Cocoa_HandleKeyEvent(_this, theEvent);
break;
default:
break;
}
Oct 14, 2016
Oct 14, 2016
79
80
81
82
83
84
85
86
87
88
89
}
// Dispatch events here so that we can handle events caught by
// nextEventMatchingMask in SDL, as well as events caught by other
// processes (such as CEF) that are passed down to NSApp.
- (void)sendEvent:(NSEvent *)theEvent
{
if (s_bShouldHandleEventsInSDLApplication) {
Cocoa_DispatchEvent(theEvent);
}
Oct 1, 2016
Oct 1, 2016
90
91
92
[super sendEvent:theEvent];
}
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
@end // SDLApplication
/* setAppleMenu disappeared from the headers in 10.4 */
@interface NSApplication(NSAppleMenu)
- (void)setAppleMenu:(NSMenu *)menu;
@end
@interface SDLAppDelegate : NSObject <NSApplicationDelegate> {
@public
BOOL seenFirstActivate;
}
- (id)init;
@end
@implementation SDLAppDelegate : NSObject
- (id)init
{
self = [super init];
if (self) {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
seenFirstActivate = NO;
[center addObserver:self
selector:@selector(windowWillClose:)
name:NSWindowWillCloseNotification
object:nil];
[center addObserver:self
selector:@selector(focusSomeWindow:)
name:NSApplicationDidBecomeActiveNotification
object:nil];
}
return self;
}
- (void)dealloc
{
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self name:NSWindowWillCloseNotification object:nil];
[center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil];
[super dealloc];
}
- (void)windowWillClose:(NSNotification *)notification;
{
NSWindow *win = (NSWindow*)[notification object];
if (![win isKeyWindow]) {
return;
}
/* HACK: Make the next window in the z-order key when the key window is
* closed. The custom event loop and/or windowing code we have seems to
* prevent the normal behavior: https://bugzilla.libsdl.org/show_bug.cgi?id=1825
*/
/* +[NSApp orderedWindows] never includes the 'About' window, but we still
* want to try its list first since the behavior in other apps is to only
* make the 'About' window key if no other windows are on-screen.
*/
for (NSWindow *window in [NSApp orderedWindows]) {
if (window != win && [window canBecomeKeyWindow]) {
May 21, 2016
May 21, 2016
160
161
if (![window isOnActiveSpace]) {
continue;
162
163
164
165
166
167
}
[window makeKeyAndOrderFront:self];
return;
}
}
May 21, 2016
May 21, 2016
168
169
170
/* If a window wasn't found above, iterate through all visible windows in
* the active Space in z-order (including the 'About' window, if it's shown)
* and make the first one key.
May 21, 2016
May 21, 2016
172
173
174
175
176
for (NSNumber *num in [NSWindow windowNumbersWithOptions:0]) {
NSWindow *window = [NSApp windowWithWindowNumber:[num integerValue]];
if (window && window != win && [window canBecomeKeyWindow]) {
[window makeKeyAndOrderFront:self];
return;
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
}
}
}
- (void)focusSomeWindow:(NSNotification *)aNotification
{
/* HACK: Ignore the first call. The application gets a
* applicationDidBecomeActive: a little bit after the first window is
* created, and if we don't ignore it, a window that has been created with
* SDL_WINDOW_MINIMIZED will ~immediately be restored.
*/
if (!seenFirstActivate) {
seenFirstActivate = YES;
return;
}
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (device && device->windows) {
SDL_Window *window = device->windows;
int i;
for (i = 0; i < device->num_displays; ++i) {
SDL_Window *fullscreen_window = device->displays[i].fullscreen_window;
if (fullscreen_window) {
if (fullscreen_window->flags & SDL_WINDOW_MINIMIZED) {
SDL_RestoreWindow(fullscreen_window);
}
return;
}
}
if (window->flags & SDL_WINDOW_MINIMIZED) {
SDL_RestoreWindow(window);
} else {
SDL_RaiseWindow(window);
}
}
}
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
Jan 5, 2016
Jan 5, 2016
217
return (BOOL)SDL_SendDropFile(NULL, [filename UTF8String]) && SDL_SendDropComplete(NULL);
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
}
@end
static SDLAppDelegate *appDelegate = nil;
static NSString *
GetApplicationName(void)
{
NSString *appName;
/* Determine the application name */
appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
if (!appName) {
appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
}
if (![appName length]) {
appName = [[NSProcessInfo processInfo] processName];
}
return appName;
}
static void
CreateApplicationMenus(void)
{
NSString *appName;
NSString *title;
NSMenu *appleMenu;
NSMenu *serviceMenu;
NSMenu *windowMenu;
NSMenu *viewMenu;
NSMenuItem *menuItem;
NSMenu *mainMenu;
if (NSApp == nil) {
return;
}
mainMenu = [[NSMenu alloc] init];
/* Create the main menu bar */
[NSApp setMainMenu:mainMenu];
[mainMenu release]; /* we're done with it, let NSApp own it. */
mainMenu = nil;
/* Create the application menu */
appName = GetApplicationName();
appleMenu = [[NSMenu alloc] initWithTitle:@""];
/* Add menu items */
title = [@"About " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
[appleMenu addItemWithTitle:@"Preferences…" action:nil keyEquivalent:@","];
[appleMenu addItem:[NSMenuItem separatorItem]];
serviceMenu = [[NSMenu alloc] initWithTitle:@""];
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
[menuItem setSubmenu:serviceMenu];
[NSApp setServicesMenu:serviceMenu];
[serviceMenu release];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Hide " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Quit " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
[menuItem setSubmenu:appleMenu];
[[NSApp mainMenu] addItem:menuItem];
[menuItem release];
/* Tell the application object that this is now the application menu */
[NSApp setAppleMenu:appleMenu];
[appleMenu release];
/* Create the window menu */
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
/* Add menu items */
[windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
[windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
[menuItem setSubmenu:windowMenu];
[[NSApp mainMenu] addItem:menuItem];
[menuItem release];
/* Tell the application object that this is now the window menu */
[NSApp setWindowsMenu:windowMenu];
[windowMenu release];
/* Add the fullscreen view toggle menu option, if supported */
May 21, 2016
May 21, 2016
332
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) {
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
/* Create the view menu */
viewMenu = [[NSMenu alloc] initWithTitle:@"View"];
/* Add menu items */
menuItem = [viewMenu addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
[menuItem setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""];
[menuItem setSubmenu:viewMenu];
[[NSApp mainMenu] addItem:menuItem];
[menuItem release];
[viewMenu release];
}
}
void
Cocoa_RegisterApp(void)
{ @autoreleasepool
{
/* This can get called more than once! Be careful what you initialize! */
if (NSApp == nil) {
[SDLApplication sharedApplication];
SDL_assert(NSApp != nil);
Oct 14, 2016
Oct 14, 2016
360
361
s_bShouldHandleEventsInSDLApplication = SDL_TRUE;
Oct 8, 2016
Oct 8, 2016
362
if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, SDL_FALSE)) {
May 21, 2016
May 21, 2016
363
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
Jul 30, 2015
Jul 30, 2015
364
365
366
[NSApp activateIgnoringOtherApps:YES];
}
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
if ([NSApp mainMenu] == nil) {
CreateApplicationMenus();
}
[NSApp finishLaunching];
NSDictionary *appDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithBool:NO], @"AppleMomentumScrollSupported",
[NSNumber numberWithBool:NO], @"ApplePressAndHoldEnabled",
[NSNumber numberWithBool:YES], @"ApplePersistenceIgnoreState",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
[appDefaults release];
}
if (NSApp && !appDelegate) {
appDelegate = [[SDLAppDelegate alloc] init];
/* If someone else has an app delegate, it means we can't turn a
* termination into SDL_Quit, and we can't handle application:openFile:
*/
if (![NSApp delegate]) {
[(NSApplication *)NSApp setDelegate:appDelegate];
} else {
appDelegate->seenFirstActivate = YES;
}
}
}}
void
Cocoa_PumpEvents(_THIS)
{ @autoreleasepool
{
Dec 1, 2016
Dec 1, 2016
397
398
399
400
401
402
403
404
405
406
407
/* Update activity every 30 seconds to prevent screensaver */
SDL_VideoData *data = (SDL_VideoData *)_this->driverdata;
if (_this->suspend_screensaver && !data->screensaver_use_iopm) {
Uint32 now = SDL_GetTicks();
if (!data->screensaver_activity ||
SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
UpdateSystemActivity(UsrActivity);
data->screensaver_activity = now;
}
}
408
409
410
411
412
413
for ( ; ; ) {
NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES ];
if ( event == nil ) {
break;
}
Oct 14, 2016
Oct 14, 2016
414
415
416
417
if (!s_bShouldHandleEventsInSDLApplication) {
Cocoa_DispatchEvent(event);
}
Oct 1, 2016
Oct 1, 2016
418
// Pass events down to SDLApplication to be handled in sendEvent:
419
420
421
422
423
424
425
426
427
428
[NSApp sendEvent:event];
}
}}
void
Cocoa_SuspendScreenSaver(_THIS)
{ @autoreleasepool
{
SDL_VideoData *data = (SDL_VideoData *)_this->driverdata;
Dec 1, 2016
Dec 1, 2016
429
430
431
432
if (!data->screensaver_use_iopm) {
return;
}
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
if (data->screensaver_assertion) {
IOPMAssertionRelease(data->screensaver_assertion);
data->screensaver_assertion = 0;
}
if (_this->suspend_screensaver) {
/* FIXME: this should ideally describe the real reason why the game
* called SDL_DisableScreenSaver. Note that the name is only meant to be
* seen by OS X power users. there's an additional optional human-readable
* (localized) reason parameter which we don't set.
*/
NSString *name = [GetApplicationName() stringByAppendingString:@" using SDL_DisableScreenSaver"];
IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep,
(CFStringRef) name,
NULL, NULL, NULL, 0, NULL,
&data->screensaver_assertion);
}
}}
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */