Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_evas / ecore_evas_wayland_shm.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 //#define LOGFNS 1
6
7 #ifdef LOGFNS
8 # include <stdio.h>
9 # define LOGFN(fl, ln, fn) \
10    printf("-ECORE_EVAS-WL: %25s: %5i - %s\n", fl, ln, fn);
11 #else
12 # define LOGFN(fl, ln, fn)
13 #endif
14
15 #ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
16 # include <stdlib.h>
17 # include <string.h>
18 # include <unistd.h>
19 # include <sys/types.h>
20 # include <sys/mman.h>
21 #endif
22
23 #include <Eina.h>
24
25 #include "Ecore_Evas.h"
26
27 #ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
28 # include "ecore_evas_private.h"
29 # include <Evas_Engine_Wayland_Shm.h>
30 # include <Ecore_Wayland.h>
31
32 /* local function prototypes */
33 static void _ecore_evas_wl_free(Ecore_Evas *ee);
34 static void _ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h);
35 static void _ecore_evas_wl_move_resize(Ecore_Evas *ee, int x, int y, int w, int h);
36 static void _ecore_evas_wl_show(Ecore_Evas *ee);
37 static void _ecore_evas_wl_hide(Ecore_Evas *ee);
38 static void _ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha);
39 static void _ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent);
40 static int  _ecore_evas_wl_render(Ecore_Evas *ee);
41
42 /* SHM Only */
43 static void _ecore_evas_wl_shm_pool_free(Ecore_Evas *ee);
44 static void _ecore_evas_wl_shm_pool_create(Ecore_Evas *ee, size_t size);
45 static void _ecore_evas_wl_buffer_free(Ecore_Evas *ee);
46 static void _ecore_evas_wl_buffer_new(Ecore_Evas *ee, int w, int h);
47
48 /* Frame listener */
49 static void _ecore_evas_wl_frame_complete(void *data, struct wl_callback *callback, uint32_t time);
50 static const struct wl_callback_listener frame_listener =
51 {
52    _ecore_evas_wl_frame_complete,
53 };
54
55 static Ecore_Evas_Engine_Func _ecore_wl_engine_func = 
56 {
57    _ecore_evas_wl_free,
58    _ecore_evas_wl_common_callback_resize_set,
59    _ecore_evas_wl_common_callback_move_set,
60    NULL, 
61    NULL,
62    _ecore_evas_wl_common_callback_delete_request_set,
63    NULL,
64    _ecore_evas_wl_common_callback_focus_in_set,
65    _ecore_evas_wl_common_callback_focus_out_set,
66    _ecore_evas_wl_common_callback_mouse_in_set,
67    _ecore_evas_wl_common_callback_mouse_out_set,
68    NULL, // sticky_set
69    NULL, // unsticky_set
70    NULL, // pre_render_set
71    NULL, // post_render_set
72    _ecore_evas_wl_common_move,
73    NULL, // managed_move
74    _ecore_evas_wl_resize,
75    _ecore_evas_wl_move_resize,
76    NULL, // rotation_set
77    NULL, // shaped_set
78    _ecore_evas_wl_show,
79    _ecore_evas_wl_hide,
80    _ecore_evas_wl_common_raise,
81    NULL, // lower
82    NULL, // activate
83    _ecore_evas_wl_common_title_set,
84    _ecore_evas_wl_common_name_class_set,
85    _ecore_evas_wl_common_size_min_set,
86    _ecore_evas_wl_common_size_max_set,
87    _ecore_evas_wl_common_size_base_set,
88    _ecore_evas_wl_common_size_step_set,
89    NULL, // object_cursor_set
90    _ecore_evas_wl_common_layer_set,
91    NULL, // focus set
92    _ecore_evas_wl_common_iconified_set,
93    NULL, // borderless set
94    NULL, // override set
95    _ecore_evas_wl_common_maximized_set,
96    _ecore_evas_wl_common_fullscreen_set,
97    NULL, // func avoid_damage set
98    NULL, // func withdrawn set
99    NULL, // func sticky set
100    _ecore_evas_wl_common_ignore_events_set,
101    _ecore_evas_wl_alpha_set,
102    _ecore_evas_wl_transparent_set,
103    NULL, // func profiles set
104    NULL, // window group set
105    NULL, // aspect set
106    NULL, // urgent set
107    NULL, // modal set
108    NULL, // demand attention set
109    NULL, // focus skip set
110    _ecore_evas_wl_render,
111    _ecore_evas_wl_common_screen_geometry_get,
112    _ecore_evas_wl_common_screen_dpi_get
113 };
114
115 /* external variables */
116
117 /* external functions */
118 EAPI Ecore_Evas *
119 ecore_evas_wayland_shm_new(const char *disp_name, unsigned int parent, int x, int y, int w, int h, Eina_Bool frame)
120 {
121    Ecore_Wl_Window *p = NULL;
122    Evas_Engine_Info_Wayland_Shm *einfo;
123    Ecore_Evas *ee;
124    int method = 0, count = 0;
125
126    LOGFN(__FILE__, __LINE__, __FUNCTION__);
127
128    if (!(method = evas_render_method_lookup("wayland_shm")))
129      {
130         ERR("Render method lookup failed for Wayland_Shm");
131         return NULL;
132      }
133
134    count = ecore_wl_init(disp_name);
135    if (!count)
136      {
137         ERR("Failed to initialize Ecore_Wayland");
138         return NULL;
139      }
140    else if (count == 1)
141      ecore_wl_display_iterate();
142
143    if (!(ee = calloc(1, sizeof(Ecore_Evas))))
144      {
145         ERR("Failed to allocate Ecore_Evas");
146         goto ee_err;
147      }
148
149    ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
150
151    _ecore_evas_wl_common_init();
152
153    ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_wl_engine_func;
154
155    ee->driver = "wayland_shm";
156    if (disp_name) ee->name = strdup(disp_name);
157
158    if (w < 1) w = 1;
159    if (h < 1) h = 1;
160
161    ee->x = x;
162    ee->y = y;
163    ee->w = w;
164    ee->h = h;
165    ee->req.x = ee->x;
166    ee->req.y = ee->y;
167    ee->req.w = ee->w;
168    ee->req.h = ee->h;
169    ee->rotation = 0;
170    ee->prop.max.w = 32767;
171    ee->prop.max.h = 32767;
172    ee->prop.layer = 4;
173    ee->prop.request_pos = 0;
174    ee->prop.sticky = 0;
175    ee->prop.draw_frame = frame;
176    ee->alpha = EINA_FALSE;
177
178    ee->evas = evas_new();
179    evas_data_attach_set(ee->evas, ee);
180    evas_output_method_set(ee->evas, method);
181    evas_output_size_set(ee->evas, ee->w, ee->h);
182    evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
183
184    /* FIXME: This needs to be set based on theme & scale */
185    if (ee->prop.draw_frame)
186      evas_output_framespace_set(ee->evas, 4, 18, 8, 22);
187
188    if (parent)
189      p = ecore_wl_window_find(parent);
190
191    /* FIXME: Get if parent is alpha, and set */
192
193    ee->engine.wl.parent = p;
194    ee->engine.wl.win = 
195      ecore_wl_window_new(p, x, y, w, h, ECORE_WL_WINDOW_BUFFER_TYPE_SHM);
196    ee->prop.window = ee->engine.wl.win->id;
197
198    if ((einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas)))
199      {
200         einfo->info.destination_alpha = ee->alpha;
201         einfo->info.rotation = ee->rotation;
202         if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
203           {
204              ERR("Failed to set Evas Engine Info for '%s'", ee->driver);
205              goto err;
206           }
207      }
208    else 
209      {
210         ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
211         goto err;
212      }
213
214    ecore_evas_callback_pre_free_set(ee, _ecore_evas_wl_common_pre_free);
215
216    if (ee->prop.draw_frame) 
217      {
218         ee->engine.wl.frame = _ecore_evas_wl_common_frame_add(ee->evas);
219         evas_object_is_frame_object_set(ee->engine.wl.frame, EINA_TRUE);
220         evas_object_move(ee->engine.wl.frame, 0, 0);
221      }
222
223    _ecore_evas_register(ee);
224    ecore_evas_input_event_register(ee);
225
226    ecore_event_window_register(ee->prop.window, ee, ee->evas, 
227                                (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, 
228                                (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, 
229                                (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, 
230                                (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
231
232    return ee;
233
234  err:
235    ecore_evas_free(ee);
236    _ecore_evas_wl_common_shutdown();
237
238  ee_err:
239    ecore_wl_shutdown();
240    return NULL;
241 }
242
243 static void 
244 _ecore_evas_wl_free(Ecore_Evas *ee)
245 {
246    _ecore_evas_wl_buffer_free(ee);
247    _ecore_evas_wl_shm_pool_free(ee);
248    _ecore_evas_wl_common_free(ee);
249 }
250
251 static void 
252 _ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h)
253 {
254    Evas_Engine_Info_Wayland_Shm *einfo;
255    int fw = 0, fh = 0;
256
257    LOGFN(__FILE__, __LINE__, __FUNCTION__);
258
259    if (!ee) return;
260    if (w < 1) w = 1;
261    if (h < 1) h = 1;
262
263    ee->req.w = w;
264    ee->req.h = h;
265
266    if (!ee->prop.fullscreen)
267      {
268         int fw = 0, fh = 0;
269
270         if (ee->prop.min.w > w) w = ee->prop.min.w;
271         else if (w > ee->prop.max.w) w = ee->prop.max.w;
272         if (ee->prop.min.h > h) h = ee->prop.min.h;
273         else if (h > ee->prop.max.h) h = ee->prop.max.h;
274
275         evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
276         w += fw;
277         h += fh;
278      }
279
280    if ((ee->w != w) || (ee->h != h))
281      {
282         ee->w = w;
283         ee->h = h;
284
285         if ((ee->rotation == 90) || (ee->rotation == 270))
286           {
287              evas_output_size_set(ee->evas, h, w);
288              evas_output_viewport_set(ee->evas, 0, 0, h, w);
289           }
290         else
291           {
292              evas_output_size_set(ee->evas, w, h);
293              evas_output_viewport_set(ee->evas, 0, 0, w, h);
294           }
295
296         if (ee->prop.avoid_damage)
297           {
298              int pdam = 0;
299
300              pdam = ecore_evas_avoid_damage_get(ee);
301              ecore_evas_avoid_damage_set(ee, 0);
302              ecore_evas_avoid_damage_set(ee, pdam);
303           }
304
305         if (ee->engine.wl.frame)
306           evas_object_resize(ee->engine.wl.frame, w, h);
307
308         _ecore_evas_wl_buffer_new(ee, w, h);
309
310         einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas);
311         if (!einfo)
312           {
313             ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
314             return;
315           }
316
317         einfo->info.dest = ee->engine.wl.pool_data;
318         evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
319
320         if (ee->engine.wl.win)
321           {
322              ecore_wl_window_update_size(ee->engine.wl.win, w, h);
323              ecore_wl_window_buffer_attach(ee->engine.wl.win, 
324                                            ee->engine.wl.buffer, 0, 0);
325           }
326
327         if (ee->func.fn_resize) ee->func.fn_resize(ee);
328      }
329 }
330
331 static void 
332 _ecore_evas_wl_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
333 {
334    LOGFN(__FILE__, __LINE__, __FUNCTION__);
335
336    if (!ee) return;
337    if ((ee->x != x) || (ee->y != y))
338      _ecore_evas_wl_common_move(ee, x, y);
339    if ((ee->w != w) || (ee->h != h))
340      _ecore_evas_wl_resize(ee, w, h);
341 }
342
343 static void
344 _ecore_evas_wl_show(Ecore_Evas *ee)
345 {
346    Evas_Engine_Info_Wayland_Shm *einfo;
347
348    LOGFN(__FILE__, __LINE__, __FUNCTION__);
349
350    if ((!ee) || (ee->visible)) return;
351
352    _ecore_evas_wl_buffer_new(ee, ee->w, ee->h);
353
354    einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas);
355    if (!einfo)
356      {
357         ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
358         return;
359      }
360
361    einfo->info.dest = ee->engine.wl.pool_data;
362    evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
363
364    if (ee->engine.wl.win)
365      {
366         ecore_wl_window_show(ee->engine.wl.win);
367         ecore_wl_window_update_size(ee->engine.wl.win, ee->w, ee->h);
368         ecore_wl_window_buffer_attach(ee->engine.wl.win, 
369                                       ee->engine.wl.buffer, 0, 0);
370
371         if ((ee->prop.clas) && (ee->engine.wl.win->shell_surface))
372           wl_shell_surface_set_class(ee->engine.wl.win->shell_surface, 
373                                      ee->prop.clas);
374         if ((ee->prop.title) && (ee->engine.wl.win->shell_surface))
375           wl_shell_surface_set_title(ee->engine.wl.win->shell_surface, 
376                                      ee->prop.title);
377      }
378
379    if (ee->engine.wl.frame)
380      {
381         evas_object_show(ee->engine.wl.frame);
382         evas_object_resize(ee->engine.wl.frame, ee->w, ee->h);
383      }
384
385    ee->visible = 1;
386    if (ee->func.fn_show) ee->func.fn_show(ee);
387 }
388
389 static void 
390 _ecore_evas_wl_hide(Ecore_Evas *ee)
391 {
392    Evas_Engine_Info_Wayland_Shm *einfo;
393
394    LOGFN(__FILE__, __LINE__, __FUNCTION__);
395
396    if ((!ee) || (!ee->visible)) return;
397
398    _ecore_evas_wl_buffer_free(ee);
399
400    munmap(ee->engine.wl.pool_data, ee->engine.wl.pool_size);
401
402    einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas);
403    if ((einfo) && (einfo->info.dest))
404      {
405         einfo->info.dest = NULL;
406         evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
407      }
408
409    if (ee->engine.wl.win) 
410      ecore_wl_window_hide(ee->engine.wl.win);
411
412    ee->visible = 0;
413    ee->should_be_visible = 0;
414
415    if (ee->func.fn_hide) ee->func.fn_hide(ee);
416 }
417
418 static void 
419 _ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha)
420 {
421    Evas_Engine_Info_Wayland_Shm *einfo;
422    Ecore_Wl_Window *win = NULL;
423
424    LOGFN(__FILE__, __LINE__, __FUNCTION__);
425
426    if (!ee) return;
427    if ((ee->alpha == alpha)) return;
428    ee->alpha = alpha;
429
430    /* FIXME: NB: We should really add a ecore_wl_window_alpha_set function
431     * but we are in API freeze, so just hack it in for now and fix when 
432     * freeze is over */
433    if ((win = ee->engine.wl.win))
434      win->alpha = alpha;
435
436    /* if (ee->engine.wl.win) */
437    /*   ecore_wl_window_transparent_set(ee->engine.wl.win, alpha); */
438
439    _ecore_evas_wl_buffer_new(ee, ee->w, ee->h);
440
441    if ((einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas)))
442      {
443         einfo->info.destination_alpha = alpha;
444         einfo->info.dest = ee->engine.wl.pool_data;
445         if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
446           ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
447         evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
448      }
449
450    if (win)
451      {
452         ecore_wl_window_update_size(win, ee->w, ee->h);
453         ecore_wl_window_buffer_attach(win, ee->engine.wl.buffer, 0, 0);
454      }
455 }
456
457 static void 
458 _ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent)
459 {
460    Evas_Engine_Info_Wayland_Shm *einfo;
461
462    LOGFN(__FILE__, __LINE__, __FUNCTION__);
463
464    if (!ee) return;
465    if ((ee->transparent == transparent)) return;
466    ee->transparent = transparent;
467
468    if (ee->engine.wl.win)
469      ecore_wl_window_transparent_set(ee->engine.wl.win, transparent);
470
471    _ecore_evas_wl_buffer_new(ee, ee->w, ee->h);
472
473    if ((einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas)))
474      {
475         einfo->info.destination_alpha = transparent;
476         einfo->info.dest = ee->engine.wl.pool_data;
477         if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
478           ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
479         evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
480      }
481
482    if (ee->engine.wl.win)
483      {
484         ecore_wl_window_update_size(ee->engine.wl.win, ee->w, ee->h);
485         ecore_wl_window_buffer_attach(ee->engine.wl.win, 
486                                       ee->engine.wl.buffer, 0, 0);
487      }
488 }
489
490 static void
491 _ecore_evas_wl_frame_complete(void *data, struct wl_callback *callback, uint32_t time __UNUSED__)
492 {
493    Ecore_Evas *ee = data;
494    Ecore_Wl_Window *win = NULL;
495
496    if (!ee) return;
497    if (!(win = ee->engine.wl.win)) return;
498
499    win->frame_callback = NULL;
500    win->frame_pending = EINA_FALSE;
501    wl_callback_destroy(callback);
502
503    if (win->surface)
504      {
505         win->frame_callback = wl_surface_frame(win->surface);
506         wl_callback_add_listener(win->frame_callback, &frame_listener, ee);
507      }
508 }
509
510 static int
511 _ecore_evas_wl_render(Ecore_Evas *ee)
512 {
513    int rend = 0;
514    Ecore_Wl_Window *win = NULL;
515
516    if (!ee) return 0;
517    if (!ee->visible)
518      {
519         evas_norender(ee->evas);
520         return 0;
521      }
522
523    if (!(win = ee->engine.wl.win)) return 0;
524
525    rend = _ecore_evas_wl_common_pre_render(ee);
526    if (!(win->frame_pending))
527      {
528         /* FIXME - ideally have an evas_changed_get to return the value
529          * of evas->changed to avoid creating this callback and
530          * destroying it again
531          */
532
533         if (!win->frame_callback)
534           {
535              win->frame_callback = wl_surface_frame(win->surface);
536              wl_callback_add_listener(win->frame_callback, &frame_listener, ee);
537           }
538
539         rend |= _ecore_evas_wl_common_render_updates(ee);
540         if (rend)
541            win->frame_pending = EINA_TRUE;
542      }
543    _ecore_evas_wl_common_post_render(ee);
544    return rend;
545 }
546
547 static void
548 _ecore_evas_wl_shm_pool_free(Ecore_Evas *ee)
549 {
550    if (!ee->engine.wl.pool) return;
551
552    wl_shm_pool_destroy(ee->engine.wl.pool);
553    ee->engine.wl.pool = NULL;
554    ee->engine.wl.pool_size = 0;
555    ee->engine.wl.pool_data = NULL;
556 }
557
558 static void
559 _ecore_evas_wl_shm_pool_create(Ecore_Evas *ee, size_t size)
560 {
561    struct wl_shm *shm;
562    void *data;
563    char tmp[PATH_MAX];
564    int fd;
565
566    LOGFN(__FILE__, __LINE__, __FUNCTION__);
567
568    if (size <= ee->engine.wl.pool_size)
569       return;
570
571    size *= 1.5;
572    _ecore_evas_wl_shm_pool_free(ee);
573
574    if (!(shm = ecore_wl_shm_get()))
575      {
576         ERR("ecore_wl_shm_get returned NULL");
577         return;
578      }
579
580    strcpy(tmp, "/tmp/ecore-evas-wayland_shm-XXXXXX");
581    if ((fd = mkstemp(tmp)) < 0) 
582      {
583         ERR("Could not create temporary file.");
584         return;
585      }
586
587    if (ftruncate(fd, size) < 0) 
588      {
589         ERR("Could not truncate temporary file.");
590         goto end;
591      }
592
593    data = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
594    unlink(tmp);
595
596    if (data == MAP_FAILED)
597      {
598         ERR("mmap of temporary file failed.");
599         goto end;
600      }
601
602    ee->engine.wl.pool_size = size;
603    ee->engine.wl.pool_data = data;
604    ee->engine.wl.pool = wl_shm_create_pool(shm, fd, size);
605
606  end:
607    close(fd);
608 }
609
610 static void
611 _ecore_evas_wl_buffer_free(Ecore_Evas *ee)
612 {
613    if (!ee->engine.wl.buffer) return;
614
615    wl_buffer_destroy(ee->engine.wl.buffer);
616    ee->engine.wl.buffer = NULL;
617 }
618
619 static void 
620 _ecore_evas_wl_buffer_new(Ecore_Evas *ee, int w, int h)
621 {
622    unsigned int format;
623    int stride = 0;
624
625    stride = (w * sizeof(int));
626
627    _ecore_evas_wl_shm_pool_create(ee, stride * h);
628
629    if ((ee->alpha) || (ee->transparent))
630      format = WL_SHM_FORMAT_ARGB8888;
631    else
632      format = WL_SHM_FORMAT_XRGB8888;
633
634    _ecore_evas_wl_buffer_free(ee);
635    ee->engine.wl.buffer = 
636      wl_shm_pool_create_buffer(ee->engine.wl.pool, 0, w, h, stride, format);
637 }
638
639 void 
640 _ecore_evas_wayland_shm_resize(Ecore_Evas *ee, int location)
641 {
642    LOGFN(__FILE__, __LINE__, __FUNCTION__);
643
644    if (!ee) return;
645    if (ee->engine.wl.win) 
646      {
647         ee->engine.wl.win->resizing = EINA_TRUE;
648         ecore_wl_window_resize(ee->engine.wl.win, ee->w, ee->h, location);
649      }
650 }
651 #else
652 EAPI Ecore_Evas *
653 ecore_evas_wayland_shm_new(const char *disp_name __UNUSED__, unsigned int parent __UNUSED__, int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__, Eina_Bool frame __UNUSED__)
654 {
655    return NULL;
656 }
657 #endif