ecore_cocoa: NSRunLoop integration
authorJean Guyomarc'h <jean.guyomarch@gmail.com>
Wed, 3 Sep 2014 18:34:52 +0000 (20:34 +0200)
committerCedric BAIL <cedric@osg.samsung.com>
Wed, 3 Sep 2014 18:34:57 +0000 (20:34 +0200)
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 <cedric@osg.samsung.com>
src/Makefile_Ecore_Cocoa.am
src/lib/ecore_cocoa/Ecore_Cocoa.h
src/lib/ecore_cocoa/ecore_cocoa.m
src/lib/ecore_cocoa/ecore_cocoa_app.h [new file with mode: 0644]
src/lib/ecore_cocoa/ecore_cocoa_app.m [new file with mode: 0644]
src/lib/ecore_cocoa/ecore_cocoa_window.m
src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c

index 0a01d1d..5bd1039 100644 (file)
@@ -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@
index 0bd8dd2..4f76f39 100644 (file)
@@ -25,6 +25,8 @@
 # define EAPI
 #endif
 
+#include <Eina.h>
+
 #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 */
 
index 2b1bf08..f02601b 100644 (file)
@@ -4,6 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 #import "ecore_cocoa_window.h"
+#import "ecore_cocoa_app.h"
 
 #include <Eina.h>
 
@@ -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 (file)
index 0000000..eac6aa8
--- /dev/null
@@ -0,0 +1,28 @@
+#import <Cocoa/Cocoa.h>
+#include "Ecore_Cocoa.h"
+#include <Ecore.h>
+
+@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 <NSApplicationDelegate>
+
++ (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 (file)
index 0000000..3aeda02
--- /dev/null
@@ -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
+
index ab4a78c..dc636fd 100644 (file)
@@ -65,7 +65,6 @@
    event->w = size.width;\r
    event->h = size.height -\r
       (([self isFullScreen] == YES) ? 0 : ecore_cocoa_titlebar_height_get());\r
-   printf("Is fullscreen: %i\n", [self isFullScreen]);\r
    ecore_event_add(ECORE_COCOA_EVENT_RESIZE, event, NULL, NULL);\r
 }\r
 \r
index 85a805c..9813d5b 100644 (file)
@@ -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;