#ifdef HAVE_CONFIG_H # include "elementary_config.h" #endif #include #include "elm_priv.h" static Eina_Bool _ews_used = EINA_FALSE; static Eina_List *_ews_ev_handlers = NULL; static Eina_Hash *_ews_borders = NULL; static Eina_Hash *_ews_borders_geo = NULL; static Evas_Object *_ews_bg = NULL; static Ecore_Animator *_ews_border_mover = NULL; static Evas_Object *_ews_border_mover_obj = NULL; static Evas_Point _ews_border_mover_off = {0, 0}; static void _elm_ews_border_usable_screen_geometry_get(int *x, int *y, int *w, int *h) { Ecore_Evas *ee = ecore_evas_ews_ecore_evas_get(); ecore_evas_geometry_get(ee, NULL, NULL, w, h); if (x) *x = 0; if (y) *y = 0; // TODO: when add a shelf for iconified, subtract its area here. } static void _elm_ews_wm_border_del(void *data) { Evas_Object *deco = data; evas_object_del(deco); if (_ews_border_mover_obj == deco) { ELM_SAFE_FREE(_ews_border_mover, ecore_animator_del); _ews_border_mover_obj = NULL; } } static Evas_Object * _elm_ews_wm_border_find(const Ecore_Evas *ee) { return eina_hash_find(_ews_borders, &ee); } static Eina_Rectangle * _elm_ews_wm_border_geo_find(const Ecore_Evas *ee) { return eina_hash_find(_ews_borders_geo, &ee); } static void _elm_ews_border_geo_apply(Ecore_Evas *ee, Evas_Object *o) { int x, y, w, h; ecore_evas_geometry_get(ee, &x, &y, &w, &h); evas_object_geometry_set(o, x, y, w, h); } static void _elm_ews_border_focus_apply(Ecore_Evas *ee, Evas_Object *o) { const char *sig; if (ecore_evas_focus_get(ee)) sig = "elm,state,focus,on"; else sig = "elm,state,focus,off"; edje_object_signal_emit(o, sig, "elm"); } static void _elm_ews_border_stack_apply(Ecore_Evas *ee, Evas_Object *o) { Evas_Object *bs_o = ecore_evas_ews_backing_store_get(ee); evas_object_stack_below(o, bs_o); } static void _elm_ews_border_iconified_apply(Ecore_Evas *ee, Evas_Object *o) { const char *sig; if (ecore_evas_iconified_get(ee)) sig = "elm,state,iconified,on"; else sig = "elm,state,iconified,off"; edje_object_signal_emit(o, sig, "elm"); // TODO: add to some taskbar? and actually hide it? DBG("EWS does not implement iconified yet"); } static void _elm_ews_border_maximized_apply(Ecore_Evas *ee, Evas_Object *o) { int x, y, w, h; if (ecore_evas_maximized_get(ee)) { Eina_Rectangle *r; int ex, ey, ew, eh; edje_object_signal_emit(o, "elm,state,maximized,on", "elm"); edje_object_message_signal_process(o); ecore_evas_geometry_get(ee, &x, &y, &w, &h); r = _elm_ews_wm_border_geo_find(ee); if (!r) { r = malloc(sizeof(Eina_Rectangle)); eina_hash_add(_ews_borders_geo, &ee, r); } r->x = x; r->y = y; r->w = w; r->h = h; _elm_ews_border_usable_screen_geometry_get(&x, &y, &w, &h); edje_object_parts_extends_calc(o, &ex, &ey, &ew, &eh); x -= ex; y -= ey; w -= ew - r->w; h -= eh - r->h; } else { Eina_Rectangle *r = _elm_ews_wm_border_geo_find(ee); edje_object_signal_emit(o, "elm,state,maximized,off", "elm"); if (!r) ecore_evas_geometry_get(ee, &x, &y, &w, &h); else { x = r->x; y = r->y; w = r->w; h = r->h; } } ecore_evas_move_resize(ee, x, y, w, h); _elm_ews_border_geo_apply(ee, o); } static void _elm_ews_border_layer_apply(Ecore_Evas *ee, Evas_Object *o) { Evas_Object *bs_o = ecore_evas_ews_backing_store_get(ee); evas_object_layer_set(o, evas_object_layer_get(bs_o)); _elm_ews_border_stack_apply(ee, o); } static void _elm_ews_border_fullscreen_apply(Ecore_Evas *ee, Evas_Object *o) { const char *sig; if (ecore_evas_fullscreen_get(ee)) sig = "elm,state,fullscreen,on"; else sig = "elm,state,fullscreen,off"; edje_object_signal_emit(o, sig, "elm"); _elm_ews_border_geo_apply(ee, o); } static void _elm_ews_border_config_apply(Ecore_Evas *ee, Evas_Object *o, Elm_Theme *th) { const char *title, *name = NULL, *class = NULL, *style = NULL; const char *sig; if (ecore_evas_borderless_get(ee)) style = "borderless"; _elm_theme_set(th, o, "ews", "decoration", style ? style : "default", EINA_TRUE); if (ecore_evas_shaped_get(ee) || ecore_evas_alpha_get(ee) || ecore_evas_transparent_get(ee)) sig = "elm,state,alpha,on"; else sig = "elm,state,alpha,off"; edje_object_signal_emit(o, sig, "elm"); title = ecore_evas_title_get(ee); ecore_evas_name_class_get(ee, &name, &class); edje_object_part_text_escaped_set(o, "elm.text.title", title); edje_object_part_text_escaped_set(o, "elm.text.name", name); edje_object_part_text_escaped_set(o, "elm.text.class", class); _elm_ews_border_geo_apply(ee, o); _elm_ews_border_focus_apply(ee, o); _elm_ews_border_stack_apply(ee, o); _elm_ews_border_iconified_apply(ee, o); _elm_ews_border_maximized_apply(ee, o); _elm_ews_border_layer_apply(ee, o); _elm_ews_border_fullscreen_apply(ee, o); } static Eina_Bool _elm_ews_wm_border_theme_set(Ecore_Evas *ee, Evas_Object *o, Elm_Theme *th) { _elm_ews_border_config_apply(ee, o, th); return EINA_TRUE; } static void _elm_ews_border_sig_focus(void *data, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *source EINA_UNUSED) { Ecore_Evas *ee = data; ecore_evas_focus_set(ee, EINA_TRUE); } static void _elm_ews_border_sig_iconify(void *data, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *source EINA_UNUSED) { Ecore_Evas *ee = data; ecore_evas_iconified_set(ee, EINA_TRUE); } static void _elm_ews_border_sig_maximize(void *data, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *source EINA_UNUSED) { Ecore_Evas *ee = data; ecore_evas_maximized_set(ee, EINA_TRUE); } static void _elm_ews_border_sig_fullscreen(void *data, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *source EINA_UNUSED) { Ecore_Evas *ee = data; ecore_evas_fullscreen_set(ee, EINA_TRUE); } static void _elm_ews_border_sig_restore(void *data, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *source EINA_UNUSED) { Ecore_Evas *ee = data; ecore_evas_iconified_set(ee, EINA_FALSE); ecore_evas_maximized_set(ee, EINA_FALSE); ecore_evas_fullscreen_set(ee, EINA_FALSE); } static void _elm_ews_border_sig_close(void *data, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *source EINA_UNUSED) { Ecore_Evas *ee = data; ecore_evas_ews_delete_request(ee); } static void _elm_ews_border_sig_menu(void *data, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *source EINA_UNUSED) { // TODO: show some menu? ERR("EWS does not implement menu yet"); (void)data; } static Eina_Bool _elm_ews_border_mover(void *data) { Ecore_Evas *ee = data; Evas_Object *o = _elm_ews_wm_border_find(ee); int x, y; evas_pointer_output_xy_get(ecore_evas_ews_evas_get(), &x, &y); x -= _ews_border_mover_off.x; y -= _ews_border_mover_off.y; ecore_evas_move(ee, x, y); evas_object_move(o, x, y); return EINA_TRUE; } static void _elm_ews_border_sig_move_start(void *data, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *source EINA_UNUSED) { Ecore_Evas *ee = data; Evas_Object *bs_o = ecore_evas_ews_backing_store_get(ee); int x, y, ox, oy; ELM_SAFE_FREE(_ews_border_mover, ecore_animator_del); evas_pointer_output_xy_get(evas_object_evas_get(bs_o), &x, &y); evas_object_geometry_get(bs_o, &ox, &oy, NULL, NULL); _ews_border_mover_off.x = x - ox; _ews_border_mover_off.y = y - oy; _ews_border_mover_obj = bs_o; _ews_border_mover = ecore_evas_animator_add(bs_o, _elm_ews_border_mover, ee); } static void _elm_ews_border_sig_move_stop(void *data EINA_UNUSED, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *source EINA_UNUSED) { if (!_ews_border_mover) return; ELM_SAFE_FREE(_ews_border_mover, ecore_animator_del); _ews_border_mover_obj = NULL; } static Eina_Bool _elm_ews_wm_add_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = edje_object_add(ecore_evas_ews_evas_get()); Evas_Coord x, y, w, h, sw, sh; edje_object_signal_callback_add (o, "elm,action,focus", "elm", _elm_ews_border_sig_focus, ee); edje_object_signal_callback_add (o, "elm,action,iconify", "elm", _elm_ews_border_sig_iconify, ee); edje_object_signal_callback_add (o, "elm,action,maximize", "elm", _elm_ews_border_sig_maximize, ee); edje_object_signal_callback_add (o, "elm,action,fullscreen", "elm", _elm_ews_border_sig_fullscreen, ee); edje_object_signal_callback_add (o, "elm,action,restore", "elm", _elm_ews_border_sig_restore, ee); edje_object_signal_callback_add (o, "elm,action,close", "elm", _elm_ews_border_sig_close, ee); edje_object_signal_callback_add (o, "elm,action,menu", "elm", _elm_ews_border_sig_menu, ee); edje_object_signal_callback_add (o, "elm,action,move,start", "elm", _elm_ews_border_sig_move_start, ee); edje_object_signal_callback_add (o, "elm,action,move,stop", "elm", _elm_ews_border_sig_move_stop, ee); eina_hash_add(_ews_borders, &ee, o); _elm_ews_wm_border_theme_set(ee, o, NULL); ecore_evas_screen_geometry_get(ee, NULL, NULL, &sw, &sh); ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); x = (sw - w) / 2; y = (sh - h) / 2; ecore_evas_move(ee, x, y); ecore_evas_focus_set(ee, EINA_TRUE); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_del_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; eina_hash_del(_ews_borders, &ee, NULL); eina_hash_del(_ews_borders_geo, &ee, NULL); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_geo_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); _elm_ews_border_geo_apply(ee, o); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_show_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); evas_object_show(o); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_hide_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); evas_object_hide(o); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_focus_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); _elm_ews_border_focus_apply(ee, o); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_stack_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); _elm_ews_border_stack_apply(ee, o); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_iconified_change_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); _elm_ews_border_iconified_apply(ee, o); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_maximized_change_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); _elm_ews_border_maximized_apply(ee, o); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_layer_change_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); _elm_ews_border_layer_apply(ee, o); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_fullscreen_change_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); _elm_ews_border_fullscreen_apply(ee, o); return EINA_TRUE; } static Eina_Bool _elm_ews_wm_config_change_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Evas *ee = event_info; Evas_Object *o = _elm_ews_wm_border_find(ee); _elm_ews_border_config_apply(ee, o, NULL); return EINA_TRUE; } void _elm_ews_wm_rescale(Elm_Theme *th, Eina_Bool use_theme) { Eina_Iterator *it; Eina_Hash_Tuple *tp = NULL; if (!_ews_borders) return; it = eina_hash_iterator_tuple_new(_ews_borders); if (!use_theme) { EINA_ITERATOR_FOREACH(it, tp) _elm_ews_wm_border_theme_set(*(void**)tp->key, tp->data, NULL); if (_ews_bg) _elm_theme_set(NULL, _ews_bg, "ews", "background", "default", EINA_TRUE); } else { EINA_ITERATOR_FOREACH(it, tp) _elm_ews_wm_border_theme_set(*(void**)tp->key, tp->data, th); if (_ews_bg) _elm_theme_set(th, _ews_bg, "ews", "background", "default", EINA_TRUE); } eina_iterator_free(it); } int _elm_ews_wm_init(void) { Evas *e; Evas_Object *o; if ((!_elm_config->engine) || (!(!strcmp(_elm_config->engine, ELM_EWS)))) { _ews_used = EINA_FALSE; return EINA_TRUE; } e = ecore_evas_ews_evas_get(); if (!e) return EINA_FALSE; o = edje_object_add(e); if (!o) return EINA_FALSE; if (_elm_theme_set(NULL, o, "ews", "background", "default", EINA_TRUE) == EFL_UI_THEME_APPLY_ERROR_GENERIC) { ERR("Could not set background theme, fallback to rectangle"); evas_object_del(o); _ews_bg = o = NULL; } else _ews_bg = o; ecore_evas_ews_background_set(o); #define ADD_EH(ev, cb) \ _ews_ev_handlers = eina_list_append \ (_ews_ev_handlers, ecore_event_handler_add(ev, cb, NULL)) ADD_EH(ECORE_EVAS_EWS_EVENT_ADD, _elm_ews_wm_add_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_DEL, _elm_ews_wm_del_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_RESIZE, _elm_ews_wm_geo_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_MOVE, _elm_ews_wm_geo_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_SHOW, _elm_ews_wm_show_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_HIDE, _elm_ews_wm_hide_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_FOCUS, _elm_ews_wm_focus_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_UNFOCUS, _elm_ews_wm_focus_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_RAISE, _elm_ews_wm_stack_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_LOWER, _elm_ews_wm_stack_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE, _elm_ews_wm_iconified_change_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE, _elm_ews_wm_maximized_change_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_LAYER_CHANGE, _elm_ews_wm_layer_change_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE, _elm_ews_wm_fullscreen_change_cb); ADD_EH(ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE, _elm_ews_wm_config_change_cb); #undef ADD_EH if (!_ews_borders) _ews_borders = eina_hash_pointer_new(_elm_ews_wm_border_del); if (!_ews_borders_geo) _ews_borders_geo = eina_hash_pointer_new(free); _ews_used = EINA_TRUE; return EINA_TRUE; } void _elm_ews_wm_shutdown(void) { Ecore_Event_Handler *eh; ELM_SAFE_FREE(_ews_border_mover, ecore_animator_del); _ews_border_mover_obj = NULL; EINA_LIST_FREE(_ews_ev_handlers, eh) ecore_event_handler_del(eh); ELM_SAFE_FREE(_ews_borders, eina_hash_free); ELM_SAFE_FREE(_ews_borders_geo, ecore_animator_del); _ews_bg = NULL; }