21fdd0b3956cdb0d8d801db94df27e4a434fd0f2
[profile/ivi/ecore.git] / src / lib / ecore_evas / ecore_evas_cocoa.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #ifdef BUILD_ECORE_EVAS_COCOA
6 #import <Cocoa/Cocoa.h>
7 #endif
8
9 #include "Ecore.h"
10 #include "ecore_private.h"
11 #include "Ecore_Input.h"
12 #include "Ecore_Input_Evas.h"
13
14 #include "ecore_evas_private.h"
15 #include "Ecore_Evas.h"
16
17 #ifdef BUILD_ECORE_EVAS_COCOA
18 #include "Ecore_Cocoa.h"
19 #include "Evas_Engine_Quartz.h"
20
21 // FIXME: this engine has lots of problems. only 1 window at a time, drawRect looks wrong, doesn't handle resizes and more
22
23 static int                      _ecore_evas_init_count = 0;
24 static Ecore_Evas               *ecore_evases = NULL;
25 static Ecore_Event_Handler      *ecore_evas_event_handlers[4] = {
26    NULL, NULL, NULL, NULL
27 };
28 static Ecore_Idle_Enterer       *ecore_evas_idle_enterer = NULL;
29 static Ecore_Poller             *ecore_evas_event = NULL;
30
31 static const char               *ecore_evas_cocoa_default = "EFL Cocoa";
32
33 @interface EvasView : NSView
34 {
35         CGContextRef ctx;
36 }
37 @end
38
39 static EvasView * evas_view;
40 static NSWindow * main_window;
41
42 @implementation EvasView
43
44 - (id) init
45 {
46    self = [super init];
47    if (self != nil)
48    {
49       ctx = NULL;
50    }
51    return self;
52 }
53
54 - (void)drawRect:(NSRect)rect
55 {
56    if(ctx != NULL)
57    {
58       Ecore_Evas  *ee;
59
60       EINA_INLIST_FOREACH(ecore_evases, ee)
61       {
62          if (ee->visible)
63             evas_damage_rectangle_add(ee->evas, 0, 0, 400, 400);
64       }
65       return;
66    }
67
68    ctx = [[NSGraphicsContext currentContext] graphicsPort];
69    CGContextRetain(ctx);
70 }
71
72 - (CGContextRef)context
73 {
74    return ctx;
75 }
76
77 @end
78
79 static Ecore_Evas *
80 _ecore_evas_cocoa_match(void)
81 {
82    return ecore_evases;
83 }
84
85 static Eina_Bool
86 _ecore_evas_cocoa_event_got_focus(void *data __UNUSED__, int type __UNUSED__, void *event)
87 {
88    Ecore_Evas                   *ee;
89
90    ee = _ecore_evas_cocoa_match();
91
92    if (!ee) return EINA_TRUE;
93    ee->prop.focused = 1;
94
95    return EINA_FALSE;
96 }
97
98 static Eina_Bool
99 _ecore_evas_cocoa_event_lost_focus(void *data __UNUSED__, int type __UNUSED__, void *event)
100 {
101    Ecore_Evas                   *ee;
102
103    ee = _ecore_evas_cocoa_match();
104
105    if (!ee) return EINA_TRUE;
106    ee->prop.focused = 0;
107
108    return EINA_FALSE;
109 }
110
111 static Eina_Bool
112 _ecore_evas_cocoa_event_video_resize(void *data __UNUSED__, int type __UNUSED__, void *event)
113 {
114    /*Ecore_Cocoa_Event_Video_Resize *e;
115    Ecore_Evas                   *ee;
116
117    e = event;
118    ee = _ecore_evas_cocoa_match();
119
120    if (!ee) return 1; // pass on event
121    evas_output_size_set(ee->evas, e->w, e->h);
122
123    return 0;*/
124 }
125
126 static Eina_Bool
127 _ecore_evas_cocoa_event_video_expose(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
128 {
129    Ecore_Evas                   *ee;
130    int                          w;
131    int                          h;
132
133    ee = _ecore_evas_cocoa_match();
134
135    if (!ee) return EINA_TRUE;
136    evas_output_size_get(ee->evas, &w, &h);
137    evas_damage_rectangle_add(ee->evas, 0, 0, w, h);
138
139    return EINA_FALSE;
140 }
141
142 static int
143 _ecore_evas_idle_enter(void *data __UNUSED__)
144 {
145    Ecore_Evas  *ee;
146    double       t1 = 0.;
147    double       t2 = 0.;
148
149    EINA_INLIST_FOREACH(ecore_evases, ee)
150    {
151       if (ee->visible)
152          evas_render(ee->evas);
153       else
154          evas_norender(ee->evas);
155    }
156
157    return 1;
158 }
159
160 static int
161 _ecore_evas_cocoa_event(void *data)
162 {
163    ecore_cocoa_feed_events();
164
165    return 1;
166 }
167
168 static int
169 _ecore_evas_cocoa_init(int w, int h)
170 {
171    _ecore_evas_init_count++;
172    if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
173
174    ecore_event_evas_init();
175
176    ecore_evas_idle_enterer = ecore_idle_enterer_add(_ecore_evas_idle_enter, NULL);
177    ecore_evas_event = ecore_poller_add(ECORE_POLLER_CORE, 1, ecore_evas_event, NULL);
178    ecore_poller_poll_interval_set(ECORE_POLLER_CORE, 0.006);
179
180    ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_COCOA_EVENT_GOT_FOCUS, _ecore_evas_cocoa_event_got_focus, NULL);
181    ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_COCOA_EVENT_LOST_FOCUS, _ecore_evas_cocoa_event_lost_focus, NULL);
182    ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_COCOA_EVENT_RESIZE, _ecore_evas_cocoa_event_video_resize, NULL);
183    ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_COCOA_EVENT_EXPOSE, _ecore_evas_cocoa_event_video_expose, NULL);
184
185    return _ecore_evas_init_count;
186 }
187
188 static int
189 _ecore_evas_cocoa_shutdown(void)
190 {
191    _ecore_evas_init_count--;
192    if (_ecore_evas_init_count == 0)
193    {
194       int i;
195
196       while (ecore_evases) _ecore_evas_free(ecore_evases);
197
198       for (i = 0; i < sizeof (ecore_evas_event_handlers) / sizeof (Ecore_Event_Handler*); i++)
199          ecore_event_handler_del(ecore_evas_event_handlers[i]);
200       ecore_event_evas_shutdown();
201       ecore_idle_enterer_del(ecore_evas_idle_enterer);
202       ecore_evas_idle_enterer = NULL;
203       ecore_poller_del(ecore_evas_event);
204       ecore_evas_event = NULL;
205
206       ecore_event_evas_shutdown();
207    }
208    if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
209    return _ecore_evas_init_count;
210 }
211
212 static void
213 _ecore_evas_cocoa_free(Ecore_Evas *ee)
214 {
215    ecore_evases = (Ecore_Evas *) eina_inlist_remove(EINA_INLIST_GET(ecore_evases), EINA_INLIST_GET(ee));
216    ecore_event_window_unregister(0);
217    _ecore_evas_cocoa_shutdown();
218    ecore_cocoa_shutdown();
219 }
220
221 static void
222 _ecore_evas_resize(Ecore_Evas *ee, int w, int h)
223 {
224    if ((w == ee->w) && (h == ee->h)) return;
225    ee->w = w;
226    ee->h = h;
227
228    evas_output_size_set(ee->evas, ee->w, ee->h);
229    evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
230    evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
231
232    if (ee->func.fn_resize) ee->func.fn_resize(ee);
233 }
234
235 static void
236 _ecore_evas_move_resize(Ecore_Evas *ee, int x __UNUSED__, int y __UNUSED__, int w, int h)
237 {
238    if ((w == ee->w) && (h == ee->h)) return;
239    ee->w = w;
240    ee->h = h;
241
242    evas_output_size_set(ee->evas, ee->w, ee->h);
243    evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
244    evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
245
246    if (ee->func.fn_resize) ee->func.fn_resize(ee);
247 }
248
249 static void
250 _ecore_evas_object_cursor_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
251 {
252    Ecore_Evas *ee;
253
254    ee = data;
255    if (ee)
256      ee->prop.cursor.object = NULL;
257 }
258
259 static void
260 _ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
261 {
262    int x, y;
263
264    if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
265
266    if (!obj)
267    {
268       ee->prop.cursor.object = NULL;
269       ee->prop.cursor.layer = 0;
270       ee->prop.cursor.hot.x = 0;
271       ee->prop.cursor.hot.y = 0;
272       return;
273    }
274
275    ee->prop.cursor.object = obj;
276    ee->prop.cursor.layer = layer;
277    ee->prop.cursor.hot.x = hot_x;
278    ee->prop.cursor.hot.y = hot_y;
279
280    evas_pointer_output_xy_get(ee->evas, &x, &y);
281    evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
282    evas_object_move(ee->prop.cursor.object,
283                     x - ee->prop.cursor.hot.x,
284                     y - ee->prop.cursor.hot.y);
285
286    evas_object_pass_events_set(ee->prop.cursor.object, 1);
287
288    if (evas_pointer_inside_get(ee->evas))
289       evas_object_show(ee->prop.cursor.object);
290
291    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee);
292 }
293
294 static Ecore_Evas_Engine_Func _ecore_cocoa_engine_func =
295 {
296    _ecore_evas_cocoa_free,
297    NULL,
298    NULL,
299    NULL,
300    NULL,
301    NULL,
302    NULL,
303    NULL,
304    NULL,
305    NULL,
306    NULL,
307    NULL,
308    NULL,
309    NULL,
310    NULL,
311    NULL,
312    NULL,
313    _ecore_evas_resize,
314    _ecore_evas_move_resize,
315    NULL,
316    NULL,
317    NULL,
318    NULL,
319    NULL,
320    NULL,
321    NULL,
322    NULL,
323    NULL,
324    NULL,
325    NULL,
326    NULL,
327    NULL,
328    _ecore_evas_object_cursor_set,
329    NULL,
330    NULL,
331    NULL,
332    NULL,
333    NULL,
334    NULL,
335    NULL,
336    NULL,
337    NULL,
338    NULL,
339    NULL, //transparent
340      
341      NULL // render
342 };
343 #endif
344
345 EAPI Ecore_Evas *
346 ecore_evas_cocoa_new(const char* name, int w, int h)
347 {
348 #ifdef BUILD_ECORE_EVAS_COCOA
349    Evas_Engine_Info_Quartz *einfo;
350    Ecore_Evas           *ee;
351    int                  rmethod;
352
353    if (!name)
354      name = ecore_evas_cocoa_default;
355
356    rmethod = evas_render_method_lookup("quartz");
357    if (!rmethod) return NULL;
358
359    if (!ecore_cocoa_init(name)) return NULL;
360
361    ee = calloc(1, sizeof(Ecore_Evas));
362    if (!ee)
363      goto shutdown_ecore_cocoa;
364
365    ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
366
367    _ecore_evas_cocoa_init(w, h);
368
369    ecore_event_window_register(0, ee, ee->evas, _ecore_evas_mouse_move_process);
370
371    ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_cocoa_engine_func;
372
373    ee->driver = "quartz";
374    if (name) ee->name = strdup(name);
375    if (!ee->name)
376      goto free_ee;
377
378    if (w < 1) w = 1;
379    if (h < 1) h = 1;
380    ee->visible = 1;
381    ee->w = w;
382    ee->h = h;
383
384    ee->prop.max.w = 0;
385    ee->prop.max.h = 0;
386    ee->prop.layer = 0;
387    ee->prop.focused = 1;
388    ee->prop.borderless = 1;
389    ee->prop.override = 1;
390    ee->prop.maximized = 1;
391    ee->prop.withdrawn = 0;
392    ee->prop.sticky = 0;
393
394    // init evas here
395    ee->evas = evas_new();
396    if (!ee->evas)
397      goto free_name;
398    evas_data_attach_set(ee->evas, ee);
399    evas_output_method_set(ee->evas, rmethod);
400
401    // Set up the Cocoa runtime
402    [[NSAutoreleasePool alloc] init];
403    [NSApplication sharedApplication];
404
405    // Register ourselves as a full-fledged Cocoa app, instead of a NSUIElement.
406    // This gives benefits like window focus and a dock icon!
407    ProcessSerialNumber psn = { 0, kCurrentProcess };
408    TransformProcessType (&psn, kProcessTransformToForegroundApplication);
409
410    [NSApp finishLaunching];
411
412    // Create our main window, and embed an EvasView in it
413    main_window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,w,h) styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask) backing:NSBackingStoreBuffered defer:NO screen:nil];
414    /* FIXME: manage the case where main_window is NULL with a goto free_evas; */
415    [main_window makeKeyAndOrderFront:NSApp];
416    [main_window setTitle:[NSString stringWithUTF8String:name]];
417    [main_window makeMainWindow];
418    [main_window setAcceptsMouseMovedEvents:YES];
419    [NSApp activateIgnoringOtherApps:YES];
420
421    evas_view = [[EvasView alloc] initWithFrame:NSMakeRect(0,0,w,h)];
422    [[main_window contentView] addSubview:evas_view];
423
424    // drawRect: must be run at least once, to make sure we've set ctx
425    [evas_view display];
426
427    evas_output_size_set(ee->evas, w, h);
428    evas_output_viewport_set(ee->evas, 0, 0, w, h);
429
430    einfo = (Evas_Engine_Info_Quartz*) evas_engine_info_get(ee->evas);
431    if (!einfo)
432      goto free_window;
433
434    einfo->info.context = [[evas_view context] retain];
435    if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
436      {
437         ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
438      }
439
440    ecore_evases = (Ecore_Evas *) eina_inlist_prepend(EINA_INLIST_GET(ecore_evases), EINA_INLIST_GET(ee));
441
442    evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL);
443    evas_focus_in(ee->evas);
444
445    return ee;
446
447  free_window:
448    /* FIXME: free window here */
449  free_evas:
450    free(ee->evas);
451  free_name:
452    free(ee->name);
453  free_ee:
454    _ecore_evas_cocoa_shutdown();
455    free(ee);
456  shutdown_ecore_cocoa:
457    ecore_cocoa_shutdown();
458
459    return NULL;
460 #else
461    ERR("OUTCH name='%s' size=%dx%d!", name ? name : "", w, h);
462    return NULL;
463 #endif
464 }