#import <Cocoa/Cocoa.h>
#import "ecore_cocoa_window.h"
+#import "ecore_cocoa_app.h"
#include <Eina.h>
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;
}
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:
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];
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. */
// 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:
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];
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)
// 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:
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))
{
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)
// 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:
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]);
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;
}
}
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]);
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;
}
}
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
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:
}
default:
{
- [NSApp sendEvent:event];
+ pass = EINA_TRUE;
break;
}
}
- [event release];
+ return pass;
}
EAPI void
--- /dev/null
+#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
+
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";
// 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)
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();
}
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;