[focus] When an object has focus_chain manager, it should return its own next object...
[framework/uifw/elementary.git] / src / lib / elu_ews_wm.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 static Eina_Bool _ews_used = EINA_FALSE;
5 static Eina_List *_ews_ev_handlers = NULL;
6 static Eina_Hash *_ews_borders = NULL;
7 static Eina_Hash *_ews_borders_geo = NULL;
8 static Evas_Object *_ews_bg = NULL;
9 static Ecore_Animator *_ews_border_mover = NULL;
10 static Evas_Object *_ews_border_mover_obj = NULL;
11 static Evas_Point _ews_border_mover_off = {0, 0};
12
13 static void
14 _elm_ews_border_usable_screen_geometry_get(int *x, int *y, int *w, int *h)
15 {
16    Ecore_Evas *ee = ecore_evas_ews_ecore_evas_get();
17    ecore_evas_geometry_get(ee, NULL, NULL, w, h);
18    if (x) *x = 0;
19    if (y) *y = 0;
20    // TODO: when add a shelf for iconified, subtract its area here.
21 }
22
23 static void
24 _elm_ews_wm_border_del(void *data)
25 {
26    Evas_Object *deco = data;
27    evas_object_del(deco);
28
29    if (_ews_border_mover_obj == deco)
30      {
31         if (_ews_border_mover)
32           {
33              ecore_animator_del(_ews_border_mover);
34              _ews_border_mover = NULL;
35           }
36         _ews_border_mover_obj = NULL;
37      }
38 }
39
40 static Evas_Object *
41 _elm_ews_wm_border_find(const Ecore_Evas *ee)
42 {
43    return eina_hash_find(_ews_borders, &ee);
44 }
45
46 static Eina_Rectangle *
47 _elm_ews_wm_border_geo_find(const Ecore_Evas *ee)
48 {
49    return eina_hash_find(_ews_borders_geo, &ee);
50 }
51
52 static void
53 _elm_ews_border_geo_apply(Ecore_Evas *ee, Evas_Object *o)
54 {
55    int x, y, w, h;
56    ecore_evas_geometry_get(ee, &x, &y, &w, &h);
57    evas_object_move(o, x, y);
58    evas_object_resize(o, w, h);
59 }
60
61 static void
62 _elm_ews_border_focus_apply(Ecore_Evas *ee, Evas_Object *o)
63 {
64    const char *sig;
65    if (ecore_evas_focus_get(ee))
66      sig = "elm,state,focus,on";
67    else
68      sig = "elm,state,focus,off";
69    edje_object_signal_emit(o, sig, "elm");
70 }
71
72 static void
73 _elm_ews_border_stack_apply(Ecore_Evas *ee, Evas_Object *o)
74 {
75    Evas_Object *bs_o = ecore_evas_ews_backing_store_get(ee);
76    evas_object_stack_below(o, bs_o);
77 }
78
79 static void
80 _elm_ews_border_iconified_apply(Ecore_Evas *ee, Evas_Object *o)
81 {
82    const char *sig;
83    if (ecore_evas_iconified_get(ee))
84      sig = "elm,state,iconified,on";
85    else
86      sig = "elm,state,iconified,off";
87    edje_object_signal_emit(o, sig, "elm");
88
89    // TODO: add to some taskbar? and actually hide it?
90    DBG("EWS does not implement iconified yet");
91 }
92
93 static void
94 _elm_ews_border_maximized_apply(Ecore_Evas *ee, Evas_Object *o)
95 {
96    int x, y, w, h;
97    if (ecore_evas_maximized_get(ee))
98      {
99         Eina_Rectangle *r;
100         int ex, ey, ew, eh;
101
102         edje_object_signal_emit(o, "elm,state,maximized,on", "elm");
103         edje_object_message_signal_process(o);
104         ecore_evas_geometry_get(ee, &x, &y, &w, &h);
105
106         r = _elm_ews_wm_border_geo_find(ee);
107         if (!r)
108           {
109              r = malloc(sizeof(Eina_Rectangle));
110              eina_hash_add(_ews_borders_geo, &ee, r);
111           }
112
113         r->x = x;
114         r->y = y;
115         r->w = w;
116         r->h = h;
117         _elm_ews_border_usable_screen_geometry_get(&x, &y, &w, &h);
118         edje_object_parts_extends_calc(o, &ex, &ey, &ew, &eh);
119         x -= ex;
120         y -= ey;
121         w -= ew - r->w;
122         h -= eh - r->h;
123      }
124    else
125      {
126         Eina_Rectangle *r = _elm_ews_wm_border_geo_find(ee);
127         edje_object_signal_emit(o, "elm,state,maximized,off", "elm");
128
129         if (!r) ecore_evas_geometry_get(ee, &x, &y, &w, &h);
130         else
131           {
132              x = r->x;
133              y = r->y;
134              w = r->w;
135              h = r->h;
136           }
137      }
138
139    ecore_evas_move_resize(ee, x, y, w, h);
140    _elm_ews_border_geo_apply(ee, o);
141 }
142
143 static void
144 _elm_ews_border_layer_apply(Ecore_Evas *ee, Evas_Object *o)
145 {
146    Evas_Object *bs_o = ecore_evas_ews_backing_store_get(ee);
147    evas_object_layer_set(o, evas_object_layer_get(bs_o));
148    _elm_ews_border_stack_apply(ee, o);
149 }
150
151 static void
152 _elm_ews_border_fullscreen_apply(Ecore_Evas *ee, Evas_Object *o)
153 {
154    const char *sig;
155    if (ecore_evas_fullscreen_get(ee))
156      sig = "elm,state,fullscreen,on";
157    else
158      sig = "elm,state,fullscreen,off";
159    edje_object_signal_emit(o, sig, "elm");
160    _elm_ews_border_geo_apply(ee, o);
161 }
162
163 static void
164 _elm_ews_border_config_apply(Ecore_Evas *ee, Evas_Object *o, Elm_Theme *th)
165 {
166    const char *title, *name = NULL, *class = NULL, *style = NULL;
167    const char *sig;
168
169    if (ecore_evas_borderless_get(ee))
170      style = "borderless";
171
172    _elm_theme_set(th, o, "ews", "decoration", style ? style : "default");
173
174    if (ecore_evas_shaped_get(ee) || ecore_evas_alpha_get(ee) ||
175        ecore_evas_transparent_get(ee))
176      sig = "elm,state,alpha,on";
177    else
178      sig = "elm,state,alpha,off";
179    edje_object_signal_emit(o, sig, "elm");
180
181    title = ecore_evas_title_get(ee);
182    ecore_evas_name_class_get(ee, &name, &class);
183    edje_object_part_text_escaped_set(o, "elm.text.title", title);
184    edje_object_part_text_escaped_set(o, "elm.text.name", name);
185    edje_object_part_text_escaped_set(o, "elm.text.class", class);
186
187    _elm_ews_border_geo_apply(ee, o);
188    _elm_ews_border_focus_apply(ee, o);
189    _elm_ews_border_stack_apply(ee, o);
190    _elm_ews_border_iconified_apply(ee, o);
191    _elm_ews_border_maximized_apply(ee, o);
192    _elm_ews_border_layer_apply(ee, o);
193    _elm_ews_border_fullscreen_apply(ee, o);
194 }
195
196 static Eina_Bool
197 _elm_ews_wm_border_theme_set(Ecore_Evas *ee, Evas_Object *o, Elm_Theme *th)
198 {
199    _elm_ews_border_config_apply(ee, o, th);
200    return EINA_TRUE;
201 }
202
203 static void
204 _elm_ews_border_sig_focus(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
205 {
206    Ecore_Evas *ee = data;
207    ecore_evas_focus_set(ee, EINA_TRUE);
208 }
209
210 static void
211 _elm_ews_border_sig_iconify(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
212 {
213    Ecore_Evas *ee = data;
214    ecore_evas_iconified_set(ee, EINA_TRUE);
215 }
216
217 static void
218 _elm_ews_border_sig_maximize(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
219 {
220    Ecore_Evas *ee = data;
221    ecore_evas_maximized_set(ee, EINA_TRUE);
222 }
223
224 static void
225 _elm_ews_border_sig_fullscreen(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
226 {
227    Ecore_Evas *ee = data;
228    ecore_evas_fullscreen_set(ee, EINA_TRUE);
229 }
230
231 static void
232 _elm_ews_border_sig_restore(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
233 {
234    Ecore_Evas *ee = data;
235    ecore_evas_iconified_set(ee, EINA_FALSE);
236    ecore_evas_maximized_set(ee, EINA_FALSE);
237    ecore_evas_fullscreen_set(ee, EINA_FALSE);
238 }
239
240 static void
241 _elm_ews_border_sig_close(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
242 {
243    Ecore_Evas *ee = data;
244    ecore_evas_ews_delete_request(ee);
245 }
246
247 static void
248 _elm_ews_border_sig_menu(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
249 {
250    // TODO: show some menu?
251    ERR("EWS does not implement menu yet");
252    (void)data;
253 }
254
255 static Eina_Bool
256 _elm_ews_border_mover(void *data)
257 {
258    Ecore_Evas *ee = data;
259    Evas_Object *o = _elm_ews_wm_border_find(ee);
260    int x, y;
261
262    evas_pointer_output_xy_get(ecore_evas_ews_evas_get(), &x, &y);
263    x -= _ews_border_mover_off.x;
264    y -= _ews_border_mover_off.y;
265    ecore_evas_move(ee, x, y);
266    evas_object_move(o, x, y);
267
268    return EINA_TRUE;
269 }
270
271 static void
272 _elm_ews_border_sig_move_start(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
273 {
274    Ecore_Evas *ee = data;
275    Evas_Object *bs_o = ecore_evas_ews_backing_store_get(ee);
276    int x, y, ox, oy;
277
278    if (_ews_border_mover) ecore_animator_del(_ews_border_mover);
279
280    evas_pointer_output_xy_get(evas_object_evas_get(bs_o), &x, &y);
281    evas_object_geometry_get(bs_o, &ox, &oy, NULL, NULL);
282    _ews_border_mover_off.x = x - ox;
283    _ews_border_mover_off.y = y - oy;
284    _ews_border_mover_obj = bs_o;
285    _ews_border_mover = ecore_animator_add(_elm_ews_border_mover, ee);
286 }
287
288 static void
289 _elm_ews_border_sig_move_stop(void *data __UNUSED__, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
290 {
291    if (!_ews_border_mover) return;
292    ecore_animator_del(_ews_border_mover);
293    _ews_border_mover = NULL;
294    _ews_border_mover_obj = NULL;
295 }
296
297 static Eina_Bool
298 _elm_ews_wm_add_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
299 {
300    Ecore_Evas *ee = event_info;
301    Evas_Object *o = edje_object_add(ecore_evas_ews_evas_get());
302    Evas_Coord x, y, w, h, sw, sh;
303
304    edje_object_signal_callback_add
305      (o, "elm,action,focus", "elm", _elm_ews_border_sig_focus, ee);
306    edje_object_signal_callback_add
307      (o, "elm,action,iconify", "elm", _elm_ews_border_sig_iconify, ee);
308    edje_object_signal_callback_add
309      (o, "elm,action,maximize", "elm", _elm_ews_border_sig_maximize, ee);
310    edje_object_signal_callback_add
311      (o, "elm,action,fullscreen", "elm", _elm_ews_border_sig_fullscreen, ee);
312    edje_object_signal_callback_add
313      (o, "elm,action,restore", "elm", _elm_ews_border_sig_restore, ee);
314    edje_object_signal_callback_add
315      (o, "elm,action,close", "elm", _elm_ews_border_sig_close, ee);
316    edje_object_signal_callback_add
317      (o, "elm,action,menu", "elm", _elm_ews_border_sig_menu, ee);
318    edje_object_signal_callback_add
319      (o, "elm,action,move,start", "elm", _elm_ews_border_sig_move_start, ee);
320    edje_object_signal_callback_add
321      (o, "elm,action,move,stop", "elm", _elm_ews_border_sig_move_stop, ee);
322
323    eina_hash_add(_ews_borders, &ee, o);
324    _elm_ews_wm_border_theme_set(ee, o, NULL);
325
326    ecore_evas_screen_geometry_get(ee, NULL, NULL, &sw, &sh);
327    ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
328    x = (sw - w) / 2;
329    y = (sh - h) / 2;
330    ecore_evas_move(ee, x, y);
331    ecore_evas_focus_set(ee, EINA_TRUE);
332
333    return EINA_TRUE;
334 }
335
336 static Eina_Bool
337 _elm_ews_wm_del_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
338 {
339    Ecore_Evas *ee = event_info;
340    eina_hash_del(_ews_borders, &ee, NULL);
341    eina_hash_del(_ews_borders_geo, &ee, NULL);
342    return EINA_TRUE;
343 }
344
345 static Eina_Bool
346 _elm_ews_wm_geo_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
347 {
348    Ecore_Evas *ee = event_info;
349    Evas_Object *o = _elm_ews_wm_border_find(ee);
350    _elm_ews_border_geo_apply(ee, o);
351    return EINA_TRUE;
352 }
353
354 static Eina_Bool
355 _elm_ews_wm_show_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
356 {
357    Ecore_Evas *ee = event_info;
358    Evas_Object *o = _elm_ews_wm_border_find(ee);
359    evas_object_show(o);
360    return EINA_TRUE;
361 }
362
363 static Eina_Bool
364 _elm_ews_wm_hide_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
365 {
366    Ecore_Evas *ee = event_info;
367    Evas_Object *o = _elm_ews_wm_border_find(ee);
368    evas_object_hide(o);
369    return EINA_TRUE;
370 }
371
372 static Eina_Bool
373 _elm_ews_wm_focus_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
374 {
375    Ecore_Evas *ee = event_info;
376    Evas_Object *o = _elm_ews_wm_border_find(ee);
377    _elm_ews_border_focus_apply(ee, o);
378    return EINA_TRUE;
379 }
380
381 static Eina_Bool
382 _elm_ews_wm_stack_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
383 {
384    Ecore_Evas *ee = event_info;
385    Evas_Object *o = _elm_ews_wm_border_find(ee);
386    _elm_ews_border_stack_apply(ee, o);
387    return EINA_TRUE;
388 }
389
390 static Eina_Bool
391 _elm_ews_wm_iconified_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
392 {
393    Ecore_Evas *ee = event_info;
394    Evas_Object *o = _elm_ews_wm_border_find(ee);
395    _elm_ews_border_iconified_apply(ee, o);
396    return EINA_TRUE;
397 }
398
399 static Eina_Bool
400 _elm_ews_wm_maximized_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
401 {
402    Ecore_Evas *ee = event_info;
403    Evas_Object *o = _elm_ews_wm_border_find(ee);
404    _elm_ews_border_maximized_apply(ee, o);
405    return EINA_TRUE;
406 }
407
408 static Eina_Bool
409 _elm_ews_wm_layer_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
410 {
411    Ecore_Evas *ee = event_info;
412    Evas_Object *o = _elm_ews_wm_border_find(ee);
413    _elm_ews_border_layer_apply(ee, o);
414    return EINA_TRUE;
415 }
416
417 static Eina_Bool
418 _elm_ews_wm_fullscreen_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
419 {
420    Ecore_Evas *ee = event_info;
421    Evas_Object *o = _elm_ews_wm_border_find(ee);
422    _elm_ews_border_fullscreen_apply(ee, o);
423    return EINA_TRUE;
424 }
425
426 static Eina_Bool
427 _elm_ews_wm_config_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
428 {
429    Ecore_Evas *ee = event_info;
430    Evas_Object *o = _elm_ews_wm_border_find(ee);
431    _elm_ews_border_config_apply(ee, o, NULL);
432    return EINA_TRUE;
433 }
434
435 void
436 _elm_ews_wm_rescale(Elm_Theme *th, Eina_Bool use_theme)
437 {
438    Eina_Iterator *it;
439    Eina_Hash_Tuple *tp = NULL;
440
441    if (!_ews_borders) return;
442    it = eina_hash_iterator_tuple_new(_ews_borders);
443    if (!use_theme)
444      {
445         EINA_ITERATOR_FOREACH(it, tp)
446           _elm_ews_wm_border_theme_set(*(void**)tp->key, tp->data, NULL);
447
448         if (_ews_bg)
449           _elm_theme_set(NULL, _ews_bg, "ews", "background", "default");
450      }
451    else
452      {
453         EINA_ITERATOR_FOREACH(it, tp)
454           _elm_ews_wm_border_theme_set(*(void**)tp->key, tp->data, th);
455
456         if (_ews_bg)
457           _elm_theme_set(th, _ews_bg, "ews", "background", "default");
458      }
459
460    eina_iterator_free(it);
461 }
462
463 int
464 _elm_ews_wm_init(void)
465 {
466    Evas *e;
467    Evas_Object *o;
468
469    if (strcmp(_elm_config->engine, ELM_EWS) != 0)
470      {
471         _ews_used = EINA_FALSE;
472         return EINA_TRUE;
473      }
474
475    e = ecore_evas_ews_evas_get();
476    if (!e) return EINA_FALSE;
477    o = edje_object_add(e);
478    if (!o) return EINA_FALSE;
479
480    if (!_elm_theme_set(NULL, o, "ews", "background", "default"))
481      {
482         ERR("Could not set background theme, fallback to rectangle");
483         evas_object_del(o);
484         _ews_bg = o = NULL;
485      }
486    else
487      _ews_bg = o;
488    ecore_evas_ews_background_set(o);
489
490
491 #define ADD_EH(ev, cb)                                          \
492    _ews_ev_handlers = eina_list_append                          \
493      (_ews_ev_handlers, ecore_event_handler_add(ev, cb, NULL))
494    ADD_EH(ECORE_EVAS_EWS_EVENT_ADD, _elm_ews_wm_add_cb);
495    ADD_EH(ECORE_EVAS_EWS_EVENT_DEL, _elm_ews_wm_del_cb);
496    ADD_EH(ECORE_EVAS_EWS_EVENT_RESIZE, _elm_ews_wm_geo_cb);
497    ADD_EH(ECORE_EVAS_EWS_EVENT_MOVE, _elm_ews_wm_geo_cb);
498    ADD_EH(ECORE_EVAS_EWS_EVENT_SHOW, _elm_ews_wm_show_cb);
499    ADD_EH(ECORE_EVAS_EWS_EVENT_HIDE, _elm_ews_wm_hide_cb);
500    ADD_EH(ECORE_EVAS_EWS_EVENT_FOCUS, _elm_ews_wm_focus_cb);
501    ADD_EH(ECORE_EVAS_EWS_EVENT_UNFOCUS, _elm_ews_wm_focus_cb);
502    ADD_EH(ECORE_EVAS_EWS_EVENT_RAISE, _elm_ews_wm_stack_cb);
503    ADD_EH(ECORE_EVAS_EWS_EVENT_LOWER, _elm_ews_wm_stack_cb);
504    ADD_EH(ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE, _elm_ews_wm_iconified_change_cb);
505    ADD_EH(ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE, _elm_ews_wm_maximized_change_cb);
506    ADD_EH(ECORE_EVAS_EWS_EVENT_LAYER_CHANGE, _elm_ews_wm_layer_change_cb);
507    ADD_EH(ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE, _elm_ews_wm_fullscreen_change_cb);
508    ADD_EH(ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE, _elm_ews_wm_config_change_cb);
509 #undef ADD_EH
510
511    if (!_ews_borders)
512      _ews_borders = eina_hash_pointer_new(_elm_ews_wm_border_del);
513
514    if (!_ews_borders_geo)
515      _ews_borders_geo = eina_hash_pointer_new(free);
516
517    _ews_used = EINA_TRUE;
518    return EINA_TRUE;
519 }
520
521 void
522 _elm_ews_wm_shutdown(void)
523 {
524    Ecore_Event_Handler *eh;
525
526    if (_ews_border_mover)
527      {
528         ecore_animator_del(_ews_border_mover);
529         _ews_border_mover = NULL;
530      }
531    _ews_border_mover_obj = NULL;
532
533    EINA_LIST_FREE(_ews_ev_handlers, eh) ecore_event_handler_del(eh);
534    if (_ews_borders)
535      {
536         eina_hash_free(_ews_borders);
537         _ews_borders = NULL;
538      }
539    if (_ews_borders_geo)
540      {
541         eina_hash_free(_ews_borders_geo);
542         _ews_borders_geo = NULL;
543      }
544    _ews_bg = NULL;
545 }