From c03876d611fca41d02513fb07d3d275f64bcf0cd Mon Sep 17 00:00:00 2001 From: Jean Guyomarc'h Date: Wed, 3 Sep 2014 20:34:52 +0200 Subject: [PATCH] ecore_cocoa: NSRunLoop integration Summary: Get rid of the old NSApplicationLoad() which was aimed to be use with Carbon. Unless the NSRunLoop is strictly integrated to the ecore_main_loop() (where cocoa events would be checked when entering the ecore_main_loop) I think the poller is the only option left. Reviewers: raster, naguirre, raoulh, stefan_schmidt, cedric @feature Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D1222 Signed-off-by: Cedric BAIL --- src/Makefile_Ecore_Cocoa.am | 2 + src/lib/ecore_cocoa/Ecore_Cocoa.h | 4 +- src/lib/ecore_cocoa/ecore_cocoa.m | 70 +++++----- src/lib/ecore_cocoa/ecore_cocoa_app.h | 28 ++++ src/lib/ecore_cocoa/ecore_cocoa_app.m | 125 ++++++++++++++++++ src/lib/ecore_cocoa/ecore_cocoa_window.m | 1 - .../engines/cocoa/ecore_evas_cocoa.c | 22 --- 7 files changed, 195 insertions(+), 57 deletions(-) create mode 100644 src/lib/ecore_cocoa/ecore_cocoa_app.h create mode 100644 src/lib/ecore_cocoa/ecore_cocoa_app.m diff --git a/src/Makefile_Ecore_Cocoa.am b/src/Makefile_Ecore_Cocoa.am index 0a01d1d7ec..5bd10397a7 100644 --- a/src/Makefile_Ecore_Cocoa.am +++ b/src/Makefile_Ecore_Cocoa.am @@ -12,6 +12,8 @@ lib/ecore_cocoa/Ecore_Cocoa_Keys.h lib_ecore_cocoa_libecore_cocoa_la_SOURCES = \ lib/ecore_cocoa/ecore_cocoa.m \ lib/ecore_cocoa/ecore_cocoa_window.m \ +lib/ecore_cocoa/ecore_cocoa_app.m \ +lib/ecore_cocoa/ecore_cocoa_app.h \ lib/ecore_cocoa/ecore_cocoa_private.h lib_ecore_cocoa_libecore_cocoa_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_COCOA_CFLAGS@ diff --git a/src/lib/ecore_cocoa/Ecore_Cocoa.h b/src/lib/ecore_cocoa/Ecore_Cocoa.h index 0bd8dd27f7..4f76f39882 100644 --- a/src/lib/ecore_cocoa/Ecore_Cocoa.h +++ b/src/lib/ecore_cocoa/Ecore_Cocoa.h @@ -25,6 +25,8 @@ # define EAPI #endif +#include + #ifdef __cplusplus extern "C" { #endif @@ -53,7 +55,7 @@ struct _Ecore_Cocoa_Screen EAPI int ecore_cocoa_init(void); EAPI int ecore_cocoa_shutdown(void); -EAPI void ecore_cocoa_feed_events(void); +EAPI Eina_Bool ecore_cocoa_feed_events(void *anEvent); /* Screen */ diff --git a/src/lib/ecore_cocoa/ecore_cocoa.m b/src/lib/ecore_cocoa/ecore_cocoa.m index 2b1bf08946..f02601bb5d 100644 --- a/src/lib/ecore_cocoa/ecore_cocoa.m +++ b/src/lib/ecore_cocoa/ecore_cocoa.m @@ -4,6 +4,7 @@ #import #import "ecore_cocoa_window.h" +#import "ecore_cocoa_app.h" #include @@ -30,16 +31,24 @@ ecore_cocoa_init(void) if (++_ecore_cocoa_init_count != 1) return _ecore_cocoa_init_count; - if (!ecore_event_init()) + if (!ecore_init()) return --_ecore_cocoa_init_count; - NSApplicationLoad(); + if (!ecore_event_init()) + return --_ecore_cocoa_init_count; ECORE_COCOA_EVENT_GOT_FOCUS = ecore_event_type_new(); ECORE_COCOA_EVENT_LOST_FOCUS = ecore_event_type_new(); ECORE_COCOA_EVENT_RESIZE = ecore_event_type_new(); ECORE_COCOA_EVENT_EXPOSE = ecore_event_type_new(); + /* Init the Application handler */ + [Ecore_Cocoa_Application sharedApplication]; + [NSApp setDelegate:[Ecore_Cocoa_AppDelegate appDelegate]]; + + /* Start events monitoring */ + [NSApp run]; + return _ecore_cocoa_init_count; } @@ -89,21 +98,16 @@ _has_ecore_cocoa_window(NSEvent *event) return _nsevent_window_is_type_of(event, [EcoreCocoaWindow class]); } -EAPI void -ecore_cocoa_feed_events(void) +EAPI Eina_Bool +ecore_cocoa_feed_events(void *anEvent) { - Ecore_Event *ev; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0.001]; - NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:date - inMode:NSDefaultRunLoopMode - dequeue:YES]; - [date release]; - if (!event) return; // SDL loops until null; maybe we should do that too. or not. + EINA_SAFETY_ON_NULL_RETURN_VAL(anEvent, EINA_FALSE); + NSEvent *event = anEvent; unsigned int time = (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff); + Eina_Bool pass = EINA_FALSE; - switch([event type]) + switch ([event type]) { case NSMouseMoved: case NSLeftMouseDragged: @@ -113,7 +117,7 @@ ecore_cocoa_feed_events(void) if (_has_ecore_cocoa_window(event)) { Ecore_Event_Mouse_Move * ev = calloc(1, sizeof(Ecore_Event_Mouse_Move)); - if (!ev) return; + if (!ev) return pass; EcoreCocoaWindow *window = (EcoreCocoaWindow *)[event window]; NSView *view = [window contentView]; @@ -124,7 +128,7 @@ ecore_cocoa_feed_events(void) ev->root.x = ev->x; ev->root.y = ev->y; ev->timestamp = time; - ev->window = window.ecore_window_data; + ev->window = (Ecore_Window)window.ecore_window_data; ev->event_window = ev->window; ev->modifiers = 0; /* FIXME: keep modifier around. */ @@ -135,7 +139,7 @@ ecore_cocoa_feed_events(void) // We might want to handle cases such as events on the menubar. // If so, let's do it here. } - [NSApp sendEvent:event]; // pass along mouse events, for window manager + pass = EINA_TRUE; break; } case NSLeftMouseDown: @@ -145,7 +149,7 @@ ecore_cocoa_feed_events(void) if (_has_ecore_cocoa_window(event)) { Ecore_Event_Mouse_Button * ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)); - if (!ev) return; + if (!ev) return pass; EcoreCocoaWindow *window = (EcoreCocoaWindow *)[event window]; NSView *view = [window contentView]; @@ -163,7 +167,7 @@ ecore_cocoa_feed_events(void) case 2: ev->buttons = 2; break; default: ev->buttons = 0; break; } - ev->window = window.ecore_window_data; + ev->window = (Ecore_Window)window.ecore_window_data; ev->event_window = ev->window; if ([event clickCount] == 2) @@ -183,7 +187,7 @@ ecore_cocoa_feed_events(void) // We might want to handle cases such as events on the menubar. // If so, let's do it here. } - [NSApp sendEvent:event]; // pass along mouse events, for window manager + pass = EINA_TRUE; break; } case NSLeftMouseUp: @@ -191,7 +195,7 @@ ecore_cocoa_feed_events(void) case NSOtherMouseUp: { Ecore_Event_Mouse_Button * ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)); - if (!ev) return; + if (!ev) return pass; if (_has_ecore_cocoa_window(event)) { @@ -211,7 +215,7 @@ ecore_cocoa_feed_events(void) case 2: ev->buttons = 2; break; default: ev->buttons = 0; break; } - ev->window = window.ecore_window_data; + ev->window = (Ecore_Window)window.ecore_window_data; ev->event_window = ev->window; if ([event clickCount] == 2) @@ -231,7 +235,7 @@ ecore_cocoa_feed_events(void) // We might want to handle cases such as events on the menubar. // If so, let's do it here. } - [NSApp sendEvent:event]; // pass along mouse events, for window manager + pass = EINA_TRUE; break; } case NSKeyDown: @@ -241,7 +245,7 @@ ecore_cocoa_feed_events(void) EcoreCocoaWindow *window = (EcoreCocoaWindow *)[event window]; ev = calloc(1, sizeof (Ecore_Event_Key)); - if (!ev) return; + if (!ev) return pass; ev->timestamp = time; ev->modifiers = _ecore_cocoa_event_modifiers([event modifierFlags]); @@ -253,10 +257,10 @@ ecore_cocoa_feed_events(void) ev->keyname = keystable[i].name; ev->key = keystable[i].name; ev->string = keystable[i].compose; - ev->window = window.ecore_window_data; + ev->window = (Ecore_Window)window.ecore_window_data; ev->event_window = ev->window; ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, NULL, NULL); - return; + return pass; } } @@ -271,7 +275,7 @@ ecore_cocoa_feed_events(void) printf("Key Up\n"); ev = calloc(1, sizeof (Ecore_Event_Key)); - if (!ev) return; + if (!ev) return pass; ev->timestamp = time; ev->modifiers = _ecore_cocoa_event_modifiers([event modifierFlags]); @@ -282,10 +286,10 @@ ecore_cocoa_feed_events(void) ev->keyname = keystable[i].name; ev->key = keystable[i].name; ev->string = keystable[i].compose; - ev->window = window.ecore_window_data; + ev->window = (Ecore_Window)window.ecore_window_data; ev->event_window = ev->window; ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL); - return; + return pass; } } @@ -299,13 +303,13 @@ ecore_cocoa_feed_events(void) Ecore_Event_Key *evUp = NULL; evDown = calloc(1, sizeof (Ecore_Event_Key)); - if (!evDown) return; + if (!evDown) return pass; evUp = calloc(1, sizeof (Ecore_Event_Key)); if (!evUp) { free(evDown); - return; + return pass; } // Turn special key flags on @@ -360,7 +364,7 @@ ecore_cocoa_feed_events(void) ecore_event_add(ECORE_COCOA_EVENT_GOT_FOCUS, NULL, NULL, NULL); else if ([event subtype] == NSApplicationDeactivatedEventType) ecore_event_add(ECORE_COCOA_EVENT_LOST_FOCUS, NULL, NULL, NULL); - [NSApp sendEvent:event]; // pass along AppKit events, for window manager + pass = EINA_TRUE; // pass along AppKit events, for window manager break; } case NSScrollWheel: @@ -370,12 +374,12 @@ ecore_cocoa_feed_events(void) } default: { - [NSApp sendEvent:event]; + pass = EINA_TRUE; break; } } - [event release]; + return pass; } EAPI void diff --git a/src/lib/ecore_cocoa/ecore_cocoa_app.h b/src/lib/ecore_cocoa/ecore_cocoa_app.h new file mode 100644 index 0000000000..eac6aa85a2 --- /dev/null +++ b/src/lib/ecore_cocoa/ecore_cocoa_app.h @@ -0,0 +1,28 @@ +#import +#include "Ecore_Cocoa.h" +#include + +@interface Ecore_Cocoa_Application : NSApplication +{ + Ecore_Poller *_poller; + NSDate *_expiration; +} + +- (NSDate *)eventExpirationDate; + ++ (Ecore_Cocoa_Application *)sharedApplication; +- (void)run; +- (void)sendEvent:(NSEvent *)anEvent; +- (id)init; +- (void)internalUpdate; + +@end + + +@interface Ecore_Cocoa_AppDelegate : NSObject + ++ (Ecore_Cocoa_AppDelegate *)appDelegate; +- (id)init; + +@end + diff --git a/src/lib/ecore_cocoa/ecore_cocoa_app.m b/src/lib/ecore_cocoa/ecore_cocoa_app.m new file mode 100644 index 0000000000..3aeda02ba2 --- /dev/null +++ b/src/lib/ecore_cocoa/ecore_cocoa_app.m @@ -0,0 +1,125 @@ +#import "ecore_cocoa_app.h" + +static Eina_Bool +_ecore_cocoa_run_loop_cb(void *data EINA_UNUSED) +{ + @autoreleasepool { + @try { + NSEvent *e; + do { + e = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSApp eventExpirationDate] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (e != nil) { + //NSLog(@"Catching event %@", e); + + [NSApp sendEvent:e]; + + /* Update (en/disable) the services menu's items */ + NSEventType type = [e type]; + if (type != NSPeriodic && type != NSMouseMoved) { + [NSApp internalUpdate]; + } + } + } while (e != nil); + } + @catch (NSException *except) { + NSLog(@"EXCEPTION: %@: %@", [except name], [except reason]); + /* Show the "fancy" annoying report panel */ + [NSApp reportException:except]; + // XXX Maybe use Eina_Log to report the error instead + } + } + + return ECORE_CALLBACK_RENEW; +} + +@implementation Ecore_Cocoa_Application + ++ (Ecore_Cocoa_Application *)sharedApplication +{ + return (Ecore_Cocoa_Application *)[super sharedApplication]; +} + +- (void)internalUpdate +{ + [_mainMenu update]; + // FIXME Will not compile with GNUStep (member is named "_main_menu") +} + +- (id)init +{ + self = [super init]; + if (self == nil) { + // XXX Critical error. Abort right now! Log? + return nil; + } + NSApp = self; // NSApp is used EVERYWHERE! Set it right now! + return NSApp; +} + +- (NSDate *)eventExpirationDate +{ + return _expiration; +} + +- (void)run +{ + [self finishLaunching]; + + _running = 1; + _expiration = [NSDate distantPast]; + + _poller = ecore_poller_add(ECORE_POLLER_CORE, + ecore_poller_poll_interval_get(ECORE_POLLER_CORE), + _ecore_cocoa_run_loop_cb, NULL); + if (_poller == NULL) { + // XXX ERROR + } +} + + +- (void)sendEvent:(NSEvent *)anEvent +{ + Eina_Bool to_super; + + /* Some events shall be handled by Ecore (like single non-command keys). + * If we dispatch all events right to NSApplication, it will complain + * with NSBeep() when an event is not authorized */ + to_super = ecore_cocoa_feed_events(anEvent); + if (to_super) + [super sendEvent:anEvent]; +} + + +@end + + + +static Ecore_Cocoa_AppDelegate *_appDelegate = nil; + +@implementation Ecore_Cocoa_AppDelegate + ++ (Ecore_Cocoa_AppDelegate *)appDelegate +{ + if (_appDelegate == nil) { + _appDelegate = [[self alloc] init]; + } + return _appDelegate; +} + +- (id)init +{ + self = [super init]; + return self; +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender +{ + // XXX This should be alterable (by Elm_Window policy) + return YES; +} + +@end + diff --git a/src/lib/ecore_cocoa/ecore_cocoa_window.m b/src/lib/ecore_cocoa/ecore_cocoa_window.m index ab4a78ce13..dc636fdb41 100644 --- a/src/lib/ecore_cocoa/ecore_cocoa_window.m +++ b/src/lib/ecore_cocoa/ecore_cocoa_window.m @@ -65,7 +65,6 @@ event->w = size.width; event->h = size.height - (([self isFullScreen] == YES) ? 0 : ecore_cocoa_titlebar_height_get()); - printf("Is fullscreen: %i\n", [self isFullScreen]); ecore_event_add(ECORE_COCOA_EVENT_RESIZE, event, NULL, NULL); } diff --git a/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c b/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c index 85a805cae7..9813d5b46a 100644 --- a/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c +++ b/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c @@ -22,7 +22,6 @@ static Ecore_Event_Handler *ecore_evas_event_handlers[4] = { NULL, NULL, NULL, NULL }; static Ecore_Idle_Enterer *ecore_evas_idle_enterer = NULL; -static Ecore_Poller *ecore_evas_event = NULL; //static const char *ecore_evas_cocoa_default = "EFL Cocoa"; @@ -198,17 +197,6 @@ _ecore_evas_cocoa_event_video_expose(void *data EINA_UNUSED, int type EINA_UNUSE // return EINA_TRUE; //} -static Eina_Bool -_ecore_evas_cocoa_event(void *data EINA_UNUSED) -{ - //Ecore_Evas *ee = data; - - DBG("Cocoa Event"); - - ecore_cocoa_feed_events(); - - return ECORE_CALLBACK_PASS_ON; -} static int _ecore_evas_cocoa_init(void) @@ -246,8 +234,6 @@ _ecore_evas_cocoa_shutdown(void) ecore_event_evas_shutdown(); ecore_idle_enterer_del(ecore_evas_idle_enterer); ecore_evas_idle_enterer = NULL; - ecore_poller_del(ecore_evas_event); - ecore_evas_event = NULL; ecore_event_evas_shutdown(); } @@ -529,14 +515,6 @@ ecore_evas_cocoa_new_internal(Ecore_Cocoa_Window *parent EINA_UNUSED, int x, int ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_cocoa_engine_func; - /* this is pretty bad: poller? and set poll time? pol time is meant to be - * adjustable for things like polling battery state, or amoutn of spare - * memory etc. I know it's bad but cedric did it for ecore_evas_sdl - * so why not me ? BTW why 0.006s ? - */ - ecore_evas_event = ecore_poller_add(ECORE_POLLER_CORE, 1, _ecore_evas_cocoa_event, ee); - ecore_poller_poll_interval_set(ECORE_POLLER_CORE, 0.006); - if (w < 1) w = 1; if (h < 1) h = 1; ee->visible = 1;