From a9042dbca637757a1521a153cec3160f0bd2f9b3 Mon Sep 17 00:00:00 2001 From: Sung-Jin Park Date: Wed, 27 Mar 2019 13:57:32 +0900 Subject: [PATCH] enlightenment_headless : temporal jobs Change-Id: Ide3962cc65bc72c9531265da0ceecd838e93e702 Signed-off-by: Sung-Jin Park --- packaging/enlightenment.spec | 1 + src/bin/Makefile.mk | 70 + src/bin/e.h | 17 +- src/bin/e_client_common.c | 7064 ++++++++++++++++++++++++++++++++ src/bin/e_client_common.h | 1336 ++++++ src/bin/e_includes.h | 2 + src/bin/e_includes_iot.h | 108 + src/bin/e_info_server_common.c | 0 src/bin/e_iot.h | 7 + src/bin/e_main.c | 40 + src/bin/e_main_iot.c | 1319 ++++++ 11 files changed, 9961 insertions(+), 3 deletions(-) create mode 100644 src/bin/e_client_common.c create mode 100644 src/bin/e_client_common.h create mode 100644 src/bin/e_includes_iot.h create mode 100644 src/bin/e_info_server_common.c create mode 100644 src/bin/e_iot.h create mode 100644 src/bin/e_main_iot.c diff --git a/packaging/enlightenment.spec b/packaging/enlightenment.spec index 565ece77fa..ff8f2e5398 100644 --- a/packaging/enlightenment.spec +++ b/packaging/enlightenment.spec @@ -82,6 +82,7 @@ export LDFLAGS+=" -pie " TIZEN_REL_VERSION="%{release}-%{TIZEN_REL_VERSION}" \ --enable-function-trace \ --enable-wayland \ + --enable-iot \ --enable-quick-init make %{?_smp_mflags} diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index fac7082bd3..f17259b578 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -21,6 +21,7 @@ E_CPPFLAGS = \ bin_PROGRAMS = \ src/bin/enlightenment \ +src/bin/enlightenment_iot \ src/bin/enlightenment_info #internal_bindir = $(libdir)/enlightenment/utils @@ -311,6 +312,75 @@ src_bin_enlightenment_info_CPPFLAGS = $(E_CPPFLAGS) @E_INFO_CFLAGS@ src_bin_enlightenment_info_LDFLAGS = -pie src_bin_enlightenment_info_CPPFLAGS += -fPIE +ENLIGHTENMENTIOTHEADERS = \ +src/bin/e_iot.h \ +src/bin/e_client.h \ +src/bin/e_comp_cfdata.h \ +src/bin/e_config_data.h \ +src/bin/e_config.h \ +src/bin/e_error.h \ +src/bin/e.h \ +src/bin/e_includes_iot.h \ +src/bin/e_info_server_common.h \ +src/bin/e_env.h \ +src/bin/e_log.h \ +src/bin/e_privilege.h \ +src/bin/e_main.h \ +src/bin/e_module.h \ +src/bin/e_object.h \ +src/bin/e_path.h \ +src/bin/e_prefix.h \ +src/bin/e_signals.h \ +src/bin/e_user.h \ +src/bin/e_info_protocol.h + +enlightenmentiotsrc = \ +src/bin/e_client.c \ +src/bin/e_comp_cfdata.c \ +src/bin/e_config.c \ +src/bin/e_config_data.c \ +src/bin/e_env.c \ +src/bin/e_error.c \ +src/bin/e_info_server_common.c \ +src/bin/e_log.c \ +src/bin/e_module.c \ +src/bin/e_object.c \ +src/bin/e_path.c \ +src/bin/e_prefix.c \ +src/bin/e_signals.c \ +src/bin/e_user.c \ +src/bin/e_info_protocol.c \ +$(ENLIGHTENMENTIOTHEADERS) + +enlightenmentiotsrc += \ +src/bin/e_process.c \ +src/bin/e_privilege.c \ +src/bin/e_security.c \ +src/bin/e_keyrouter_events.c \ +src/bin/e_keyrouter_list.c \ +src/bin/e_keyrouter_conf.c \ +src/bin/e_keyrouter_wl.c \ +src/bin/e_keyrouter.c \ +src/bin/e_input_private.h \ +src/bin/e_input.c \ +src/bin/e_input_inputs.c \ +src/bin/e_input_device.c \ +src/bin/e_input_evdev.c \ +src/bin/e_devicemgr.c \ +src/bin/e_devicemgr_conf.c \ +src/bin/e_devicemgr_block.c \ +src/bin/e_devicemgr_input.c \ +src/bin/e_devicemgr_inputgen.c \ +src/bin/e_devicemgr_wl.c + +src_bin_enlightenment_iot_SOURCES = \ +src/bin/e_main_iot.c \ +$(enlightenmentiotsrc) +src_bin_enlightenment_iot_LDADD = #@E_IOT_LIBS@ +src_bin_enlightenment_iot_CPPFLAGS = $(E_CPPFLAGS) #@E_IOT_CFLAGS@ +src_bin_enlightenment_iot_LDFLAGS = -pie +src_bin_enlightenment_iot_CPPFLAGS += -fPIE + # HACK! why install-data-hook? install-exec-hook is run after bin_PROGRAMS # and before internal_bin_PROGRAMS are installed. install-data-hook is # run after both diff --git a/src/bin/e.h b/src/bin/e.h index ba77ecc8ca..d439d76ec8 100644 --- a/src/bin/e.h +++ b/src/bin/e.h @@ -123,10 +123,12 @@ void *alloca (size_t); # include # include # include -# include -# include # include -# include +# ifndef HAVE_IOT +# include +# include +# include +# endif # include # include # include @@ -294,10 +296,12 @@ typedef struct _E_Rect E_Rect; } \ } +#ifndef HAVE_IOT #define E_WEIGHT evas_object_size_hint_weight_set #define E_ALIGN evas_object_size_hint_align_set #define E_EXPAND(X) E_WEIGHT((X), EVAS_HINT_EXPAND, EVAS_HINT_EXPAND) #define E_FILL(X) E_ALIGN((X), EVAS_HINT_FILL, EVAS_HINT_FILL) +#endif # define E_REMOTE_OPTIONS 1 # define E_REMOTE_OUT 2 @@ -316,10 +320,17 @@ typedef struct _E_Rect E_Rect; #define YOLO EINA_DEPRECATED #endif +#ifndef HAVE_IOT # define E_TYPEDEFS 1 # include "e_includes.h" # undef E_TYPEDEFS # include "e_includes.h" +#else +# define E_TYPEDEFS 1 +# include "e_includes_iot.h" +# undef E_TYPEDEFS +# include "e_includes_iot.h" +#endif E_API double e_main_ts(const char *str); E_API double e_main_ts_begin(const char *str); diff --git a/src/bin/e_client_common.c b/src/bin/e_client_common.c new file mode 100644 index 0000000000..5faf6df933 --- /dev/null +++ b/src/bin/e_client_common.c @@ -0,0 +1,7064 @@ +#include "e.h" + +static int _e_client_hooks_delete = 0; +static int _e_client_hooks_walking = 0; + +static int _e_client_intercept_hooks_delete = 0; +static int _e_client_intercept_hooks_walking = 0; + +E_API int E_EVENT_CLIENT_ADD = -1; +E_API int E_EVENT_CLIENT_REMOVE = -1; +E_API int E_EVENT_CLIENT_ZONE_SET = -1; +E_API int E_EVENT_CLIENT_DESK_SET = -1; +E_API int E_EVENT_CLIENT_RESIZE = -1; +E_API int E_EVENT_CLIENT_MOVE = -1; +E_API int E_EVENT_CLIENT_SHOW = -1; +E_API int E_EVENT_CLIENT_HIDE = -1; +E_API int E_EVENT_CLIENT_ICONIFY = -1; +E_API int E_EVENT_CLIENT_UNICONIFY = -1; +E_API int E_EVENT_CLIENT_STACK = -1; +E_API int E_EVENT_CLIENT_FOCUS_IN = -1; +E_API int E_EVENT_CLIENT_FOCUS_OUT = -1; +E_API int E_EVENT_CLIENT_PROPERTY = -1; +E_API int E_EVENT_CLIENT_FULLSCREEN = -1; +E_API int E_EVENT_CLIENT_UNFULLSCREEN = -1; +#ifdef _F_ZONE_WINDOW_ROTATION_ +E_API int E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN = -1; +E_API int E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL = -1; +E_API int E_EVENT_CLIENT_ROTATION_CHANGE_END = -1; +#endif +E_API int E_EVENT_CLIENT_VISIBILITY_CHANGE = -1; +E_API int E_EVENT_CLIENT_BUFFER_CHANGE = -1; + +static Eina_Hash *clients_hash[E_PIXMAP_TYPE_MAX] = {NULL}; // pixmap->client + +static unsigned int focus_track_frozen = 0; + +static int warp_to = 0; +static int warp_to_x = 0; +static int warp_to_y = 0; +static int warp_x[2] = {0}; //{cur,prev} +static int warp_y[2] = {0}; //{cur,prev} +static Ecore_Timer *warp_timer = NULL; + +static E_Client *focused = NULL; +static E_Client *warp_client = NULL; +static E_Client *ecmove = NULL; +static E_Client *ecresize = NULL; +static E_Client *action_client = NULL; +static E_Drag *client_drag = NULL; + +static Eina_List *focus_stack = NULL; +static Eina_List *defer_focus_stack = NULL; + +static Eina_Bool comp_grabbed = EINA_FALSE; + +static Eina_List *handlers = NULL; +static Eina_List *hooks = NULL; + +static Ecore_Event_Handler *action_handler_key = NULL; +static Ecore_Event_Handler *action_handler_mouse = NULL; +static Ecore_Timer *action_timer = NULL; +static Eina_Rectangle action_orig = {0, 0, 0, 0}; + +static E_Client_Layout_Cb _e_client_layout_cb = NULL; + +static Eina_Bool _e_calc_visibility = EINA_FALSE; +static Eina_Bool _e_visibility_changed = EINA_FALSE; + +EINTERN void e_client_focused_set(E_Client *ec); + +static Eina_Inlist *_e_client_hooks[] = +{ + [E_CLIENT_HOOK_EVAL_PRE_FETCH] = NULL, + [E_CLIENT_HOOK_EVAL_FETCH] = NULL, + [E_CLIENT_HOOK_EVAL_PRE_POST_FETCH] = NULL, + [E_CLIENT_HOOK_EVAL_POST_FETCH] = NULL, + [E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN] = NULL, + [E_CLIENT_HOOK_EVAL_POST_FRAME_ASSIGN] = NULL, + [E_CLIENT_HOOK_EVAL_PRE_NEW_CLIENT] = NULL, + [E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT] = NULL, + [E_CLIENT_HOOK_EVAL_END] = NULL, + [E_CLIENT_HOOK_FOCUS_SET] = NULL, + [E_CLIENT_HOOK_FOCUS_UNSET] = NULL, + [E_CLIENT_HOOK_NEW_CLIENT] = NULL, + [E_CLIENT_HOOK_DESK_SET] = NULL, + [E_CLIENT_HOOK_MOVE_BEGIN] = NULL, + [E_CLIENT_HOOK_MOVE_UPDATE] = NULL, + [E_CLIENT_HOOK_MOVE_END] = NULL, + [E_CLIENT_HOOK_RESIZE_BEGIN] = NULL, + [E_CLIENT_HOOK_RESIZE_UPDATE] = NULL, + [E_CLIENT_HOOK_RESIZE_END] = NULL, + [E_CLIENT_HOOK_FULLSCREEN_PRE] = NULL, + [E_CLIENT_HOOK_DEL] = NULL, + [E_CLIENT_HOOK_UNREDIRECT] = NULL, + [E_CLIENT_HOOK_REDIRECT] = NULL, +#ifdef _F_E_CLIENT_NEW_CLIENT_POST_HOOK_ + [E_CLIENT_HOOK_NEW_CLIENT_POST] = NULL, +#endif + [E_CLIENT_HOOK_EVAL_VISIBILITY] = NULL, + [E_CLIENT_HOOK_ICONIFY] = NULL, + [E_CLIENT_HOOK_UNICONIFY] = NULL, + [E_CLIENT_HOOK_AUX_HINT_CHANGE] = NULL, + [E_CLIENT_HOOK_WINDOW_ROLE_CHANGE] = NULL, + [E_CLIENT_HOOK_CAL_VISIBILITY_DISPLAY_OFF] = NULL, + [E_CLIENT_HOOK_TRANSFORM_CHANGE] = NULL, +}; + +static Eina_Inlist *_e_client_intercept_hooks[] = +{ + [E_CLIENT_INTERCEPT_HOOK_FOCUS_REVERT] = NULL, +}; + +/////////////////////////////////////////// + +static Eina_Bool +_e_client_cb_config_mode(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED) +{ + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_client_cb_pointer_warp(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Pointer_Warp *ev) +{ + if (ecmove) + evas_object_move(ecmove->frame, ecmove->x + (ev->curr.x - ev->prev.x), ecmove->y + (ev->curr.y - ev->prev.y)); + return ECORE_CALLBACK_RENEW; +} + + +static Eina_Bool +_e_client_cb_desk_window_profile_change(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Desk_Window_Profile_Change *ev EINA_UNUSED) +{ + const Eina_List *l; + E_Client *ec; + + EINA_LIST_FOREACH(e_comp->clients, l, ec) + { + if (e_object_is_del(E_OBJECT(ec))) continue; + ec->e.fetch.profile = 1; + EC_CHANGED(ec); + } + return ECORE_CALLBACK_RENEW; +} + +static void +_e_client_cb_drag_finished(E_Drag *drag, int dropped EINA_UNUSED) +{ + E_Client *ec; + + ec = drag->data; + UNREFD(ec, 1); + e_object_unref(E_OBJECT(ec)); + client_drag = NULL; +} + +static void +_e_client_desk_window_profile_wait_desk_delfn(void *data, void *obj) +{ + E_Client *ec = data; + E_Desk *desk = obj, *new_desk; + const char *p; + int i; + + if (e_object_is_del(E_OBJECT(ec))) return; + + ec->e.state.profile.wait_desk_delfn = NULL; + eina_stringshare_replace(&ec->e.state.profile.wait, NULL); + if (ec->e.state.profile.wait_desk) + e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk)); + ec->e.state.profile.wait_desk = NULL; + ec->e.state.profile.wait_for_done = 0; + + if (!ec->e.state.profile.use) return; + + new_desk = e_comp_desk_window_profile_get(desk->window_profile); + if (new_desk) + e_client_desk_set(ec, new_desk); + else + { + for (i = 0; i < ec->e.state.profile.num; i++) + { + p = ec->e.state.profile.available_list[i]; + new_desk = e_comp_desk_window_profile_get(p); + if (new_desk) + { + e_client_desk_set(ec, new_desk); + break; + } + } + } +} +//////////////////////////////////////////////// + + +static Eina_Bool +_e_client_pointer_warp_to_center_timer(void *data EINA_UNUSED) +{ + if (warp_to && warp_client) + { + int x, y; + double spd; + + e_input_device_pointer_xy_get(NULL, &x, &y); + /* move hasn't happened yet */ + if ((x == warp_x[1]) && (y == warp_y[1])) + return EINA_TRUE; + if ((abs(x - warp_x[0]) > 5) || (abs(y - warp_y[0]) > 5)) + { + /* User moved the mouse, so stop warping */ + warp_to = 0; + goto cleanup; + } + + spd = 0.5; + warp_x[1] = x = warp_x[0]; + warp_y[1] = y = warp_y[0]; + warp_x[0] = (x * (1.0 - spd)) + (warp_to_x * spd); + warp_y[0] = (y * (1.0 - spd)) + (warp_to_y * spd); + if ((warp_x[0] == x) && (warp_y[0] == y)) + { + warp_x[0] = warp_to_x; + warp_y[0] = warp_to_y; + warp_to = 0; + goto cleanup; + } + e_input_device_pointer_warp(NULL, warp_x[0], warp_y[0]); + return ECORE_CALLBACK_RENEW; + } +cleanup: + E_FREE_FUNC(warp_timer, ecore_timer_del); + if (warp_client) + { + warp_x[0] = warp_x[1] = warp_y[0] = warp_y[1] = -1; + if (warp_client->modal) + { + warp_client = NULL; + return ECORE_CALLBACK_CANCEL; + } + e_focus_event_mouse_in(warp_client); + if (warp_client->iconic) + { + if (!warp_client->lock_user_iconify) + e_client_uniconify(warp_client); + } + if (warp_client->shaded) + { + if (!warp_client->lock_user_shade) + e_client_unshade(warp_client, warp_client->shade_dir); + } + + if (!warp_client->lock_focus_out) + { + ELOGF("FOCUS", "focus set | pointer_warp_to_center", warp_client); + evas_object_focus_set(warp_client->frame, 1); + e_client_focus_latest_set(warp_client); + } + warp_client = NULL; + } + return ECORE_CALLBACK_CANCEL; +} + +//////////////////////////////////////////////// + +static void +_e_client_hooks_clean(void) +{ + Eina_Inlist *l; + E_Client_Hook *ch; + unsigned int x; + + for (x = 0; x < E_CLIENT_HOOK_LAST; x++) + EINA_INLIST_FOREACH_SAFE(_e_client_hooks[x], l, ch) + { + if (!ch->delete_me) continue; + _e_client_hooks[x] = eina_inlist_remove(_e_client_hooks[x], EINA_INLIST_GET(ch)); + free(ch); + } +} + +static Eina_Bool +_e_client_hook_call(E_Client_Hook_Point hookpoint, E_Client *ec) +{ + E_Client_Hook *ch; + + e_object_ref(E_OBJECT(ec)); + _e_client_hooks_walking++; + EINA_INLIST_FOREACH(_e_client_hooks[hookpoint], ch) + { + if (ch->delete_me) continue; + ch->func(ch->data, ec); + if ((hookpoint != E_CLIENT_HOOK_DEL) && + (hookpoint != E_CLIENT_HOOK_MOVE_END) && + (hookpoint != E_CLIENT_HOOK_RESIZE_END) && + (hookpoint != E_CLIENT_HOOK_FOCUS_UNSET) && + e_object_is_del(E_OBJECT(ec))) + break; + } + _e_client_hooks_walking--; + if ((_e_client_hooks_walking == 0) && (_e_client_hooks_delete > 0)) + _e_client_hooks_clean(); + return !!e_object_unref(E_OBJECT(ec)); +} + +/////////////////////////////////////////// + +static void +_e_client_intercept_hooks_clean(void) +{ + Eina_Inlist *l; + E_Client_Intercept_Hook *ch; + unsigned int x; + + for (x = 0; x < E_CLIENT_INTERCEPT_HOOK_LAST; x++) + EINA_INLIST_FOREACH_SAFE(_e_client_intercept_hooks[x], l, ch) + { + if (!ch->delete_me) continue; + _e_client_intercept_hooks[x] = + eina_inlist_remove(_e_client_intercept_hooks[x], EINA_INLIST_GET(ch)); + free(ch); + } +} + +static Eina_Bool +_e_client_intercept_hook_call(E_Client_Intercept_Hook_Point hookpoint, E_Client *ec) +{ + E_Client_Intercept_Hook *ch; + Eina_Bool ret = EINA_TRUE; + + if (e_object_is_del(E_OBJECT(ec))) + { + if (hookpoint != E_CLIENT_INTERCEPT_HOOK_FOCUS_REVERT) + { + return ret; + } + } + + e_object_ref(E_OBJECT(ec)); + _e_client_intercept_hooks_walking++; + EINA_INLIST_FOREACH(_e_client_intercept_hooks[hookpoint], ch) + { + if (ch->delete_me) continue; + if (!(ch->func(ch->data, ec))) + { + ret = EINA_FALSE; + break; + } + } + _e_client_intercept_hooks_walking--; + if ((_e_client_intercept_hooks_walking == 0) && + (_e_client_intercept_hooks_delete > 0)) + _e_client_intercept_hooks_clean(); + + e_object_unref(E_OBJECT(ec)); + return ret; +} + +static void +_e_client_event_simple_free(void *d EINA_UNUSED, E_Event_Client *ev) +{ + UNREFD(ev->ec, 3); + e_object_unref(E_OBJECT(ev->ec)); + free(ev); +} + +static void +_e_client_event_simple(E_Client *ec, int type) +{ + E_Event_Client *ev; + + ev = E_NEW(E_Event_Client, 1); + if (!ev) return; + ev->ec = ec; + REFD(ec, 3); + e_object_ref(E_OBJECT(ec)); + ecore_event_add(type, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL); +} + +static void +_e_client_event_add(E_Client *ec) +{ + if (ec->reg_ev.add) + return; + + ec->reg_ev.add = EINA_TRUE; + _e_client_event_simple(ec, E_EVENT_CLIENT_ADD); +} + +static void +_e_client_event_remove(E_Client *ec) +{ + if (!ec->reg_ev.add) + return; + + ec->reg_ev.add = EINA_FALSE; + _e_client_event_simple(ec, E_EVENT_CLIENT_REMOVE); +} + +static void +_e_client_event_show(E_Client *ec) +{ + if (ec->reg_ev.show) + return; + + ec->reg_ev.show = EINA_TRUE; + _e_client_event_simple(ec, E_EVENT_CLIENT_SHOW); +} + +static void +_e_client_event_hide(E_Client *ec) +{ + if (!ec->reg_ev.show) + return; + + ec->reg_ev.show = EINA_FALSE; + _e_client_event_simple(ec, E_EVENT_CLIENT_HIDE); +} + +static void +_e_client_event_property(E_Client *ec, int prop) +{ + E_Event_Client_Property *ev; + + ev = E_NEW(E_Event_Client_Property, 1); + if (!ev) return; + ev->ec = ec; + ev->property = prop; + REFD(ec, 33); + e_object_ref(E_OBJECT(ec)); + ecore_event_add(E_EVENT_CLIENT_PROPERTY, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL); +} + +static void +_e_client_event_desk_set_free(void *d EINA_UNUSED, E_Event_Client_Desk_Set *ev) +{ + UNREFD(ev->ec, 4); + e_object_unref(E_OBJECT(ev->ec)); + e_object_unref(E_OBJECT(ev->desk)); + free(ev); +} + +static void +_e_client_event_zone_set_free(void *d EINA_UNUSED, E_Event_Client_Zone_Set *ev) +{ + UNREFD(ev->ec, 5); + e_object_unref(E_OBJECT(ev->ec)); + e_object_unref(E_OBJECT(ev->zone)); + free(ev); +} + +//////////////////////////////////////////////// + +static int +_e_client_action_input_win_del(void) +{ + if (!comp_grabbed) return 0; + + e_comp_ungrab_input(1, 1); + comp_grabbed = 0; + return 1; +} + +static void +_e_client_action_finish(void) +{ + if (comp_grabbed) + _e_client_action_input_win_del(); + + if (action_handler_key && action_client) + evas_object_freeze_events_set(action_client->frame, 0); + E_FREE_FUNC(action_timer, ecore_timer_del); + E_FREE_FUNC(action_handler_key, ecore_event_handler_del); + E_FREE_FUNC(action_handler_mouse, ecore_event_handler_del); + if (action_client) + { + action_client->keyboard_resizing = 0; + //if (action_client->internal_elm_win) + // ecore_event_window_ignore_events(elm_win_window_id_get(action_client->internal_elm_win), 0); + } + action_client = NULL; +} + +static void +_e_client_transform_point_transform(int cx, int cy, double angle, int x, int y, int *tx, int *ty) +{ + double s = sin(angle * M_PI / 180); + double c = cos(angle * M_PI / 180); + int rx, ry; + + x -= cx; + y -= cy; + + rx = x * c + y * s; + ry = - x * s + y * c; + + rx += cx; + ry += cy; + + *tx = rx; + *ty = ry; +} + +static void +_e_client_transform_geometry_save(E_Client *ec, Evas_Map *map) +{ + int i; + + if (!map) return; + + for (i = 0; i < 4; i ++) + { + evas_map_point_precise_coord_get(map, i, + &ec->transform.saved[i].x, + &ec->transform.saved[i].y, + &ec->transform.saved[i].z); + } +} + +static void +_e_client_transform_resize(E_Client *ec) +{ + Evas_Map *map; + int cx, cy; + double dx = 0, dy = 0; + double px[4], py[4]; + int pw, ph; + int i; + + if (!ec->transformed) return; + + if (!e_pixmap_size_get(ec->pixmap, &pw, &ph)) + { + pw = ec->client.w; + ph = ec->client.h; + } + + cx = ec->client.x + pw / 2; + cy = ec->client.y + ph / 2; + + /* step 1: Rotate resized object and get map points */ + map = evas_map_new(4); + evas_map_util_points_populate_from_geometry(map, + ec->client.x, ec->client.y, + pw, ph, + 0); + evas_map_util_rotate(map, ec->transform.angle, cx, cy); + evas_map_util_zoom(map, ec->transform.zoom, ec->transform.zoom, cx, cy); + + for (i = 0; i < 4; i++) + evas_map_point_precise_coord_get(map, i, &px[i], &py[i], NULL); + + evas_map_free(map); + + /* step 2: get adjusted values to keep up fixed position according + * to resize mode */ + switch (ec->resize_mode) + { + case E_POINTER_RESIZE_R: + case E_POINTER_RESIZE_BR: + dx = ec->transform.saved[0].x - px[0]; + dy = ec->transform.saved[0].y - py[0]; + break; + case E_POINTER_RESIZE_BL: + case E_POINTER_RESIZE_B: + dx = ec->transform.saved[1].x - px[1]; + dy = ec->transform.saved[1].y - py[1]; + break; + case E_POINTER_RESIZE_TL: + case E_POINTER_RESIZE_L: + dx = ec->transform.saved[2].x - px[2]; + dy = ec->transform.saved[2].y - py[2]; + break; + case E_POINTER_RESIZE_T: + case E_POINTER_RESIZE_TR: + dx = ec->transform.saved[3].x - px[3]; + dy = ec->transform.saved[3].y - py[3]; + break; + default: + break; + } + + ec->transform.adjusted.x = dx; + ec->transform.adjusted.y = dy; + + /* step 3: set each points of the quadrangle */ + map = evas_map_new(4); + evas_map_util_points_populate_from_object_full(map, ec->frame, 0); + + for (i = 0; i < 4; i++) + evas_map_point_precise_coord_set(map, i, px[i] + dx, py[i] + dy, 0); + + evas_object_map_set(ec->frame, map); + evas_object_map_enable_set(ec->frame, EINA_TRUE); + evas_map_free(map); +} + +static void +_e_client_transform_resize_handle(E_Client *ec) +{ + + int new_x, new_y, new_w, new_h; + int org_w, org_h; + int button_id; + int cx, cy; + Evas_Point current, moveinfo; + + if (e_object_is_del(E_OBJECT(ec))) return; + if (e_client_util_ignored_get(ec)) return; + if (!ec->transformed) return; + + button_id = ec->moveinfo.down.button; + + org_w = ec->mouse.last_down[button_id - 1].w; + org_h = ec->mouse.last_down[button_id - 1].h; + + new_w = ec->client.w; + new_h = ec->client.h; + new_x = ec->client.x; + new_y = ec->client.y; + + /* step 1: get center coordinate its' based on original object geometry*/ + cx = ec->client.x + org_w / 2; + cy = ec->client.y + org_h / 2; + + /* step 2: transform coordinates of mouse position + * subtract adjusted value from mouse position is needed */ + current.x = ec->mouse.current.mx - ec->transform.adjusted.x; + current.y = ec->mouse.current.my - ec->transform.adjusted.y; + moveinfo.x = ec->moveinfo.down.mx - ec->transform.adjusted.x; + moveinfo.y = ec->moveinfo.down.my - ec->transform.adjusted.y; + + _e_client_transform_point_transform(cx, cy, ec->transform.angle, + current.x, current.y, + ¤t.x, ¤t.y); + _e_client_transform_point_transform(cx, cy, ec->transform.angle, + moveinfo.x, moveinfo.y, + &moveinfo.x, &moveinfo.y); + + /* step 3: calculate new size */ + if ((ec->resize_mode == E_POINTER_RESIZE_TR) || + (ec->resize_mode == E_POINTER_RESIZE_R) || + (ec->resize_mode == E_POINTER_RESIZE_BR)) + { + if ((button_id >= 1) && (button_id <= 3)) + new_w = org_w + (current.x - moveinfo.x); + else + new_w = ec->moveinfo.down.w + (current.x - moveinfo.x); + } + else if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_L) || + (ec->resize_mode == E_POINTER_RESIZE_BL)) + { + if ((button_id >= 1) && (button_id <= 3)) + new_w = org_w - (current.x - moveinfo.x); + else + new_w = ec->moveinfo.down.w - (current.x - moveinfo.x); + } + + if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_T) || + (ec->resize_mode == E_POINTER_RESIZE_TR)) + { + if ((button_id >= 1) && (button_id <= 3)) + new_h = org_h - (current.y - moveinfo.y); + else + new_h = ec->moveinfo.down.h - (current.y - moveinfo.y); + } + else if ((ec->resize_mode == E_POINTER_RESIZE_BL) || + (ec->resize_mode == E_POINTER_RESIZE_B) || + (ec->resize_mode == E_POINTER_RESIZE_BR)) + { + if ((button_id >= 1) && (button_id <= 3)) + new_h = org_h + (current.y - moveinfo.y); + else + new_h = ec->moveinfo.down.h + (current.y - moveinfo.y); + } + + new_w = MIN(new_w, ec->zone->w); + new_h = MIN(new_h, ec->zone->h); + + /* step 4: move to new position */ + if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_L) || + (ec->resize_mode == E_POINTER_RESIZE_BL)) + new_x += (new_w - org_w); + if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_T) || + (ec->resize_mode == E_POINTER_RESIZE_TR)) + new_y += (new_h - org_h); + + /* step 5: set geometry to new value */ + evas_object_geometry_set(ec->frame, new_x, new_y, new_w, new_h); +} + +void +_e_client_transform_resize_begin(E_Client *ec) +{ + if (!ec->transformed) return; + + _e_client_transform_geometry_save(ec, (Evas_Map *)evas_object_map_get(ec->frame)); +} + +void +_e_client_transform_resize_end(E_Client *ec) +{ + Evas_Map *map; + int new_x = 0, new_y = 0; + int cx, cy, pw, ph; + + if (!ec->transformed) return; + + map = (Evas_Map*)evas_object_map_get(ec->frame); + if (!map) return; + + if (!e_pixmap_size_get(ec->pixmap, &pw, &ph)) + { + pw = ec->client.w; + ph = ec->client.h; + } + + cx = ec->client.x + pw / 2 + ec->transform.adjusted.x; + cy = ec->client.y + ph / 2 + ec->transform.adjusted.y; + + if (ec->transform.zoom != 1.0) + { + Evas_Map *tmp_map; + + tmp_map = evas_map_dup(map); + evas_map_util_zoom(tmp_map, + 1 / ec->transform.zoom, + 1 / ec->transform.zoom, + cx, cy); + + _e_client_transform_geometry_save(ec, tmp_map); + evas_map_free(tmp_map); + } + else + { + _e_client_transform_geometry_save(ec, map); + } + + /* move original object to adjusted position after resizing */ + _e_client_transform_point_transform(cx, cy, + ec->transform.angle, + ec->transform.saved[0].x, + ec->transform.saved[0].y, + &new_x, &new_y); + e_client_util_move_without_frame(ec, new_x, new_y); + evas_map_util_object_move_sync_set(map, EINA_TRUE); +} + +static void +_e_client_transform_move_end(E_Client *ec) +{ + + int i; + double dx, dy, px, py; + Evas_Map *map; + + if (!ec->transformed) return; + + map = (Evas_Map*)evas_object_map_get(ec->frame); + if (!map) return; + + if (ec->transform.zoom != 1.0) + { + evas_map_point_precise_coord_get(map, 0, &px, &py, NULL); + + dx = px - ec->transform.saved[0].x; + dy = py - ec->transform.saved[0].y; + + for (i = 0; i < 4; i++) + { + ec->transform.saved[i].x += dx; + ec->transform.saved[i].y += dy; + } + } + else + _e_client_transform_geometry_save(ec, map); +} + +static E_Client * +_e_client_check_fully_contain_by_above(E_Client *ec, Eina_Bool check_layer) +{ + E_Client *above = NULL; + E_Zone *_z = NULL; + int x = 0, y = 0, w = 0, h = 0; + + if (!ec) return NULL; + + x = ec->x; + y = ec->y; + w = ec->w; + h = ec->h; + + if (ec->zone) + { + _z = ec->zone; + E_RECTS_CLIP_TO_RECT(x, y, w, h, _z->x, _z->y, _z->w, _z->h); + } + + above = e_client_above_get(ec); + while (above) + { + if ((check_layer) && + (above->layer <= ec->layer)) + { + above = e_client_above_get(above); + continue; + } + + if ((!e_object_is_del(E_OBJECT(above))) && + (!e_client_util_ignored_get(above)) && + (above->visible) && + (!above->iconic || e_policy_visibility_client_is_uniconic(above)) && + (!above->bg_state) && + (above->frame) && + (above->icccm.accepts_focus || above->icccm.take_focus)) + { + if (E_CONTAINS(above->x, above->y, above->w, above->h, x, y, w, h)) + break; + } + above = e_client_above_get(above); + } + + return above; +} + +static Eina_Bool +_e_client_focus_can_take(E_Client *ec) +{ + if (!ec) return EINA_FALSE; + if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE; + if (e_client_util_ignored_get(ec)) return EINA_FALSE; + if (!(ec->icccm.accepts_focus || ec->icccm.take_focus)) return EINA_FALSE; + if (ec->lock_focus_in || ec->lock_focus_out) return EINA_FALSE; + if (!ec->visible) return EINA_FALSE; + if (ec->bg_state) return EINA_FALSE; + if (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED) + { + if (ec->iconic && e_policy_visibility_client_is_iconic(ec)) + return EINA_FALSE; + if (ec->visibility.obscured == E_VISIBILITY_UNKNOWN) + return EINA_FALSE; + } + if (_e_client_check_fully_contain_by_above(ec, EINA_FALSE)) return EINA_FALSE; + + return EINA_TRUE; +} + +static E_Client * +_e_client_find_next_focus(E_Client *ec) +{ + Eina_List *l = NULL; + E_Client *temp_ec = NULL; + + // intercept revert focus policy + if (ec && !_e_client_intercept_hook_call(E_CLIENT_INTERCEPT_HOOK_FOCUS_REVERT, ec)) + return NULL; + + EINA_LIST_FOREACH(focus_stack, l, temp_ec) + { + if (_e_client_focus_can_take(temp_ec)) + return temp_ec; + } + + return NULL; +} + +static E_Client * +_e_client_revert_focus_get(E_Client *ec) +{ + E_Client *pec = NULL, *focus_ec = NULL; + E_Desk *desk = NULL; + + if (stopping) return NULL; + if (!ec) + return _e_client_find_next_focus(NULL); + + if (!ec->zone) return NULL; + desk = e_desk_current_get(ec->zone); + if (!desk) return NULL; + if (ec->zone->display_state == E_ZONE_DISPLAY_STATE_OFF) return NULL; + + if ((ec->parent) && + (ec->parent->desk == desk) && (ec->parent->modal == ec)) + { + // set parent focus + focus_ec = ec->parent; + if (e_config->raise_on_revert_focus) + evas_object_raise(ec->parent->frame); + } + else if (e_config->focus_policy == E_FOCUS_MOUSE) + { + // set mouse over focus + pec = e_client_under_pointer_get(desk, ec); + if (pec) + focus_ec = pec; + /* no autoraise/revert here because it's probably annoying */ + } + else + focus_ec = _e_client_find_next_focus(ec); + + return focus_ec; +} + +EINTERN void +e_client_revert_focus(E_Client *ec) +{ + E_Client *focus_ec = NULL; + focus_ec = _e_client_revert_focus_get(ec); + + if (focus_ec) + { + if (focus_ec != ec) + { + e_client_focus_defer_unset(ec); + ELOGF("FOCUS", "focus unset | revert_focus", ec); + evas_object_focus_set(ec->frame, EINA_FALSE); + } + ELOGF("FOCUS", "focus set | revert_focus", focus_ec); + evas_object_focus_set(focus_ec->frame, EINA_TRUE); + } +} + +EINTERN Eina_Bool +e_client_check_above_focused(E_Client *ec) +{ + E_Client *focus = NULL; + E_Client *above = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); + + focus = e_client_focused_get(); + if (!focus) return EINA_FALSE; + + above = e_client_above_get(ec); + while (above) + { + if (above == focus) + return EINA_TRUE; + + above = e_client_above_get(above); + } + + return EINA_FALSE; +} + +static void +_e_client_free(E_Client *ec) +{ + e_comp_object_redirected_set(ec->frame, 0); + e_comp_object_render_update_del(ec->frame); + + E_OBJECT(ec)->references++; + if (ec->fullscreen) + { + ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec); + if (!ec->desk->fullscreen_clients) + e_comp_render_queue(); + } + if (ec->new_client) + e_comp->new_clients--; + if (ec->e.state.profile.use) + { + e_client_desk_window_profile_wait_desk_set(ec, NULL); + + if (ec->e.state.profile.available_list) + { + int i; + for (i = 0; i < ec->e.state.profile.num; i++) + eina_stringshare_replace(&ec->e.state.profile.available_list[i], NULL); + E_FREE(ec->e.state.profile.available_list); + } + + ec->e.state.profile.num = 0; + + eina_stringshare_replace(&ec->e.state.profile.set, NULL); + eina_stringshare_replace(&ec->e.state.profile.wait, NULL); + eina_stringshare_replace(&ec->e.state.profile.name, NULL); + ec->e.state.profile.wait_for_done = 0; + ec->e.state.profile.use = 0; + } + + if (ec->e.state.video_parent && ec->e.state.video_parent_client) + { + ec->e.state.video_parent_client->e.state.video_child = + eina_list_remove(ec->e.state.video_parent_client->e.state.video_child, ec); + } + if (ec->e.state.video_child) + { + E_Client *tmp; + + EINA_LIST_FREE(ec->e.state.video_child, tmp) + tmp->e.state.video_parent_client = NULL; + } + E_FREE_FUNC(ec->internal_elm_win, evas_object_del); + E_FREE_FUNC(ec->post_job, ecore_idle_enterer_del); + + E_FREE_FUNC(ec->kill_timer, ecore_timer_del); + E_FREE_LIST(ec->pending_resize, free); + + E_FREE_FUNC(ec->map_timer, ecore_timer_del); + + ec->group = eina_list_free(ec->group); + ec->transients = eina_list_free(ec->transients); + ec->stick_desks = eina_list_free(ec->stick_desks); + if (ec->netwm.icons) + { + int i; + for (i = 0; i < ec->netwm.num_icons; i++) + free(ec->netwm.icons[i].data); + E_FREE(ec->netwm.icons); + } + E_FREE(ec->netwm.extra_types); + eina_stringshare_replace(&ec->border.name, NULL); + eina_stringshare_replace(&ec->bordername, NULL); + eina_stringshare_replace(&ec->icccm.name, NULL); + eina_stringshare_replace(&ec->icccm.class, NULL); + eina_stringshare_replace(&ec->icccm.title, NULL); + eina_stringshare_replace(&ec->icccm.icon_name, NULL); + eina_stringshare_replace(&ec->icccm.machine, NULL); + eina_stringshare_replace(&ec->icccm.window_role, NULL); + if ((ec->icccm.command.argc > 0) && (ec->icccm.command.argv)) + { + int i; + + for (i = 0; i < ec->icccm.command.argc; i++) + free(ec->icccm.command.argv[i]); + E_FREE(ec->icccm.command.argv); + } + eina_stringshare_replace(&ec->netwm.name, NULL); + eina_stringshare_replace(&ec->netwm.icon_name, NULL); + eina_stringshare_replace(&ec->internal_icon, NULL); + eina_stringshare_replace(&ec->internal_icon_key, NULL); + + focus_stack = eina_list_remove(focus_stack, ec); + defer_focus_stack = eina_list_remove(defer_focus_stack, ec); + + if (ec->e.state.profile.wait_desk) + { + e_object_delfn_del(E_OBJECT(ec->e.state.profile.wait_desk), + ec->e.state.profile.wait_desk_delfn); + ec->e.state.profile.wait_desk_delfn = NULL; + e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk)); + } + ec->e.state.profile.wait_desk = NULL; + E_FREE_FUNC(ec->frame, evas_object_del); + E_OBJECT(ec)->references--; + ELOG("CLIENT FREE", ec); + + e_uuid_store_entry_del(ec->uuid); + + e_desk_client_del(ec->desk, ec); + + free(ec); +} + +static void +_e_client_del(E_Client *ec) +{ + E_Client *child; + E_Pixmap_Type type; + + ec->changed = 0; + focus_stack = eina_list_remove(focus_stack, ec); + defer_focus_stack = eina_list_remove(defer_focus_stack, ec); + + if (ec == e_comp_object_dim_client_get()) + { + INF("[DIM] client deleted\n"); + e_comp_object_dim_client_set(NULL); + } + + if (ec->cur_mouse_action) + { + if (ec->cur_mouse_action->func.end) + ec->cur_mouse_action->func.end(E_OBJECT(ec), ""); + } + if (action_client == ec) _e_client_action_finish(); + + if (warp_client == ec) + { + E_FREE_FUNC(warp_timer, ecore_timer_del); + warp_client = NULL; + } + + if ((client_drag) && (client_drag->data == ec)) + { + e_object_del(E_OBJECT(client_drag)); + client_drag = NULL; + } + if (!stopping) + { + e_client_comp_hidden_set(ec, 1); + evas_object_pass_events_set(ec->frame, 1); + } + + E_FREE_FUNC(ec->border_prop_dialog, e_object_del); + E_FREE_FUNC(ec->color_editor, evas_object_del); + + if (ec->internal_elm_win) + evas_object_hide(ec->internal_elm_win); + + if (ec->focused) + e_client_revert_focus(ec); + + E_FREE_FUNC(ec->ping_poller, ecore_poller_del); + /* must be called before parent/child clear */ + _e_client_hook_call(E_CLIENT_HOOK_DEL, ec); + E_FREE(ec->comp_data); + + if ((!ec->new_client) && (!stopping)) + { + ELOGF("COMP", "SEND E_EVENT_CLIENT_REMOVE event", ec); + _e_client_event_remove(ec); + } + else + { + if (stopping) + { + ELOGF("COMP", "SEND E_EVENT_CLIENT_REMOVE event on stopping env", ec); + _e_client_event_remove(ec); + } + } + + ELOG("CLIENT DEL", ec); + + if (ec->parent) + { + ec->parent->transients = eina_list_remove(ec->parent->transients, ec); + ec->parent = NULL; + } + EINA_LIST_FREE(ec->transients, child) + child->parent = NULL; + + if (ec->leader) + { + ec->leader->group = eina_list_remove(ec->leader->group, ec); + if (ec->leader->modal == ec) + ec->leader->modal = NULL; + ec->leader = NULL; + } + EINA_LIST_FREE(ec->group, child) + child->leader = NULL; + + type = e_pixmap_type_get(ec->pixmap); + if (type < E_PIXMAP_TYPE_MAX) + eina_hash_del_by_key(clients_hash[type], &ec->pixmap); + e_comp->clients = eina_list_remove(e_comp->clients, ec); + e_comp_object_render_update_del(ec->frame); + e_comp_post_update_purge(ec); + if (e_pixmap_free(ec->pixmap)) + e_pixmap_client_set(ec->pixmap, NULL); + ec->pixmap = NULL; + + if (ec->transform_core.transform_list) + { + E_Util_Transform *transform; + + EINA_LIST_FREE(ec->transform_core.transform_list, transform) + { + e_util_transform_unref(transform); + } + } + + ec->transform_core.result.enable = EINA_FALSE; + + e_client_visibility_calculate(); +} + +/////////////////////////////////////////// + +static Eina_Bool +_e_client_cb_kill_timer(void *data) +{ + E_Client *ec = data; + +// dont wait until it's hung - +// if (ec->hung) +// { + if (ec->netwm.pid > 1) + kill(ec->netwm.pid, SIGKILL); +// } + ec->kill_timer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_e_client_cb_ping_poller(void *data) +{ + E_Client *ec; + + ec = data; + if (e_object_is_del(E_OBJECT(ec))) + { + ec->ping_poller = NULL; + return ECORE_CALLBACK_CANCEL; + } + + if (ec->ping_ok) + { + if (ec->hung) + { + ec->hung = 0; + evas_object_smart_callback_call(ec->frame, "unhung", NULL); + E_FREE_FUNC(ec->kill_timer, ecore_timer_del); + } + } + else + { + /* if time between last ping and now is greater + * than half the ping interval... */ + if ((ecore_loop_time_get() - ec->ping) > + ((e_config->ping_clients_interval * + ecore_poller_poll_interval_get(ECORE_POLLER_CORE)) / 2.0)) + { + if (!ec->hung) + { + ec->hung = 1; + evas_object_smart_callback_call(ec->frame, "hung", NULL); + /* FIXME: if below dialog is up - hide it now */ + } + if (ec->delete_requested) + { + /* FIXME: pop up dialog saying app is hung - kill client, or pid */ + e_client_act_kill_begin(ec); + } + } + } + ec->ping_poller = NULL; + e_client_ping(ec); + return ECORE_CALLBACK_CANCEL; +} + +/////////////////////////////////////////// + +static int +_e_client_action_input_win_new(void) +{ + if (comp_grabbed) + { + CRI("DOUBLE COMP GRAB! ACK!!!!"); + return 1; + } + comp_grabbed = e_comp_grab_input(1, 1); + if (!comp_grabbed) _e_client_action_input_win_del(); + return comp_grabbed; +} + +static void +_e_client_action_init(E_Client *ec) +{ + action_orig.x = ec->x; + action_orig.y = ec->y; + action_orig.w = ec->w; + action_orig.h = ec->h; + + if (action_client) + { + action_client->keyboard_resizing = 0; + //if (action_client->internal_elm_win) + // ecore_event_window_ignore_events(elm_win_window_id_get(action_client->internal_elm_win), 0); + } + action_client = ec; + //if (ec->internal_elm_win) + // ecore_event_window_ignore_events(elm_win_window_id_get(ec->internal_elm_win), 1); +} + +static void +_e_client_action_restore_orig(E_Client *ec) +{ + if (action_client != ec) + return; + + evas_object_geometry_set(ec->frame, action_orig.x, action_orig.y, action_orig.w, action_orig.h); +} + +static int +_e_client_key_down_modifier_apply(int modifier, int value) +{ + if (modifier & ECORE_EVENT_MODIFIER_CTRL) + return value * 2; + else if (modifier & ECORE_EVENT_MODIFIER_ALT) + { + value /= 2; + if (value) + return value; + else + return 1; + } + + return value; +} + + +static int +_e_client_move_begin(E_Client *ec) +{ + if ((ec->fullscreen) || (ec->lock_user_location)) + return 0; + + if (!_e_client_action_input_win_new()) return 0; + ec->moving = 1; + ecmove = ec; + _e_client_hook_call(E_CLIENT_HOOK_MOVE_BEGIN, ec); + if (!ec->moving) + { + if (ecmove == ec) ecmove = NULL; + _e_client_action_input_win_del(); + return 0; + } + if (!ec->lock_user_stacking) + { + if (e_config->border_raise_on_mouse_action) + evas_object_raise(ec->frame); + } + + if (e_comp->hwc) + e_comp_client_override_add(ec); + + return 1; +} + +static int +_e_client_move_end(E_Client *ec) +{ + _e_client_action_input_win_del(); + ec->moving = 0; + _e_client_hook_call(E_CLIENT_HOOK_MOVE_END, ec); + + if (ec->transformed) + _e_client_transform_move_end(ec); + + if (e_comp->hwc) + e_comp_client_override_del(ec); + + ecmove = NULL; + return 1; +} + +static Eina_Bool +_e_client_action_move_timeout(void *data EINA_UNUSED) +{ + _e_client_move_end(action_client); + _e_client_action_finish(); + return ECORE_CALLBACK_CANCEL; +} + +static void +_e_client_action_move_timeout_add(void) +{ + E_FREE_FUNC(action_timer, ecore_timer_del); + if (e_config->border_keyboard.timeout) + action_timer = ecore_timer_add(e_config->border_keyboard.timeout, _e_client_action_move_timeout, NULL); +} + +static Eina_Bool +_e_client_move_key_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_Event_Key *ev = event; + int x, y; + + if (!comp_grabbed) return ECORE_CALLBACK_RENEW; + if (!action_client) + { + ERR("no action_client!"); + goto stop; + } + + x = action_client->x; + y = action_client->y; + + if ((strcmp(ev->key, "Up") == 0) || (strcmp(ev->key, "k") == 0)) + y -= _e_client_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dy, 1)); + else if ((strcmp(ev->key, "Down") == 0) || (strcmp(ev->key, "j") == 0)) + y += _e_client_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dy, 1)); + else if ((strcmp(ev->key, "Left") == 0) || (strcmp(ev->key, "h") == 0)) + x -= _e_client_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dx, 1)); + else if ((strcmp(ev->key, "Right") == 0) || (strcmp(ev->key, "l") == 0)) + x += _e_client_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dx, 1)); + else if (strcmp(ev->key, "Return") == 0) + goto stop; + else if (strcmp(ev->key, "Escape") == 0) + { + _e_client_action_restore_orig(action_client); + goto stop; + } + else if ((strncmp(ev->key, "Control", sizeof("Control") - 1) != 0) && + (strncmp(ev->key, "Alt", sizeof("Alt") - 1) != 0)) + goto stop; + + evas_object_move(action_client->frame, x, y); + _e_client_action_move_timeout_add(); + + return ECORE_CALLBACK_PASS_ON; + +stop: + if (action_client) _e_client_move_end(action_client); + _e_client_action_finish(); + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_e_client_move_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + if (!comp_grabbed) return ECORE_CALLBACK_RENEW; + + if (!action_client) + ERR("no action_client!"); + + if (action_client) _e_client_move_end(action_client); + _e_client_action_finish(); + return ECORE_CALLBACK_DONE; +} + +static void +_e_client_moveinfo_gather(E_Client *ec, const char *source) +{ + if (e_util_glob_match(source, "mouse,*,1")) + ec->moveinfo.down.button = 1; + else if (e_util_glob_match(source, "mouse,*,2")) + ec->moveinfo.down.button = 2; + else if (e_util_glob_match(source, "mouse,*,3")) + ec->moveinfo.down.button = 3; + else + ec->moveinfo.down.button = 0; + if ((ec->moveinfo.down.button >= 1) && (ec->moveinfo.down.button <= 3)) + { + ec->moveinfo.down.mx = ec->mouse.last_down[ec->moveinfo.down.button - 1].mx; + ec->moveinfo.down.my = ec->mouse.last_down[ec->moveinfo.down.button - 1].my; + } + else + { + ec->moveinfo.down.mx = ec->mouse.current.mx; + ec->moveinfo.down.my = ec->mouse.current.my; + } +} + +static void +_e_client_resize_handle(E_Client *ec) +{ + int x, y, w, h; + int new_x, new_y, new_w, new_h; + int tw, th; + Eina_List *skiplist = NULL; + + if (ec->transformed) + { + _e_client_transform_resize_handle(ec); + return; + } + + x = ec->x; + y = ec->y; + w = ec->w; + h = ec->h; + + if ((ec->resize_mode == E_POINTER_RESIZE_TR) || + (ec->resize_mode == E_POINTER_RESIZE_R) || + (ec->resize_mode == E_POINTER_RESIZE_BR)) + { + if ((ec->moveinfo.down.button >= 1) && + (ec->moveinfo.down.button <= 3)) + w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w + + (ec->mouse.current.mx - ec->moveinfo.down.mx); + else + w = ec->moveinfo.down.w + (ec->mouse.current.mx - ec->moveinfo.down.mx); + } + else if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_L) || + (ec->resize_mode == E_POINTER_RESIZE_BL)) + { + if ((ec->moveinfo.down.button >= 1) && + (ec->moveinfo.down.button <= 3)) + w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w - + (ec->mouse.current.mx - ec->moveinfo.down.mx); + else + w = ec->moveinfo.down.w - (ec->mouse.current.mx - ec->moveinfo.down.mx); + } + + if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_T) || + (ec->resize_mode == E_POINTER_RESIZE_TR)) + { + if ((ec->moveinfo.down.button >= 1) && + (ec->moveinfo.down.button <= 3)) + h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h - + (ec->mouse.current.my - ec->moveinfo.down.my); + else + h = ec->moveinfo.down.h - (ec->mouse.current.my - ec->moveinfo.down.my); + } + else if ((ec->resize_mode == E_POINTER_RESIZE_BL) || + (ec->resize_mode == E_POINTER_RESIZE_B) || + (ec->resize_mode == E_POINTER_RESIZE_BR)) + { + if ((ec->moveinfo.down.button >= 1) && + (ec->moveinfo.down.button <= 3)) + h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h + + (ec->mouse.current.my - ec->moveinfo.down.my); + else + h = ec->moveinfo.down.h + (ec->mouse.current.my - ec->moveinfo.down.my); + } + + tw = ec->w; + th = ec->h; + + if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_L) || + (ec->resize_mode == E_POINTER_RESIZE_BL)) + x += (tw - w); + if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_T) || + (ec->resize_mode == E_POINTER_RESIZE_TR)) + y += (th - h); + + skiplist = eina_list_append(skiplist, ec); + e_resist_client_position(skiplist, + ec->x, ec->y, ec->w, ec->h, + x, y, w, h, + &new_x, &new_y, &new_w, &new_h); + eina_list_free(skiplist); + + w = new_w; + h = new_h; + if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE) + { + if (ec->zone) + { + w = MIN(w, ec->zone->w); + h = MIN(h, ec->zone->h); + } + } + e_client_resize_limit(ec, &new_w, &new_h); + if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_L) || + (ec->resize_mode == E_POINTER_RESIZE_BL)) + new_x += (w - new_w); + if ((ec->resize_mode == E_POINTER_RESIZE_TL) || + (ec->resize_mode == E_POINTER_RESIZE_T) || + (ec->resize_mode == E_POINTER_RESIZE_TR)) + new_y += (h - new_h); + + evas_object_geometry_set(ec->frame, new_x, new_y, new_w, new_h); +} + +static int +_e_client_resize_end(E_Client *ec) +{ + _e_client_action_input_win_del(); + ec->resize_mode = E_POINTER_RESIZE_NONE; + + /* If this border was maximized, we need to unset Maximized state or + * on restart, E still thinks it's maximized */ + if (ec->maximized != E_MAXIMIZE_NONE) + e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL, + ec->maximized & E_MAXIMIZE_VERTICAL); + + _e_client_hook_call(E_CLIENT_HOOK_RESIZE_END, ec); + + if (ec->transformed) + _e_client_transform_resize_end(ec); + + if (e_comp->hwc) + e_comp_client_override_del(ec); + + ecresize = NULL; + + return 1; +} + +static Eina_Bool +_e_client_action_resize_timeout(void *data EINA_UNUSED) +{ + _e_client_resize_end(action_client); + _e_client_action_finish(); + return ECORE_CALLBACK_CANCEL; +} + +static void +_e_client_action_resize_timeout_add(void) +{ + E_FREE_FUNC(action_timer, ecore_timer_del); + if (e_config->border_keyboard.timeout) + action_timer = ecore_timer_add(e_config->border_keyboard.timeout, _e_client_action_resize_timeout, NULL); +} + +static Eina_Bool +_e_client_resize_key_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_Event_Key *ev = event; + int w, h, dx, dy; + + if (!comp_grabbed) return ECORE_CALLBACK_RENEW; + if (!action_client) + { + ERR("no action_client!"); + goto stop; + } + + w = action_client->w; + h = action_client->h; + + dx = e_config->border_keyboard.resize.dx; + if (dx < action_client->icccm.step_w) + dx = action_client->icccm.step_w; + dx = _e_client_key_down_modifier_apply(ev->modifiers, dx); + if (dx < action_client->icccm.step_w) + dx = action_client->icccm.step_w; + + dy = e_config->border_keyboard.resize.dy; + if (dy < action_client->icccm.step_h) + dy = action_client->icccm.step_h; + dy = _e_client_key_down_modifier_apply(ev->modifiers, dy); + if (dy < action_client->icccm.step_h) + dy = action_client->icccm.step_h; + + if ((strcmp(ev->key, "Up") == 0) || (strcmp(ev->key, "k") == 0)) + h -= dy; + else if ((strcmp(ev->key, "Down") == 0) || (strcmp(ev->key, "j") == 0)) + h += dy; + else if ((strcmp(ev->key, "Left") == 0) || (strcmp(ev->key, "h") == 0)) + w -= dx; + else if ((strcmp(ev->key, "Right") == 0) || (strcmp(ev->key, "l") == 0)) + w += dx; + else if (strcmp(ev->key, "Return") == 0) + goto stop; + else if (strcmp(ev->key, "Escape") == 0) + { + _e_client_action_restore_orig(action_client); + goto stop; + } + else if ((strncmp(ev->key, "Control", sizeof("Control") - 1) != 0) && + (strncmp(ev->key, "Alt", sizeof("Alt") - 1) != 0)) + goto stop; + if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE) + { + if (action_client->zone) + { + w = MIN(w, action_client->zone->w); + h = MIN(h, action_client->zone->h); + } + } + e_client_resize_limit(action_client, &w, &h); + evas_object_resize(action_client->frame, w, h); + _e_client_action_resize_timeout_add(); + + return ECORE_CALLBACK_PASS_ON; + +stop: + if (action_client) _e_client_resize_end(action_client); + _e_client_action_finish(); + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_e_client_resize_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + if (!comp_grabbed) return ECORE_CALLBACK_RENEW; + + if (!action_client) + ERR("no action_client!"); + + if (action_client) _e_client_resize_end(action_client); + _e_client_action_finish(); + return ECORE_CALLBACK_DONE; +} + +//////////////////////////////////////////////// + +static E_Client * +_e_client_under_pointer_helper(E_Desk *desk, E_Client *exclude, int x, int y) +{ + E_Client *ec = NULL, *cec; + + E_CLIENT_REVERSE_FOREACH(cec) + { + /* If a border was specified which should be excluded from the list + * (because it will be closed shortly for example), skip */ + if (e_client_util_ignored_get(cec) || (!e_client_util_desk_visible(cec, desk))) continue; + if (!evas_object_visible_get(cec->frame)) continue; + if ((exclude) && (cec == exclude)) continue; + if (!E_INSIDE(x, y, cec->x, cec->y, cec->w, cec->h)) + continue; + /* If the layer is higher, the position of the window is higher + * (always on top vs always below) */ + if (!ec || (cec->layer > ec->layer)) + ec = cec; + } + return ec; +} + +//////////////////////////////////////////////// + +static void +_e_client_zones_layout_calc(E_Client *ec, int *zx, int *zy, int *zw, int *zh) +{ + int x, y, w, h; + E_Zone *zone_above, *zone_below, *zone_left, *zone_right; + + if (!ec->zone) return; + x = ec->zone->x; + y = ec->zone->y; + w = ec->zone->w; + h = ec->zone->h; + + if (eina_list_count(e_comp->zones) == 1) + { + if (zx) *zx = x; + if (zy) *zy = y; + if (zw) *zw = w; + if (zh) *zh = h; + return; + } + + zone_left = e_comp_zone_xy_get((x - w + 5), y); + zone_right = e_comp_zone_xy_get((x + w + 5), y); + zone_above = e_comp_zone_xy_get(x, (y - h + 5)); + zone_below = e_comp_zone_xy_get(x, (y + h + 5)); + + if (!(zone_above) && (y)) + zone_above = e_comp_zone_xy_get(x, (h - 5)); + + if (!(zone_left) && (x)) + zone_left = e_comp_zone_xy_get((x - 5), y); + + if (zone_right) + w = zone_right->x + zone_right->w; + + if (zone_left) + w = ec->zone->x + ec->zone->w; + + if (zone_below) + h = zone_below->y + zone_below->h; + + if (zone_above) + h = ec->zone->y + ec->zone->h; + + if ((zone_left) && (zone_right)) + w = ec->zone->w + zone_right->x; + + if ((zone_above) && (zone_below)) + h = ec->zone->h + zone_below->y; + + if (x) x -= ec->zone->w; + if (y) y -= ec->zone->h; + + if (zx) *zx = x > 0 ? x : 0; + if (zy) *zy = y > 0 ? y : 0; + if (zw) *zw = w; + if (zh) *zh = h; +} + +static void +_e_client_stay_within_canvas(E_Client *ec, int x, int y, int *new_x, int *new_y) +{ + int new_x_max, new_y_max; + int zw, zh; + Eina_Bool lw, lh; + + if (!ec->zone) + { + if (new_x) *new_x = x; + if (new_y) *new_y = y; + return; + } + + _e_client_zones_layout_calc(ec, NULL, NULL, &zw, &zh); + + new_x_max = zw - ec->w; + new_y_max = zh - ec->h; + lw = ec->w > zw ? EINA_TRUE : EINA_FALSE; + lh = ec->h > zh ? EINA_TRUE : EINA_FALSE; + + if (lw) + { + if (x <= new_x_max) + *new_x = new_x_max; + else if (x >= 0) + *new_x = 0; + } + else + { + if (x >= new_x_max) + *new_x = new_x_max; + else if (x <= 0) + *new_x = 0; + } + + if (lh) + { + if (y <= new_y_max) + *new_y = new_y_max; + else if (y >= 0) + *new_y = 0; + } + else + { + if (y >= new_y_max) + *new_y = new_y_max; + else if (y <= 0) + *new_y = 0; + } +} + +static void +_e_client_stay_within_canvas_margin(E_Client *ec, int x, int y, int *new_x, int *new_y) +{ + int new_x_max, new_y_max, new_x_min, new_y_min; + int margin_w, margin_h; + int zw, zh; + int cw, ch; + + if (!ec->zone) + { + if (new_x) *new_x = x; + if (new_y) *new_y = y; + return; + } + + cw = ec->w; + ch = ec->h; + + _e_client_zones_layout_calc(ec, NULL, NULL, &zw, &zh); + + margin_w = zw/3; + margin_h = zh/10; + + new_x_min = (margin_w > cw) ? 0 : -(cw - margin_w); + new_x_max = (margin_w > cw) ? (zw - cw) : (zw - margin_w); + new_y_min = (margin_h > ch) ? 0 : -(ch - margin_h); + new_y_max = (margin_h > ch) ? (zh - ch) : (zh - margin_h); + + if (x >= new_x_max) + *new_x = new_x_max; + else if (x <= new_x_min) + *new_x = new_x_min; + + if (y >= new_y_max) + *new_y = new_y_max; + else if (y <= new_y_min) + *new_y = new_y_min; + +} + +static void +_e_client_reset_lost_window(E_Client *ec) +{ + E_OBJECT_CHECK(ec); + + if (ec->during_lost) return; + ec->during_lost = EINA_TRUE; + + if (ec->iconic) e_client_uniconify(ec); + if (!ec->moving) e_comp_object_util_center(ec->frame); + + evas_object_raise(ec->frame); + if (!ec->lock_focus_out) + { + ELOGF("FOCUS", "focus set | reset_lost_window", ec); + evas_object_focus_set(ec->frame, 1); + } + + e_client_pointer_warp_to_center(ec); + ec->during_lost = EINA_FALSE; +} + +static void +_e_client_move_lost_window_to_center(E_Client *ec) +{ + int loss_overlap = 5; + int zw, zh, zx, zy; + + if (ec->during_lost) return; + if (!ec->zone) return; + + _e_client_zones_layout_calc(ec, &zx, &zy, &zw, &zh); + + if (!E_INTERSECTS(zx + loss_overlap, + zy + loss_overlap, + zw - (2 * loss_overlap), + zh - (2 * loss_overlap), + ec->x, ec->y, ec->w, ec->h)) + { + _e_client_reset_lost_window(ec); + } +} + +//////////////////////////////////////////////// +static void +_e_client_zone_update(E_Client *ec) +{ + Eina_List *l; + E_Zone *zone; + + /* still within old zone - leave it there */ + if (ec->zone && E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, + ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h)) + return; + /* find a new zone */ + EINA_LIST_FOREACH(e_comp->zones, l, zone) + { + if (E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, + zone->x, zone->y, zone->w, zone->h)) + { + e_client_zone_set(ec, zone); + return; + } + } +} + +//////////////////////////////////////////////// + +static void +_e_client_cb_evas_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Client *ec = data; + + if (stopping) return; //ignore all of this if we're shutting down! + if (e_object_is_del(data)) return; //client is about to die + if (ec->cur_mouse_action) + { + if (ec->cur_mouse_action->func.end_mouse) + ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", NULL); + else if (ec->cur_mouse_action->func.end) + ec->cur_mouse_action->func.end(E_OBJECT(ec), ""); + E_FREE_FUNC(ec->cur_mouse_action, e_object_unref); + } + if (action_client == ec) _e_client_action_finish(); + + ec->want_focus = ec->take_focus = 0; + + ec->post_show = 0; + + if (ec->new_client) return; + _e_client_event_hide(ec); + + EC_CHANGED(ec); +} + +static void +_e_client_cb_evas_shade_done(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Client *ec = data; + + if (e_object_is_del(data)) return; + + ec->shading = 0; + ec->shaded = !(ec->shaded); + ec->changes.shaded = 1; + ec->changes.shading = 1; + e_client_comp_hidden_set(ec, ec->shaded); +} + +static void +_e_client_cb_evas_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Client *ec = data; + Evas_Coord x, y; + + if (e_object_is_del(data)) return; + + ec->pre_res_change.valid = 0; + if (ec->internal_elm_win) + { + EC_CHANGED(ec); + ec->changes.pos = 1; + } + + _e_client_event_simple(ec, E_EVENT_CLIENT_MOVE); + + _e_client_zone_update(ec); + evas_object_geometry_get(ec->frame, &x, &y, NULL, NULL); + if ((e_config->transient.move) && (ec->transients)) + { + Eina_List *list = eina_list_clone(ec->transients); + E_Client *child; + + EINA_LIST_FREE(list, child) + { + if (child->vkbd.vkbd) continue; + + evas_object_move(child->frame, + child->x + x - ec->pre_cb.x, + child->y + y - ec->pre_cb.y); + } + } + if (ec->moving || (ecmove == ec)) + _e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec); + + if ((!ec->moving) && (ec->transformed)) + _e_client_transform_geometry_save(ec, + (Evas_Map *)evas_object_map_get(ec->frame)); + + ec->pre_cb.x = x; ec->pre_cb.y = y; + + if (ec->focused) + { + if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, + ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h)) + { + e_client_revert_focus(ec); + } + } + + e_client_visibility_calculate(); +} + +static void +_e_client_cb_evas_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Client *ec = data; + Evas_Coord x, y, w, h; + + if (e_object_is_del(data)) return; + + ec->pre_res_change.valid = 0; + + _e_client_event_simple(ec, E_EVENT_CLIENT_RESIZE); + + _e_client_zone_update(ec); + evas_object_geometry_get(ec->frame, &x, &y, &w, &h); + if ((e_config->transient.resize) && (ec->transients)) + { + Eina_List *list = eina_list_clone(ec->transients); + E_Client *child; + + EINA_LIST_FREE(list, child) + { + Evas_Coord nx, ny, nw, nh; + + if ((ec->pre_cb.w > 0) && (ec->pre_cb.h > 0)) + { + nx = x + (((child->x - x) * w) / ec->pre_cb.w); + ny = y + (((child->y - y) * h) / ec->pre_cb.h); + nw = (child->w * w) / ec->pre_cb.w; + nh = (child->h * h) / ec->pre_cb.h; + nx += ((nw - child->w) / 2); + ny += ((nh - child->h) / 2); + evas_object_move(child->frame, nx, ny); + } + } + } + + if (e_client_util_resizing_get(ec) || (ecresize == ec)) + _e_client_hook_call(E_CLIENT_HOOK_RESIZE_UPDATE, ec); + ec->pre_cb.w = w; ec->pre_cb.h = h; + + e_client_transform_core_update(ec); + e_client_visibility_calculate(); +} + +static void +_e_client_cb_evas_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Client *ec = data; + + if (e_object_is_del(data)) return; + + _e_client_event_show(ec); + EC_CHANGED(ec); +} + +static void +_e_client_cb_evas_restack(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Client *ec = data; + + if (e_object_is_del(data)) return; + if (ec->layer_block) return; + if (ec->layer_pending) return; + if (e_config->transient.raise && ec->transients) + { + Eina_List *list = eina_list_clone(ec->transients); + E_Client *child, *below = NULL, *above = NULL; + + E_LIST_REVERSE_FREE(list, child) + { + /* Don't stack vkbd if parent is splitted */ + if (child->vkbd.vkbd && ec->layout.splited) continue; + + /* Don't stack iconic transients. If the user wants these shown, + * that's another option. + */ + if (child->iconic && child->exp_iconify.by_client) continue; + + if (child->transient_policy == E_TRANSIENT_ABOVE) + { + if (below) + evas_object_stack_below(child->frame, below->frame); + else + evas_object_stack_above(child->frame, ec->frame); + below = child; + } + else if (child->transient_policy == E_TRANSIENT_BELOW) + { + if (above) + evas_object_stack_above(child->frame, above->frame); + else + evas_object_stack_below(child->frame, ec->frame); + above = child; + } + + } + } + if (ec->unredirected_single) return; + _e_client_event_simple(ec, E_EVENT_CLIENT_STACK); + + e_client_visibility_calculate(); +} + +//////////////////////////////////////////////// + +static void +_e_client_maximize(E_Client *ec, E_Maximize max) +{ + int x1, yy1, x2, y2; + int w, h, pw, ph; + int zx, zy, zw, zh; + int ecx, ecy, ecw, ech; + Eina_Bool override = ec->maximize_override; + + if (!ec->zone) return; + zx = zy = zw = zh = 0; + ec->maximize_override = 1; + + switch (max & E_MAXIMIZE_TYPE) + { + case E_MAXIMIZE_NONE: + /* Ignore */ + break; + + case E_MAXIMIZE_FULLSCREEN: + w = ec->desk->geom.w; + h = ec->desk->geom.h; + + evas_object_smart_callback_call(ec->frame, "fullscreen", NULL); + e_client_resize_limit(ec, &w, &h); + /* center x-direction */ + x1 = ec->desk->geom.x + (ec->desk->geom.w - w) / 2; + /* center y-direction */ + yy1 = ec->desk->geom.y + (ec->desk->geom.h - h) / 2; + + switch (max & E_MAXIMIZE_DIRECTION) + { + case E_MAXIMIZE_BOTH: + evas_object_geometry_set(ec->frame, x1, yy1, w, h); + break; + + case E_MAXIMIZE_VERTICAL: + evas_object_geometry_set(ec->frame, ec->x, yy1, ec->w, h); + break; + + case E_MAXIMIZE_HORIZONTAL: + evas_object_geometry_set(ec->frame, x1, ec->y, w, ec->h); + break; + + case E_MAXIMIZE_LEFT: + evas_object_geometry_set(ec->frame, ec->desk->geom.x, ec->desk->geom.y, w / 2, h); + break; + + case E_MAXIMIZE_RIGHT: + evas_object_geometry_set(ec->frame, x1, ec->desk->geom.y, w / 2, h); + break; + } + break; + + case E_MAXIMIZE_SMART: + case E_MAXIMIZE_EXPAND: + if (ec->desk->visible) + { + zx = ec->desk->geom.x; + zy = ec->desk->geom.y; + zw = ec->desk->geom.w; + zh = ec->desk->geom.h; + } + else + { + x1 = ec->desk->geom.x; + yy1 = ec->desk->geom.y; + x2 = ec->desk->geom.x + ec->desk->geom.w; + y2 = ec->desk->geom.y + ec->desk->geom.h; + e_maximize_client_shelf_fill(ec, &x1, &yy1, &x2, &y2, max); + zx = x1, zy = yy1; + zw = x2 - x1; + zh = y2 - yy1; + } + w = zw, h = zh; + + evas_object_smart_callback_call(ec->frame, "maximize", NULL); + e_comp_object_frame_xy_unadjust(ec->frame, ec->x, ec->y, &ecx, &ecy); + e_comp_object_frame_wh_unadjust(ec->frame, ec->w, ec->h, &ecw, &ech); + + if (ecw < zw) + w = ecw; + + if (ech < zh) + h = ech; + + if (ecx < zx) // window left not useful coordinates + x1 = zx; + else if (ecx + ecw > zx + zw) // window right not useful coordinates + x1 = zx + zw - ecw; + else // window normal position + x1 = ecx; + + if (ecy < zy) // window top not useful coordinates + yy1 = zy; + else if (ecy + ech > zy + zh) // window bottom not useful coordinates + yy1 = zy + zh - ech; + else // window normal position + yy1 = ecy; + + switch (max & E_MAXIMIZE_DIRECTION) + { + case E_MAXIMIZE_BOTH: + evas_object_geometry_set(ec->frame, zx, zy, zw, zh); + break; + + case E_MAXIMIZE_VERTICAL: + evas_object_geometry_set(ec->frame, ec->x, zy, ec->w, zh); + break; + + case E_MAXIMIZE_HORIZONTAL: + evas_object_geometry_set(ec->frame, zx, ec->y, zw, ec->h); + break; + + case E_MAXIMIZE_LEFT: + evas_object_geometry_set(ec->frame, zx, zy, zw / 2, zh); + break; + + case E_MAXIMIZE_RIGHT: + evas_object_geometry_set(ec->frame, zx + zw / 2, zy, zw / 2, zh); + break; + } + + break; + + case E_MAXIMIZE_FILL: + x1 = ec->desk->geom.x; + yy1 = ec->desk->geom.y; + x2 = ec->desk->geom.x + ec->desk->geom.w; + y2 = ec->desk->geom.y + ec->desk->geom.h; + + /* walk through all shelves */ + e_maximize_client_shelf_fill(ec, &x1, &yy1, &x2, &y2, max); + + /* walk through all windows */ + e_maximize_client_client_fill(ec, &x1, &yy1, &x2, &y2, max); + + w = x2 - x1; + h = y2 - yy1; + pw = w; + ph = h; + e_client_resize_limit(ec, &w, &h); + /* center x-direction */ + x1 = x1 + (pw - w) / 2; + /* center y-direction */ + yy1 = yy1 + (ph - h) / 2; + + switch (max & E_MAXIMIZE_DIRECTION) + { + case E_MAXIMIZE_BOTH: + evas_object_geometry_set(ec->frame, x1, yy1, w, h); + break; + + case E_MAXIMIZE_VERTICAL: + evas_object_geometry_set(ec->frame, ec->x, yy1, ec->w, h); + break; + + case E_MAXIMIZE_HORIZONTAL: + evas_object_geometry_set(ec->frame, x1, ec->y, w, ec->h); + break; + + case E_MAXIMIZE_LEFT: + evas_object_geometry_set(ec->frame, ec->desk->geom.x, ec->desk->geom.y, w / 2, h); + break; + + case E_MAXIMIZE_RIGHT: + evas_object_geometry_set(ec->frame, x1, ec->desk->geom.y, w / 2, h); + break; + } + break; + } + if (ec->maximize_override) + ec->maximize_override = override; +} + +//////////////////////////////////////////////// +static void +_e_client_aux_hint_eval(E_Client *ec) +{ + if (!ec) return; + + E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data; + Eina_List *l, *ll; + E_Comp_Wl_Aux_Hint *hint; + + if (cdata && cdata->aux_hint.changed) + { + _e_client_hook_call(E_CLIENT_HOOK_AUX_HINT_CHANGE, ec); + + EINA_LIST_FOREACH_SAFE(cdata->aux_hint.hints, l, ll, hint) + { + hint->changed = EINA_FALSE; + if (hint->deleted) + { + ELOGF("COMP", "AUX_HINT |Del [%d:%s:%s]", ec, hint->id, hint->hint, hint->val); + if (hint->hint) eina_stringshare_del(hint->hint); + if (hint->val) eina_stringshare_del(hint->val); + cdata->aux_hint.hints = eina_list_remove_list(cdata->aux_hint.hints, l); + E_FREE(hint); + } + } + cdata->aux_hint.changed = 0; + } +} + +static void +_e_client_eval(E_Client *ec) +{ + int send_event = 1; + unsigned int prop = 0; + + if (e_object_is_del(E_OBJECT(ec))) + { + CRI("_e_client_eval(%p) with deleted border! - %d\n", ec, ec->new_client); + ec->changed = 0; + return; + } + + TRACE_DS_BEGIN(CLIENT:EVAL); + + if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_NEW_CLIENT, ec)) + { + TRACE_DS_END(); + return; + } + + if ((ec->new_client) && (!e_client_util_ignored_get(ec)) && (ec->zone)) + { + int zx = 0, zy = 0, zw = 0, zh = 0; + + e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh); + /* enforce wm size hints for initial sizing */ + if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE) + { + ec->w = MIN(ec->w, ec->zone->w); + ec->h = MIN(ec->h, ec->zone->h); + } + e_client_resize_limit(ec, &ec->w, &ec->h); + + if (ec->re_manage) + { + int x = ec->x, y = ec->y; + if (ec->x) e_comp_object_frame_xy_adjust(ec->frame, ec->x, 0, &ec->x, NULL); + if (ec->y) e_comp_object_frame_xy_adjust(ec->frame, 0, ec->y, NULL, &ec->y); + if ((x != ec->x) || (y != ec->y)) ec->changes.pos = 1; + ec->placed = 1; + ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y; + } + if (!ec->placed) + { + if (ec->parent) + { + if (ec->parent->zone != e_zone_current_get()) + { + e_client_zone_set(ec, ec->parent->zone); + e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh); + } + + if (evas_object_visible_get(ec->parent->frame)) + { + if ((!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh)) || + (!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, ec->parent->x, ec->parent->y, ec->parent->w, ec->parent->h))) + { + int x, y; + + e_comp_object_util_center_pos_get(ec->parent->frame, &x, &y); + if (E_CONTAINS(x, y, ec->w, ec->h, zx, zy, zw, zh)) + { + ec->x = x, ec->y = y; + } + else + { + x = ec->parent->x; + y = ec->parent->y; + if (!E_CONTAINS(x, y, ec->w, ec->h, zx, zy, zw, zh)) + { + e_comp_object_util_center_on(ec->frame, + ec->parent->frame); + } + } + ec->changes.pos = 1; + } + } + else + { + e_comp_object_util_center_on(ec->frame, + ec->parent->frame); + ec->changes.pos = 1; + } + ec->placed = 1; + ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y; + } +#if 0 + else if ((ec->leader) && (ec->dialog)) + { + /* TODO: Place in center of group */ + } +#endif + else if (ec->dialog) + { + E_Client *trans_ec = NULL; + + if (ec->icccm.transient_for) + trans_ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ec->icccm.transient_for); + if (trans_ec) + { + // if transient for a window and not placed, center on + // transient parent if found + ec->x = trans_ec->x + ((trans_ec->w - ec->w) / 2); + ec->y = trans_ec->y + ((trans_ec->h - ec->h) / 2); + } + else + { + ec->x = zx + ((zw - ec->w) / 2); + ec->y = zy + ((zh - ec->h) / 2); + } + ec->changes.pos = 1; + ec->placed = 1; + ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y; + } + } + + if (!ec->placed) + { + Eina_List *skiplist = NULL; + int new_x, new_y, t = 0; + E_Client *trans_ec = NULL; + + if (zw > ec->w) + new_x = zx + (rand() % (zw - ec->w)); + else + new_x = zx; + if (zh > ec->h) + new_y = zy + (rand() % (zh - ec->h)); + else + new_y = zy; + + e_comp_object_frame_geometry_get(ec->frame, NULL, NULL, &t, NULL); + + if (ec->icccm.transient_for) + trans_ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ec->icccm.transient_for); + if (trans_ec) + { + // if transient for a window and not placed, center on + // transient parent if found + new_x = trans_ec->x + ((trans_ec->w - ec->w) / 2); + new_y = trans_ec->y + ((trans_ec->h - ec->h) / 2); + } + else if ((e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART) || (e_config->window_placement_policy == E_WINDOW_PLACEMENT_ANTIGADGET)) + { + skiplist = eina_list_append(skiplist, ec); + if (ec->desk) + e_place_desk_region_smart(ec->desk, skiplist, + ec->x, ec->y, ec->w, ec->h, + &new_x, &new_y); + else + e_place_zone_region_smart(ec->zone, skiplist, + ec->x, ec->y, ec->w, ec->h, + &new_x, &new_y); + eina_list_free(skiplist); + } + else if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL) + { + e_place_zone_manual(ec->zone, ec->w, t, &new_x, &new_y); + } + else + { + e_place_zone_cursor(ec->zone, ec->x, ec->y, ec->w, ec->h, + t, &new_x, &new_y); + } + ec->x = new_x; + ec->y = new_y; + ec->changes.pos = 1; + ec->placed = 1; + ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y; + } + else if (!E_INSIDE(ec->x, ec->y, zx, zy, zw, zh)) + { + /* workaround: some client such as lockscreen doesn't want to be placed in the zone */ + if (!ec->changes.tz_position) + { + /* If an ec is placed out of bound, fix it! */ + ec->x = zx + ((zw - ec->w) / 2); + ec->y = zy + ((zh - ec->h) / 2); + ec->changes.pos = 1; + } + } + + /* Recreate state */ + if (!ec->override) + e_hints_window_init(ec); + if (ec->e.state.centered) + { + ec->x = zx + (zw - ec->w) / 2; + ec->y = zy + (zh - ec->h) / 2; + ec->changes.pos = 1; + } + + /* if the explicit geometry request asks for the app to be + * in another zone - well move it there */ + { + E_Zone *zone = NULL; + int x, y; + + x = MAX(ec->x, 0); + y = MAX(ec->y, 0); + if ((!ec->re_manage) && ((ec->x != x) || (ec->y != y))) + zone = e_comp_zone_xy_get(x, y); + + if (!zone) + { + zone = e_comp_zone_xy_get(ec->x + (ec->w / 2), ec->y + (ec->h / 2)); + if (zone) + { + E_Zone *z2 = e_comp_zone_xy_get(ec->x, ec->y); + + if (z2 && (z2 != zone)) + { + size_t psz = 0; + E_Zone *zf = z2; + Eina_List *l; + + EINA_LIST_FOREACH(e_comp->zones, l, z2) + { + int w, h; + + x = ec->x, y = ec->y, w = ec->w, h = ec->h; + E_RECTS_CLIP_TO_RECT(x, y, w, h, z2->x, z2->y, z2->w, z2->h); + if (w * h == z2->w * z2->h) + { + /* client fully covering zone */ + zf = z2; + break; + } + if ((unsigned)(w * h) > psz) + { + psz = w * h; + zf = z2; + } + } + zone = zf; + } + } + } + if (!zone) + zone = e_comp_zone_xy_get(ec->x, ec->y); + if (!zone) + zone = e_comp_zone_xy_get(ec->x + ec->w - 1, ec->y); + if (!zone) + zone = e_comp_zone_xy_get(ec->x + ec->w - 1, ec->y + ec->h - 1); + if (!zone) + zone = e_comp_zone_xy_get(ec->x, ec->y + ec->h - 1); + if ((zone) && (zone != ec->zone)) + e_client_zone_set(ec, zone); + } + } + + if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT, ec)) + { + TRACE_DS_END(); + return; + } + + /* effect changes to the window border itself */ + if ((ec->changes.shading)) + { + /* show at start of unshade (but don't hide until end of shade) */ + ec->changes.shading = 0; + send_event = 0; + } + if (ec->changes.shaded) send_event = 0; + if ((ec->changes.shaded) && (ec->changes.pos) && (ec->changes.size)) + { + ec->changes.shaded = 0; + } + else if ((ec->changes.shaded) && (ec->changes.pos)) + { + ec->changes.size = 1; + ec->changes.shaded = 0; + } + else if ((ec->changes.shaded) && (ec->changes.size)) + { + ec->changes.shaded = 0; + } + else if (ec->changes.shaded) + { + ec->changes.shaded = 0; + } + + if (ec->changes.size) + { + ec->changes.size = 0; + if ((!ec->shaded) && (!ec->shading)) + evas_object_resize(ec->frame, ec->w, ec->h); + + prop |= E_CLIENT_PROPERTY_SIZE; + } + if (ec->changes.pos) + { + ec->changes.tz_position = 0; + ec->changes.pos = 0; + evas_object_move(ec->frame, ec->x, ec->y); + prop |= E_CLIENT_PROPERTY_POS; + } + + if (ec->changes.reset_gravity) + { + ec->changes.reset_gravity = 0; + prop |= E_CLIENT_PROPERTY_GRAVITY; + } + + if (ec->changes.title) + { + ec->changes.title = 0; + prop |= E_CLIENT_PROPERTY_TITLE; + } + + if ((ec->changes.visible) && (ec->visible) && (ec->new_client) && (!ec->iconic)) + { + int x, y; + + e_input_device_pointer_xy_get(NULL, &x, &y); + if ((!ec->placed) && (!ec->re_manage) && + (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL) && + (!((ec->icccm.transient_for != 0) || + (ec->dialog))) && + (!ecmove) && (!ecresize)) + { + /* Set this window into moving state */ + + ec->cur_mouse_action = e_action_find("window_move"); + if (ec->cur_mouse_action) + { + if ((!ec->cur_mouse_action->func.end_mouse) && + (!ec->cur_mouse_action->func.end)) + ec->cur_mouse_action = NULL; + if (ec->cur_mouse_action) + { + int t; + ec->x = x - (ec->w >> 1); + e_comp_object_frame_geometry_get(ec->frame, NULL, NULL, &t, NULL); + ec->y = y - (t >> 1); + EC_CHANGED(ec); + ec->changes.pos = 1; + } + } + } + + evas_object_show(ec->frame); + if (evas_object_visible_get(ec->frame)) + { + if (ec->cur_mouse_action) + { + ec->moveinfo.down.x = ec->x; + ec->moveinfo.down.y = ec->y; + ec->moveinfo.down.w = ec->w; + ec->moveinfo.down.h = ec->h; + ec->mouse.current.mx = x; + ec->mouse.current.my = y; + ec->moveinfo.down.button = 0; + ec->moveinfo.down.mx = x; + ec->moveinfo.down.my = y; + + e_object_ref(E_OBJECT(ec->cur_mouse_action)); + ec->cur_mouse_action->func.go(E_OBJECT(ec), NULL); + if (e_config->border_raise_on_mouse_action) + evas_object_raise(ec->frame); + ELOGF("FOCUS", "focus set | client eval", ec); + evas_object_focus_set(ec->frame, 1); + } + ec->changes.visible = 0; + _e_client_event_show(ec); + } + } + else if ((ec->changes.visible) && (ec->new_client)) + { + ec->changes.visible = 0; + if (!ec->iconic) + _e_client_event_hide(ec); + } + + if (ec->changes.icon) + { + ec->changes.icon = 0; + } + + if (ec->new_client) + e_comp->new_clients--; + ec->new_client = 0; + ec->changed = ec->changes.pos || ec->changes.size || + ec->changes.stack || ec->changes.prop || ec->changes.border || + ec->changes.reset_gravity || ec->changes.shading || ec->changes.shaded || + ec->changes.shape || ec->changes.shape_input || ec->changes.icon || + ec->changes.internal_state || + ec->changes.need_maximize || ec->changes.need_unmaximize; + ec->changes.stack = 0; + + if ((!ec->input_only) && (!ec->iconic) && + ((!ec->zone) || e_client_util_desk_visible(ec, e_desk_current_get(ec->zone))) && + ((ec->take_focus) || (ec->want_focus))) + { + ec->take_focus = 0; + if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || (ec->want_focus)) + { + ec->want_focus = 0; +#if 0 // focus should be set to the top window + e_client_focus_set_with_pointer(ec); +#endif + } + else if (ec->dialog) + { + if ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) || + ((e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED) && + (ec->parent == e_client_focused_get()))) + { + e_client_focus_set_with_pointer(ec); + } + } + else + { + /* focus window by default when it is the only one on desk */ + E_Client *ec2 = NULL; + Eina_List *l; + EINA_LIST_FOREACH(focus_stack, l, ec2) + { + if (ec == ec2) continue; + if ((!ec2->iconic) && (ec2->visible) && + ((ec->desk == ec2->desk) || ec2->sticky)) + break; + } + + if (!ec2) + { + e_client_focus_set_with_pointer(ec); + } + } + } + else + ec->take_focus = ec->want_focus = 0; + + if (ec->changes.need_maximize) + { + E_Maximize max = ec->maximized; + ec->maximized = E_MAXIMIZE_NONE; + e_client_maximize(ec, max); + ec->changes.need_maximize = 0; + } + else if (ec->changes.need_unmaximize) + { + e_client_unmaximize(ec, ec->maximized); + ec->changes.need_unmaximize = 0; + } + + if (ec->need_fullscreen) + { + e_client_fullscreen(ec, e_config->fullscreen_policy); + ec->need_fullscreen = 0; + } + + if (ec->changes.accepts_focus) + { + if ((!ec->icccm.accepts_focus) && (!ec->icccm.take_focus)) + { + if (!ec->focused) + ec->changes.accepts_focus = 0; + } + } + + if (send_event && prop) + { + _e_client_event_property(ec, prop); + } + + _e_client_aux_hint_eval(ec); + + e_client_transform_core_update(ec); + _e_client_hook_call(E_CLIENT_HOOK_EVAL_END, ec); + + TRACE_DS_END(); +} + +static void +_e_client_frame_update(E_Client *ec) +{ + const char *bordername; + + ec->border.changed = 0; + if (!e_comp_object_frame_allowed(ec->frame)) return; + if (ec->fullscreen || ec->borderless) + bordername = "borderless"; + else if (ec->bordername) + bordername = ec->bordername; + else if (ec->mwm.borderless) + bordername = "borderless"; + else if (((ec->icccm.transient_for != 0) || (ec->dialog)) && + (ec->icccm.min_w == ec->icccm.max_w) && + (ec->icccm.min_h == ec->icccm.max_h)) + bordername = "noresize_dialog"; + else if ((ec->icccm.min_w == ec->icccm.max_w) && + (ec->icccm.min_h == ec->icccm.max_h)) + bordername = "noresize"; + else if (ec->shaped) + bordername = "shaped"; + else if (e_pixmap_is_x(ec->pixmap) && + ((!ec->icccm.accepts_focus) && + (!ec->icccm.take_focus))) + bordername = "nofocus"; + else if (ec->urgent) + bordername = "urgent"; + else if (((ec->icccm.transient_for != 0) || (ec->dialog)) && + (e_pixmap_is_x(ec->pixmap))) + bordername = "dialog"; + else if (ec->netwm.state.modal) + bordername = "modal"; + else if ((ec->netwm.state.skip_taskbar) || + (ec->netwm.state.skip_pager)) + bordername = "skipped"; + /* + else if ((ec->internal) && (ec->icccm.class) && + (!strncmp(ec->icccm.class, "e_fwin", 6))) + bordername = "internal_fileman"; + */ + else + bordername = e_config->theme_default_border_style; + if (!bordername) bordername = "default"; + + e_client_border_set(ec, bordername); +} + +static Eina_Bool +_e_client_type_match(E_Client *ec, E_Config_Client_Type *m) +{ + if (!ec || !m) return EINA_FALSE; + if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE; + + if ((int)ec->netwm.type != m->window_type) + return EINA_FALSE; + + if (((m->clas) && (!ec->icccm.class)) || + ((ec->icccm.class) && (m->clas) && (!e_util_glob_match(ec->icccm.class, m->clas)))) + return EINA_FALSE; + + if (((m->name) && (!ec->icccm.name)) || + ((ec->icccm.name) && (m->name) && (!e_util_glob_match(ec->icccm.name, m->name)))) + return EINA_FALSE; + + return EINA_TRUE; +} + +static int +_e_client_type_get(E_Client *ec) +{ + E_Config_Client_Type *m; + Eina_List *l; + int type = 0; + + if (!e_config->client_types) return 0; + + EINA_LIST_FOREACH(e_config->client_types, l, m) + { + if (!_e_client_type_match(ec, m)) continue; + else + { + type = m->client_type; + break; + } + } + + ec->client_type = type; + + return ec->client_type; +} + +static void +_e_client_transform_sub_apply(E_Client *ec, E_Client *epc, double zoom) +{ + E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data; + E_Comp_Wl_Subsurf_Data *sdata = cdata->sub.data; + E_Client *subc; + Eina_List *l; + int px, py; + int ox, oy, ow, oh; + int mx, my, mw, mh; + Evas_Map *map; + + EINA_SAFETY_ON_NULL_RETURN(sdata); + + ox = sdata->position.x; + oy = sdata->position.y; + ow = cdata->width_from_viewport; + oh = cdata->height_from_viewport; + + map = (Evas_Map*)evas_object_map_get(epc->frame); + evas_map_point_coord_get(map, 0, &px, &py, 0); + + mx = ox * zoom + px; + my = oy * zoom + py; + mw = ow * zoom; + mh = oh * zoom; + + map = evas_map_new(4); + evas_map_util_points_populate_from_geometry(map, mx, my, mw, mh, 0); + evas_map_util_object_move_sync_set(map, EINA_TRUE); + evas_object_map_set(ec->frame, map); + evas_object_map_enable_set(ec->frame, EINA_TRUE); + + EINA_LIST_FOREACH(cdata->sub.list, l, subc) + _e_client_transform_sub_apply(subc, ec, zoom); + EINA_LIST_REVERSE_FOREACH(cdata->sub.below_list, l, subc) + _e_client_transform_sub_apply(subc, ec, zoom); + + evas_map_free(map); +} + +static void +_e_client_transient_for_group_make(E_Client *ec, Eina_List **list) +{ + E_Client *child; + Eina_List *l; + + if (!ec) return; + + if (e_config->transient.raise) + { + EINA_LIST_FOREACH(ec->transients, l, child) + { + if (!child) continue; + if (!child->iconic) + { + if (child->transient_policy == E_TRANSIENT_ABOVE) + { + *list = eina_list_prepend(*list, child); + _e_client_transient_for_group_make(child, list); + } + } + } + } +} + +E_API E_Client * +e_client_transient_child_top_get(E_Client *ec, Eina_Bool consider_focus) +{ + E_Client *top_ec = NULL; + Eina_List *transient_list = NULL; + + _e_client_transient_for_group_make(ec, &transient_list); + + if (transient_list) + { + Eina_List *l = NULL; + E_Client *temp_ec = NULL; + E_Client *temp_ec2 = NULL; + + E_CLIENT_REVERSE_FOREACH(temp_ec) + { + if (top_ec) break; + if (temp_ec == ec) + { + top_ec = ec; + break; + } + + EINA_LIST_FOREACH(transient_list, l, temp_ec2) + { + if (temp_ec == temp_ec2) + { + if (consider_focus) + { + if ((temp_ec2->icccm.accepts_focus) || + (temp_ec2->icccm.take_focus)) + { + top_ec = temp_ec2; + } + } + else + { + top_ec = temp_ec2; + } + break; + } + } + } + eina_list_free(transient_list); + } + return top_ec; +} + +#ifdef EC_IS_NOT_VISIBLE +# undef EC_IS_NOT_VISIBLE +#endif +#define EC_IS_NOT_VISIBLE if (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED) + +static Eina_Bool +_e_client_visibility_touched_check(E_Client *ec) +{ + int x, y, w, h; + int tx, ty; + Eina_List *list = NULL, *l; + Eina_Rectangle *data; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); + + tx = wl_fixed_to_int(e_comp->wl_comp_data->ptr.x); + ty = wl_fixed_to_int(e_comp->wl_comp_data->ptr.y); + + e_comp_object_input_rect_get(ec->frame, &list); + if (list) + { + EINA_LIST_FOREACH(list, l, data) + { + if ((tx >= data->x) && (tx <= data->x + data->w) && + (ty >= data->y) && (ty <= data->y + data->h)) + { + return EINA_TRUE; + } + } + list = eina_list_free(list); + } + else + { + e_client_geometry_get(ec, &x, &y, &w, &h); + + if ((tx >= x) && (tx <= x + w) && + (ty >= y) && (ty <= y + h)) + { + return EINA_TRUE; + } + } + + return EINA_FALSE; +} + +static void +_e_client_visibility_zone_calculate(E_Zone *zone) +{ + E_Client *ec; + + Eina_Tiler *t; + Eina_Rectangle r, *_r; + Eina_Iterator *it; + Eina_Bool canvas_vis = EINA_TRUE; + Eina_Bool ec_vis, ec_opaque, calc_region; + Eina_Bool skip_rot_pending_show = EINA_FALSE; + Eina_Bool is_above_rot_pending = EINA_FALSE; + Eina_Bool is_launching_effect = EINA_FALSE; + Eina_Bool is_vis_on_skip = EINA_FALSE; + Eina_Bool is_display_off = EINA_FALSE; + + int x = 0, y = 0, w = 0, h = 0; + const int edge = 1; + E_Comp_Wl_Client_Data *cdata; + Eina_List *changed_list = NULL; + Eina_List *l = NULL; + Eina_Bool effect_running = EINA_FALSE; + Eina_Bool ec_frame_visible = EINA_FALSE; + int calc_skip_type = 0; + + Eina_Bool touched_win_changed = EINA_FALSE; + E_Client *touched_ec; + + if (!e_config->calc_vis_without_effect) + { + if (e_comp->animating) return; + } + + if (!zone) return; + + TRACE_DS_BEGIN(CLIENT:VISIBILITY CALCULATE); + + t = eina_tiler_new(zone->w + edge, zone->h + edge); + eina_tiler_tile_size_set(t, 1, 1); + + if (zone->display_state != E_ZONE_DISPLAY_STATE_OFF) + { + EINA_RECTANGLE_SET(&r, zone->x, zone->y, zone->w, zone->h); + eina_tiler_rect_add(t, &r); + } + else + { + is_display_off = EINA_TRUE; + canvas_vis = EINA_FALSE; + _e_client_hook_call(E_CLIENT_HOOK_CAL_VISIBILITY_DISPLAY_OFF, NULL); + } + + E_CLIENT_REVERSE_FOREACH(ec) + { + calc_skip_type = 0; + if (e_object_is_del(E_OBJECT(ec))) continue; + if (e_client_util_ignored_get(ec)) continue; + if (ec->zone != zone) continue; + if (!ec->frame) continue; + if (ec->visibility.skip) continue; + if (ec->is_cursor) continue; + /* if ec is subsurface, skip this */ + cdata = (E_Comp_Wl_Client_Data *)ec->comp_data; + if (cdata && cdata->sub.data) continue; + if ((!ec->first_mapped) && + (e_comp_object_content_type_get(ec->frame) == E_COMP_OBJECT_CONTENT_TYPE_INT_IMAGE)) continue; + + /* TODO: need to check whether window intersects with entire screen, not zone. */ + /* if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zone->x, zone->y, zone->w, zone->h)) continue; */ + + if (is_display_off) + { + if ((ec->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED) && + (ec->visibility.last_sent_type != E_VISIBILITY_FULLY_OBSCURED)) + { + ec->visibility.changed = 1; + } + } + + if (!e_config->calc_vis_without_effect) + { + if ((e_comp_object_is_animating(ec->frame)) || + (evas_object_data_get(ec->frame, "effect_running"))) + { + effect_running = EINA_TRUE; + if (ec->launching) + is_launching_effect = EINA_TRUE; + continue; + } + } + + e_client_geometry_get(ec, &x, &y, &w, &h); + ec_vis = ec_opaque = skip_rot_pending_show = is_vis_on_skip = EINA_FALSE; + calc_region = EINA_TRUE; + ec_frame_visible = evas_object_visible_get(ec->frame); + + if (!ec->visible) + { + EC_IS_NOT_VISIBLE continue; + calc_region = EINA_FALSE; + calc_skip_type |= 0x01; + } + else if (!ec_frame_visible) + { + if (ec->e.state.rot.pending_show) + { + calc_region = EINA_FALSE; + calc_skip_type |= 0x02; + skip_rot_pending_show = EINA_TRUE; + } + else + { + if (cdata && !cdata->mapped) + { + EC_IS_NOT_VISIBLE continue; + calc_region = EINA_FALSE; + calc_skip_type |= 0x04; + } + + if (!ec->iconic) + { + EC_IS_NOT_VISIBLE continue; + calc_region = EINA_FALSE; + calc_skip_type |= 0x08; + } + else + { + if (ec->exp_iconify.by_client) + { + EC_IS_NOT_VISIBLE continue; + calc_region = EINA_FALSE; + calc_skip_type |= 0x10; + } + } + + if (ec->bg_state) + { + EC_IS_NOT_VISIBLE continue; + calc_region = EINA_FALSE; + calc_skip_type |= 0x20; + } + } + } + + if (canvas_vis) + { + if ((calc_region || skip_rot_pending_show) && + (!ec->visibility.force_obscured) && + (!ec->exp_iconify.by_client)) + { + it = eina_tiler_iterator_new(t); + EINA_ITERATOR_FOREACH(it, _r) + { + if (E_INTERSECTS(x, y, w, h, + _r->x, _r->y, _r->w, _r->h)) + { + ec_vis = EINA_TRUE; + break; + } + } + eina_iterator_free(it); + } + } + + if (ec_vis) + { + /* unobscured case */ + EC_IS_NOT_VISIBLE + { + if ((!is_above_rot_pending) && + ((!effect_running) || + ((effect_running) && (!is_launching_effect)))) + { + /* previous state is obscured: -1 or 1 */ + ec->visibility.obscured = E_VISIBILITY_UNOBSCURED; + ec->visibility.changed = 1; + ELOGF("POL_VIS", "CLIENT VIS ON. argb:%d, opaque:%2d, frame_v:%d", ec, ec->argb, ec->visibility.opaque, ec_frame_visible); + } + else + { + if (!is_above_rot_pending) + is_vis_on_skip = EINA_TRUE; + ELOGF("POL_VIS", "CLIENT VIS ON-SKIP. argb:%d, opaque:%2d, frame_v:%d", ec, ec->argb, ec->visibility.opaque, ec_frame_visible); + } + } + + /* subtract window region from canvas region */ + if (canvas_vis && !skip_rot_pending_show && !is_vis_on_skip) + { + /* check alpha window is opaque or not. */ + if ((ec->visibility.opaque > 0) && (ec->argb)) + ec_opaque = EINA_TRUE; + + /* if e_client is not alpha or opaque then delete intersect rect */ + if (((!ec->argb) || (ec_opaque)) && + (!ec->floating)) + { + EINA_RECTANGLE_SET(&r, + x, + y, + w + edge, + h + edge); + eina_tiler_rect_del(t, &r); + + if (eina_tiler_empty(t)) + canvas_vis = EINA_FALSE; + } + } + } + else + { + /* It prevents unwanted iconification of the top visible window + * while showing an window with rotation mode. + * However, with rotation mode, iconification is done if client + * is iconified by itself. + */ + if ((!skip_rot_pending_show) || + (ec->visibility.force_obscured) || + (ec->bg_state) || + (ec->exp_iconify.by_client)) + { + /* obscured case */ + if (ec->visibility.obscured != E_VISIBILITY_FULLY_OBSCURED) + { + /* previous state is unobscured: -1 or 0 */ + ec->visibility.obscured = E_VISIBILITY_FULLY_OBSCURED; + ec->visibility.changed = 1; + ELOGF("POL_VIS", "CLIENT VIS OFF. argb:%d, opaque:%2d, frame_v:%d, canvas_v:%d, calc_r:%d(%d), rot_p:%d", + ec, ec->argb, ec->visibility.opaque, + ec_frame_visible, canvas_vis, calc_region, calc_skip_type, skip_rot_pending_show); + } + } + } + + if (!is_vis_on_skip) + changed_list = eina_list_append(changed_list, ec); + is_above_rot_pending |= skip_rot_pending_show; + } + + if (changed_list) + { + touched_ec = e_comp_wl->ptr.ec ? e_comp_wl->ptr.ec : e_comp_wl->touch.faked_ec; + EINA_LIST_FOREACH(changed_list, l, ec) + { + if (ec->visibility.changed) + _e_client_event_simple(ec, E_EVENT_CLIENT_VISIBILITY_CHANGE); + + _e_client_hook_call(E_CLIENT_HOOK_EVAL_VISIBILITY, ec); + + if (ec == touched_ec) + touched_win_changed = EINA_TRUE; + + if (ec->visibility.obscured == E_VISIBILITY_UNOBSCURED) + { + if (e_comp_wl->touch.pressed && !touched_win_changed && !e_policy_client_is_keyboard_sub(ec)) + { + if (_e_client_visibility_touched_check(ec)) + { + touched_win_changed = EINA_TRUE; + e_comp_wl_touch_cancel(); + } + } + } + + ec->visibility.changed = 0; + _e_visibility_changed = 1; + } + } + eina_tiler_free(t); + TRACE_DS_END(); +} + +static void +_e_client_merge_focus_stack_with_defer_focus(void) +{ + Eina_List *l = NULL; + E_Client *ec = NULL, *defer_ec = NULL; + Eina_Bool find_rel = EINA_FALSE; + Eina_Bool inserted = EINA_FALSE; + + if (focus_track_frozen > 0) return; + + if (!focus_stack) + { + focus_stack = eina_list_merge(focus_stack, defer_focus_stack); + goto end; + } + + E_CLIENT_REVERSE_FOREACH(defer_ec) + { + if (!eina_list_data_find(defer_focus_stack, defer_ec)) continue; + + find_rel = EINA_FALSE; + inserted = EINA_FALSE; + focus_stack = eina_list_remove(focus_stack, defer_ec); + + EINA_LIST_FOREACH(focus_stack, l, ec) + { + if (ec == NULL) continue; + + if (!find_rel) + { + if (ec == focused) + find_rel = EINA_TRUE; + continue; + } + + if (ec->layer > defer_ec->layer) continue; + + focus_stack = eina_list_prepend_relative_list(focus_stack, defer_ec, l); + inserted = EINA_TRUE; + break; + } + + if (!inserted) + focus_stack = eina_list_append(focus_stack, defer_ec); + } + +end: + defer_focus_stack = eina_list_free(defer_focus_stack); + return; +} + +static void +_e_client_focus_calculate(E_Zone *zone) +{ + E_Client *defered_focus_ec = NULL, *reverted_focus_ec = NULL; + E_Client *ec = NULL; + + EINA_SAFETY_ON_NULL_RETURN(zone); + if (zone->display_state == E_ZONE_DISPLAY_STATE_OFF) return; + + if ((!focused) || + (focused != eina_list_data_get(focus_stack)) || + (!_e_client_focus_can_take(focused))) + { + reverted_focus_ec = _e_client_revert_focus_get(focused); + if (!reverted_focus_ec && focused) + { + e_client_focus_defer_unset(focused); + ELOGF("FOCUS", "focus unset | focus calculate", focused); + evas_object_focus_set(focused->frame, EINA_FALSE); + } + } + + E_CLIENT_REVERSE_FOREACH(ec) + { + if (!eina_list_data_find(defer_focus_stack, ec)) continue; + + if (e_object_is_del(E_OBJECT(ec))) continue; + if (e_client_util_ignored_get(ec)) continue; + if (ec->zone != zone) continue; + if (!e_desk_current_get(ec->zone)) continue; + if (ec->desk != e_desk_current_get(ec->zone)) continue; + + if (!(ec->icccm.accepts_focus || ec->icccm.take_focus)) continue; + if (ec->lock_focus_in || ec->lock_focus_out) continue; + if (!evas_object_visible_get(ec->frame)) continue; + if (ec->iconic) continue; + if (ec->bg_state) continue; + if (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED) continue; + if (_e_client_check_fully_contain_by_above(ec, EINA_FALSE)) continue; + + if (focused && (focused->layer > ec->layer)) continue; + else if (!focused && reverted_focus_ec && (reverted_focus_ec->layer > ec->layer)) continue; + + defered_focus_ec = ec; + break; + } + + if (defered_focus_ec) + { + if (defered_focus_ec != focused) + { + ELOGF("FOCUS", "focus set | defer_focus", defered_focus_ec); + if (focused) + e_client_focus_defer_unset(focused); + evas_object_focus_set(defered_focus_ec->frame, EINA_TRUE); + } + + e_client_focus_defer_unset(defered_focus_ec); + + _e_client_merge_focus_stack_with_defer_focus(); + } + else if(reverted_focus_ec) + { + if (reverted_focus_ec != focused) + { + ELOGF("FOCUS", "focus set | revert_focus", reverted_focus_ec); + if (focused) + e_client_focus_defer_unset(focused); + evas_object_focus_set(reverted_focus_ec->frame, EINA_TRUE); + } + + e_client_focus_defer_unset(reverted_focus_ec); + } + + return; +} + +static Eina_Bool +_e_client_transform_core_check_change(E_Client *ec) +{ + int w = 0; + int h = 0; + Eina_Bool check = EINA_FALSE; + if (!ec) return EINA_FALSE; + + // wait viewport setting + if (!ec->transform_core.transform_list) + { + if (ec->comp_data && ec->comp_data->scaler.viewport) + { + if (!ec->comp_data->sub.below_list && !ec->comp_data->sub.below_list_pending) + { + return EINA_FALSE; + } + } + } + + if (ec->frame) + evas_object_geometry_get(ec->frame, 0, 0, &w, &h); + + if ((ec->transform_core.transform_list) && + (ec->comp_data && ec->comp_data->sub.below_obj)) + { + const Evas_Map *map_ = evas_object_map_get(ec->comp_data->sub.below_obj); + if (!map_) + check = EINA_TRUE; + } + + // check client position or size change + if (ec->x != ec->transform_core.backup.client_x || + ec->y != ec->transform_core.backup.client_y || + ec->w != ec->transform_core.backup.client_w || + ec->h != ec->transform_core.backup.client_h || + w != ec->transform_core.backup.frame_w || + h != ec->transform_core.backup.frame_h) + { + check = EINA_TRUE; + ec->transform_core.backup.client_x = ec->x; + ec->transform_core.backup.client_y = ec->y; + ec->transform_core.backup.client_w = ec->w; + ec->transform_core.backup.client_h = ec->h; + ec->transform_core.backup.frame_w = w; + ec->transform_core.backup.frame_h = h; + } + + // check new transform or del transform + if (ec->transform_core.changed) + { + check = EINA_TRUE; + ec->transform_core.changed = EINA_FALSE; + } + + // check each transform change + if (ec->transform_core.transform_list) + { + Eina_List *l; + Eina_List *l_next; + E_Util_Transform *transform; + + EINA_LIST_FOREACH_SAFE(ec->transform_core.transform_list, l, l_next, transform) + { + // del transform check + if (e_util_transform_ref_count_get(transform) <= 1) + { + ec->transform_core.transform_list = eina_list_remove(ec->transform_core.transform_list, transform); + e_util_transform_unref(transform); + check = EINA_TRUE; + continue; + } + + // transform change test + if (e_util_transform_change_get(transform)) + { + check = EINA_TRUE; + e_util_transform_change_unset(transform); + } + } + } + + // check parent matrix change + if (ec->comp_data) + { + E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data; + + if (cdata->sub.data) + { + E_Client *parent = cdata->sub.data->parent; + + if (parent && parent->transform_core.result.enable) + { + ec->transform_core.parent.enable = EINA_TRUE; + + if (!e_util_transform_matrix_equal_check(&ec->transform_core.parent.matrix, + &parent->transform_core.result.matrix)) + { + check = EINA_TRUE; + ec->transform_core.parent.matrix = parent->transform_core.result.matrix; + } + } + else if (ec->transform_core.parent.enable) + { + ec->transform_core.parent.enable = EINA_FALSE; + e_util_transform_matrix_load_identity(&ec->transform_core.parent.matrix); + check = EINA_TRUE; + } + } + } + + return check; +} + +static void +_e_client_transform_core_boundary_update(E_Client *ec, E_Util_Transform_Rect_Vertex *vertices) +{ + int minx = 99999, miny = 99999; + int maxx = -99999, maxy = -99999; + int x, y; + int i; + + if (!ec) return; + if (!ec->frame) return; + if (!ec->transform_core.result.enable) return; + if (!vertices) return; + + for (i = 0; i < 4; ++i) + { + x = 0; + y = 0; + + e_util_transform_vertices_pos_round_get(vertices, i, &x, &y, 0, 0); + + if (x < minx) minx = x; + if (y < miny) miny = y; + if (x > maxx) maxx = x; + if (y > maxy) maxy = y; + } + + ec->transform_core.result.boundary.x = minx; + ec->transform_core.result.boundary.y = miny; + ec->transform_core.result.boundary.w = maxx - minx; + ec->transform_core.result.boundary.h = maxy - miny; + + ELOGF("COMP", "[Transform][boundary][%d %d %d %d]", + ec, + ec->transform_core.result.boundary.x, + ec->transform_core.result.boundary.y, + ec->transform_core.result.boundary.w, + ec->transform_core.result.boundary.h); +} + +static void +_e_client_transform_core_vertices_apply(E_Client *ec EINA_UNUSED, + Evas_Object *obj, + E_Util_Transform_Rect_Vertex *vertices, + E_Util_Transform *transform) +{ + Evas_Map *map = NULL; + int i; + + if (!obj) return; + + if (vertices) + { + map = evas_map_new(4); + EINA_SAFETY_ON_NULL_RETURN(map); + + evas_map_util_points_populate_from_object_full(map, obj, 0); + evas_map_util_points_color_set(map, 255, 255, 255, 255); + + for (i = 0 ; i < 4 ; ++i) + { + int x = 0; + int y = 0; + + e_util_transform_vertices_pos_round_get(vertices, i, &x, &y, 0, 0); + evas_map_point_coord_set(map, i, x, y, 1.0); + + if (transform && e_util_transform_texcoord_flag_get(transform)) + { + double u = 0.0; + double v = 0.0; + + e_util_transform_texcoord_get(transform, i, &u, &v); + evas_map_point_image_uv_set(map, i, u, v); + } + } + + evas_object_map_set(obj, map); + evas_object_map_enable_set(obj, EINA_TRUE); + + evas_map_free(map); + } + else + evas_object_map_enable_set(obj, EINA_FALSE); +} + +static void +_e_client_transform_core_sub_update(E_Client *ec, E_Util_Transform_Rect_Vertex *vertices) +{ + Eina_List *l; + E_Client *subc; + E_Comp_Wl_Client_Data *cdata; + + if (!ec) return; + if (!ec->comp_data) return; + + cdata = (E_Comp_Wl_Client_Data*)ec->comp_data; + + if (cdata->sub.below_obj) + _e_client_transform_core_vertices_apply(ec, cdata->sub.below_obj, vertices, NULL); + + EINA_LIST_FOREACH(cdata->sub.list, l, subc) + e_client_transform_core_update(subc); + + EINA_LIST_FOREACH(cdata->sub.below_list, l, subc) + e_client_transform_core_update(subc); +} + +static void +_e_client_cb_hook_shell_surface_ready(void *data EINA_UNUSED, E_Client *ec) +{ + if (EINA_UNLIKELY(!ec)) + return; + + _e_client_aux_hint_eval(ec); +} + +E_API void +e_client_visibility_calculate(void) +{ + _e_calc_visibility = EINA_TRUE; +} + +E_API void +e_client_visibility_skip_set(E_Client *ec, Eina_Bool skip) +{ + if (!ec) return; + + ELOGF("POL_VIS", "visibility skip set to %d", ec, skip); + ec->visibility.skip = skip; +} + +E_API void +e_client_post_raise_lower_set(E_Client *ec, Eina_Bool raise_set, Eina_Bool lower_set) +{ + if (!ec) return; + + ec->post_raise = raise_set; + ec->post_lower = lower_set; +} + +E_API Eina_Bool +e_client_first_mapped_get(E_Client *ec) +{ + if (!ec) return EINA_FALSE; + + return ec->first_mapped; +} + +//////////////////////////////////////////////// +EINTERN void +e_client_idler_before(void) +{ + const Eina_List *l; + E_Client *ec; + Eina_Bool exist_clients_hash = EINA_FALSE; + int pix_id; + Eina_Bool check_focus = EINA_FALSE; + + for (pix_id = 0; pix_id < E_PIXMAP_TYPE_MAX; pix_id++) + { + if (eina_hash_population(clients_hash[pix_id])) + { + exist_clients_hash = EINA_TRUE; + break; + } + } + if (!exist_clients_hash) return; + + TRACE_DS_BEGIN(CLIENT:IDLE BEFORE); + + EINA_LIST_FOREACH(e_comp->clients, l, ec) + { + Eina_Stringshare *title; + int client_type; + + // pass 1 - eval0. fetch properties on new or on change and + // call hooks to decide what to do - maybe move/resize + if (ec->ignored || (!ec->changed)) continue; + + if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_FETCH, ec)) continue; + /* FETCH is hooked by the compositor to get client hints */ + title = e_client_util_name_get(ec); + if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_FETCH, ec)) continue; + if (title != e_client_util_name_get(ec)) + _e_client_event_property(ec, E_CLIENT_PROPERTY_TITLE); + + client_type = ec->client_type; + if (client_type != _e_client_type_get(ec)) + _e_client_event_property(ec, E_CLIENT_PROPERTY_CLIENT_TYPE); + + /* PRE_POST_FETCH calls e_remember apply for new client */ + if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_POST_FETCH, ec)) continue; + if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_FETCH, ec)) continue; + if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN, ec)) continue; + + if ((ec->border.changed) && (!ec->shaded) && (!e_client_is_stacking(ec)) && + ((!ec->override) || ec->internal) && + (!(((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)))) + _e_client_frame_update(ec); + ec->border.changed = 0; + _e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_FRAME_ASSIGN, ec); + } + + E_CLIENT_FOREACH(ec) + { + if (ec->ignored) continue; + // pass 2 - show windows needing show + if ((ec->changes.visible) && (ec->visible) && + (!ec->new_client) && (!ec->changes.pos) && + (!ec->changes.size)) + { + evas_object_show(ec->frame); + ec->changes.visible = !evas_object_visible_get(ec->frame); + } + + if ((!ec->new_client) && (!e_client_util_ignored_get(ec)) && + (!E_INSIDE(ec->x, ec->y, 0, 0, e_comp->w - 5, e_comp->h - 5)) && + (!E_INSIDE(ec->x, ec->y, 0 - ec->w + 5, 0 - ec->h + 5, e_comp->w - 5, e_comp->h - 5)) + ) + { + if (e_config->screen_limits != E_CLIENT_OFFSCREEN_LIMIT_ALLOW_FULL) + _e_client_move_lost_window_to_center(ec); + } + } + + if (_e_client_layout_cb) + _e_client_layout_cb(); + + // pass 3 - hide windows needing hide and eval (main eval) + E_CLIENT_FOREACH(ec) + { + if (ec->ignored || e_object_is_del(E_OBJECT(ec))) continue; + + if ((ec->changes.visible) && (!ec->visible)) + { + evas_object_hide(ec->frame); + ec->changes.visible = 0; + } + + if (ec->changed) + { + _e_client_eval(ec); + e_client_visibility_calculate(); + if (ec->changes.accepts_focus) + check_focus = EINA_TRUE; + ec->changes.accepts_focus = 0; + } + + if ((ec->changes.visible) && (ec->visible) && (!ec->changed)) + { + evas_object_show(ec->frame); + ec->changes.visible = !evas_object_visible_get(ec->frame); + ec->changed = ec->changes.visible; + e_client_visibility_calculate(); + } + } + + if (e_comp_canvas_norender_get() <= 0) + { + E_Zone *zone; + Eina_List *zl; + EINA_LIST_FOREACH(e_comp->zones, zl, zone) + { + if (_e_calc_visibility) + _e_client_visibility_zone_calculate(zone); + if (check_focus || + (focused == NULL) || + (_e_calc_visibility && (defer_focus_stack != NULL)) || + (_e_visibility_changed)) + { + _e_client_focus_calculate(zone); + } + } + _e_calc_visibility = EINA_FALSE; + _e_visibility_changed = 0; + } + + + TRACE_DS_END(); +} + + +EINTERN Eina_Bool +e_client_init(void) +{ + int pix_id; + for (pix_id = 0; pix_id < E_PIXMAP_TYPE_MAX; pix_id++) + clients_hash[pix_id] = eina_hash_pointer_new(NULL); + + E_LIST_HANDLER_APPEND(handlers, E_EVENT_POINTER_WARP, _e_client_cb_pointer_warp, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_MODE_CHANGED, _e_client_cb_config_mode, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_DESK_WINDOW_PROFILE_CHANGE, _e_client_cb_desk_window_profile_change, NULL); + + E_COMP_WL_HOOK_APPEND(hooks, E_COMP_WL_HOOK_SHELL_SURFACE_READY, _e_client_cb_hook_shell_surface_ready, NULL); + + E_EVENT_CLIENT_ADD = ecore_event_type_new(); + E_EVENT_CLIENT_REMOVE = ecore_event_type_new(); + E_EVENT_CLIENT_DESK_SET = ecore_event_type_new(); + E_EVENT_CLIENT_ZONE_SET = ecore_event_type_new(); + E_EVENT_CLIENT_RESIZE = ecore_event_type_new(); + E_EVENT_CLIENT_MOVE = ecore_event_type_new(); + E_EVENT_CLIENT_SHOW = ecore_event_type_new(); + E_EVENT_CLIENT_HIDE = ecore_event_type_new(); + E_EVENT_CLIENT_ICONIFY = ecore_event_type_new(); + E_EVENT_CLIENT_UNICONIFY = ecore_event_type_new(); + E_EVENT_CLIENT_STACK = ecore_event_type_new(); + E_EVENT_CLIENT_FOCUS_IN = ecore_event_type_new(); + E_EVENT_CLIENT_FOCUS_OUT = ecore_event_type_new(); + E_EVENT_CLIENT_PROPERTY = ecore_event_type_new(); + E_EVENT_CLIENT_FULLSCREEN = ecore_event_type_new(); + E_EVENT_CLIENT_UNFULLSCREEN = ecore_event_type_new(); +#ifdef _F_ZONE_WINDOW_ROTATION_ + E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN = ecore_event_type_new(); + E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL = ecore_event_type_new(); + E_EVENT_CLIENT_ROTATION_CHANGE_END = ecore_event_type_new(); +#endif + E_EVENT_CLIENT_VISIBILITY_CHANGE = ecore_event_type_new(); + E_EVENT_CLIENT_BUFFER_CHANGE = ecore_event_type_new(); + + return (!!clients_hash[1]); +} + +EINTERN void +e_client_shutdown(void) +{ + int pix_id; + for (pix_id = 0; pix_id < E_PIXMAP_TYPE_MAX; pix_id++) + E_FREE_FUNC(clients_hash[pix_id], eina_hash_free); + + E_FREE_LIST(hooks, e_comp_wl_hook_del); + E_FREE_LIST(handlers, ecore_event_handler_del); + + E_FREE_FUNC(warp_timer, ecore_timer_del); + warp_client = NULL; +} + +E_API void +e_client_unignore(E_Client *ec) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->ignored) return; + + ec->ignored = 0; + _e_client_event_add(ec); +} + +E_API E_Client * +e_client_new(E_Pixmap *cp, int first_map, int internal) +{ + E_Client *ec; + E_Pixmap_Type type; + + type = e_pixmap_type_get(cp); + if (type >= E_PIXMAP_TYPE_MAX) return NULL; + if (eina_hash_find(clients_hash[type], &cp)) return NULL; + + ec = E_OBJECT_ALLOC(E_Client, E_CLIENT_TYPE, _e_client_free); + if (!ec) return NULL; + e_object_del_func_set(E_OBJECT(ec), E_OBJECT_CLEANUP_FUNC(_e_client_del)); + + uuid_generate(ec->uuid); + + ec->focus_policy_override = E_FOCUS_LAST; + ec->w = 1; + ec->h = 1; + ec->internal = internal; + + ec->pixmap = cp; + e_pixmap_client_set(cp, ec); + ec->resize_mode = E_POINTER_RESIZE_NONE; + ec->layer = E_LAYER_CLIENT_NORMAL; + ec->first_mapped = EINA_FALSE; + ec->post_raise = EINA_TRUE; + ec->post_lower = EINA_FALSE; + ec->animatable = EINA_TRUE; + + /* FIXME: if first_map is 1 then we should ignore the first hide event + * or ensure the window is already hidden and events flushed before we + * create a border for it */ + if (first_map) + { + ec->changes.pos = 1; + ec->re_manage = 1; + // needed to be 1 for internal windw and on restart. + // ec->ignore_first_unmap = 2; + } + ec->offer_resistance = 1; + ec->new_client = 1; + e_comp->new_clients++; + + ec->exp_iconify.by_client = 0; + ec->exp_iconify.not_raise = 0; + ec->exp_iconify.skip_iconify = 0; + ec->exp_iconify.skip_by_remote = 0; + if (e_config->deiconify_approve) + ec->exp_iconify.deiconify_update= 1; + else + ec->exp_iconify.deiconify_update= 0; + if (e_config->use_buffer_flush) + ec->exp_iconify.buffer_flush = 1; + else + ec->exp_iconify.buffer_flush = 0; + + if (!_e_client_hook_call(E_CLIENT_HOOK_NEW_CLIENT, ec)) + { + /* delete the above allocated object */ + //e_object_del(E_OBJECT(ec)); + return NULL; + } + + _e_client_aux_hint_eval(ec); + + if (ec->override) + _e_client_zone_update(ec); + else + e_client_desk_set(ec, e_desk_current_get(e_zone_current_get())); + + ec->icccm.title = NULL; + ec->icccm.name = NULL; + ec->icccm.class = NULL; + ec->icccm.icon_name = NULL; + ec->icccm.machine = NULL; + ec->icccm.min_w = 1; + ec->icccm.min_h = 1; + ec->icccm.max_w = 32767; + ec->icccm.max_h = 32767; + ec->icccm.base_w = 0; + ec->icccm.base_h = 0; + ec->icccm.step_w = -1; + ec->icccm.step_h = -1; + ec->icccm.min_aspect = 0.0; + ec->icccm.max_aspect = 0.0; + + ec->netwm.pid = 0; + ec->netwm.name = NULL; + ec->netwm.icon_name = NULL; + ec->netwm.desktop = 0; + ec->netwm.state.modal = 0; + ec->netwm.state.sticky = 0; + ec->netwm.state.shaded = 0; + ec->netwm.state.hidden = 0; + ec->netwm.state.maximized_v = 0; + ec->netwm.state.maximized_h = 0; + ec->netwm.state.skip_taskbar = 0; + ec->netwm.state.skip_pager = 0; + ec->netwm.state.fullscreen = 0; + ec->netwm.state.stacking = E_STACKING_NONE; + ec->netwm.action.move = 0; + ec->netwm.action.resize = 0; + ec->netwm.action.minimize = 0; + ec->netwm.action.shade = 0; + ec->netwm.action.stick = 0; + ec->netwm.action.maximized_h = 0; + ec->netwm.action.maximized_v = 0; + ec->netwm.action.fullscreen = 0; + ec->netwm.action.change_desktop = 0; + ec->netwm.action.close = 0; + ec->netwm.opacity = 255; + + ec->visibility.obscured = E_VISIBILITY_UNKNOWN; + ec->visibility.opaque = -1; + ec->visibility.changed = 0; + ec->visibility.skip = 0; + ec->visibility.last_sent_type = E_VISIBILITY_UNKNOWN; + + ec->transform.zoom = 1.0; + ec->transform.angle = 0.0; + + ec->pointer_enter_sent = EINA_FALSE; + + EC_CHANGED(ec); + + e_comp->clients = eina_list_append(e_comp->clients, ec); + eina_hash_add(clients_hash[e_pixmap_type_get(cp)], &ec->pixmap, ec); + + ELOGF("COMP", "CLIENT ADD. cp:%p", ec, cp); + if (!ec->ignored) + _e_client_event_add(ec); + e_comp_object_client_add(ec); + if (ec->frame) + { + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW, _e_client_cb_evas_show, ec); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE, _e_client_cb_evas_hide, ec); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE, _e_client_cb_evas_move, ec); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESIZE, _e_client_cb_evas_resize, ec); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESTACK, _e_client_cb_evas_restack, ec); + evas_object_smart_callback_add(ec->frame, "shade_done", _e_client_cb_evas_shade_done, ec); + if (ec->override) + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_ABOVE); + else + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NORMAL); + } + +#ifdef _F_E_CLIENT_NEW_CLIENT_POST_HOOK_ + _e_client_hook_call(E_CLIENT_HOOK_NEW_CLIENT_POST, ec); +#endif + + return ec; +} + +E_API Eina_Bool +e_client_desk_window_profile_available_check(E_Client *ec, const char *profile) +{ + int i; + + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(ec->e.state.profile.use, EINA_FALSE); + if (ec->e.state.profile.num == 0) return EINA_TRUE; + + for (i = 0; i < ec->e.state.profile.num; i++) + { + if (!e_util_strcmp(ec->e.state.profile.available_list[i], + profile)) + return EINA_TRUE; + } + + return EINA_FALSE; +} + +E_API void +e_client_desk_window_profile_wait_desk_set(E_Client *ec, E_Desk *desk) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + E_OBJECT_CHECK(desk); + E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE); + + if (ec->e.state.profile.wait_desk == desk) return; + + if (ec->e.state.profile.wait_desk_delfn) + { + if (ec->e.state.profile.wait_desk) + e_object_delfn_del(E_OBJECT(ec->e.state.profile.wait_desk), + ec->e.state.profile.wait_desk_delfn); + ec->e.state.profile.wait_desk_delfn = NULL; + } + + if (ec->e.state.profile.wait_desk) + e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk)); + ec->e.state.profile.wait_desk = NULL; + + if (desk) + { + ec->e.state.profile.wait_desk_delfn = + e_object_delfn_add(E_OBJECT(desk), + _e_client_desk_window_profile_wait_desk_delfn, + ec); + } + ec->e.state.profile.wait_desk = desk; + if (ec->e.state.profile.wait_desk) + e_object_ref(E_OBJECT(ec->e.state.profile.wait_desk)); +} + +E_API void +e_client_desk_set(E_Client *ec, E_Desk *desk) +{ + E_Event_Client_Desk_Set *ev; + E_Desk *old_desk; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + E_OBJECT_CHECK(desk); + E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE); + if (ec->desk == desk) return; + if ((e_config->use_desktop_window_profile) && + (ec->e.state.profile.use)) + { + if (e_util_strcmp(ec->e.state.profile.name, desk->window_profile)) + { + if (e_client_desk_window_profile_available_check(ec, desk->window_profile)) + { + eina_stringshare_replace(&ec->e.state.profile.set, desk->window_profile); + eina_stringshare_replace(&ec->e.state.profile.wait, NULL); + ec->e.state.profile.wait_for_done = 0; + e_client_desk_window_profile_wait_desk_set(ec, desk); + EC_CHANGED(ec); + } + } + } + + if (ec->fullscreen) + { + ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec); + desk->fullscreen_clients = eina_list_append(desk->fullscreen_clients, ec); + } + old_desk = ec->desk; + if (old_desk) + e_desk_client_del(old_desk, ec); + ec->desk = desk; + e_desk_client_add(desk, ec); + e_comp_object_effect_unclip(ec->frame); + e_comp_object_effect_set(ec->frame, NULL); + if (desk->visible || ec->sticky) + { + if ((!ec->hidden) && (!ec->iconic)) + evas_object_show(ec->frame); + } + else + { + ec->hidden = 1; + evas_object_hide(ec->frame); + } + e_client_comp_hidden_set(ec, (!desk->visible) && (!ec->sticky)); + e_client_zone_set(ec, desk->zone); + + e_hints_window_desktop_set(ec); + + if (old_desk) + { + ev = E_NEW(E_Event_Client_Desk_Set, 1); + if (ev) + { + ev->ec = ec; + UNREFD(ec, 4); + e_object_ref(E_OBJECT(ec)); + ev->desk = old_desk; + e_object_ref(E_OBJECT(old_desk)); + ecore_event_add(E_EVENT_CLIENT_DESK_SET, ev, (Ecore_End_Cb)_e_client_event_desk_set_free, NULL); + } + + if (old_desk->zone == ec->zone) + { + e_client_res_change_geometry_save(ec); + e_client_res_change_geometry_restore(ec); + ec->pre_res_change.valid = 0; + } + } + + if (e_config->transient.desktop) + { + E_Client *child; + const Eina_List *l; + + EINA_LIST_FOREACH(ec->transients, l, child) + e_client_desk_set(child, ec->desk); + } + + _e_client_hook_call(E_CLIENT_HOOK_DESK_SET, ec); + evas_object_smart_callback_call(ec->frame, "desk_change", ec); +} + +E_API Eina_Bool +e_client_comp_grabbed_get(void) +{ + return comp_grabbed; +} + +E_API E_Client * +e_client_action_get(void) +{ + return action_client; +} + +E_API E_Client * +e_client_warping_get(void) +{ + return warp_client; +} + + +E_API Eina_List * +e_clients_immortal_list(void) +{ + const Eina_List *l; + Eina_List *list = NULL; + E_Client *ec; + + EINA_LIST_FOREACH(e_comp->clients, l, ec) + { + if (ec->lock_life) + list = eina_list_append(list, ec); + } + return list; +} + +////////////////////////////////////////////////////////// + +E_API void +e_client_mouse_in(E_Client *ec, int x, int y) +{ + if (comp_grabbed) return; + if (warp_client && (ec != warp_client)) return; + if (e_object_is_del(E_OBJECT(ec))) return; + if (ec->desk && ec->desk->animate_count) return; + ec->mouse.current.mx = x; + ec->mouse.current.my = y; + ec->mouse.in = 1; + if ((!ec->iconic) && (!e_client_util_ignored_get(ec))) + e_focus_event_mouse_in(ec); +} + +E_API void +e_client_mouse_out(E_Client *ec, int x, int y) +{ + if (comp_grabbed) return; + if (ec->fullscreen) return; + if (e_object_is_del(E_OBJECT(ec))) return; + if (ec->desk && ec->desk->animate_count) return; + if (e_pixmap_is_x(ec->pixmap) && E_INSIDE(x, y, ec->x, ec->y, ec->w, ec->h)) return; + + ec->mouse.current.mx = x; + ec->mouse.current.my = y; + ec->mouse.in = 0; + if ((!ec->iconic) && (!e_client_util_ignored_get(ec))) + e_focus_event_mouse_out(ec); +} + +E_API void +e_client_mouse_wheel(E_Client *ec, Evas_Point *output, E_Binding_Event_Wheel *ev) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (action_client) return; + ec->mouse.current.mx = output->x; + ec->mouse.current.my = output->y; +} + +E_API void +e_client_mouse_down(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button *ev) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (action_client || ec->iconic || e_client_util_ignored_get(ec)) return; + if ((button >= 1) && (button <= 3)) + { + ec->mouse.last_down[button - 1].mx = output->x; + ec->mouse.last_down[button - 1].my = output->y; + ec->mouse.last_down[button - 1].x = ec->x; + ec->mouse.last_down[button - 1].y = ec->y; + ec->mouse.last_down[button - 1].w = ec->w; + ec->mouse.last_down[button - 1].h = ec->h; + } + else + { + ec->moveinfo.down.x = ec->x; + ec->moveinfo.down.y = ec->y; + ec->moveinfo.down.w = ec->w; + ec->moveinfo.down.h = ec->h; + } + ec->mouse.current.mx = output->x; + ec->mouse.current.my = output->y; + if ((button >= 1) && (button <= 3)) + { + ec->mouse.last_down[button - 1].mx = output->x; + ec->mouse.last_down[button - 1].my = output->y; + ec->mouse.last_down[button - 1].x = ec->x; + ec->mouse.last_down[button - 1].y = ec->y; + ec->mouse.last_down[button - 1].w = ec->w; + ec->mouse.last_down[button - 1].h = ec->h; + } + else + { + ec->moveinfo.down.x = ec->x; + ec->moveinfo.down.y = ec->y; + ec->moveinfo.down.w = ec->w; + ec->moveinfo.down.h = ec->h; + } + ec->mouse.current.mx = output->x; + ec->mouse.current.my = output->y; +} + +E_API void +e_client_mouse_up(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button* ev) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (ec->iconic || e_client_util_ignored_get(ec)) return; + if ((button >= 1) && (button <= 3)) + { + ec->mouse.last_up[button - 1].mx = output->x; + ec->mouse.last_up[button - 1].my = output->y; + ec->mouse.last_up[button - 1].x = ec->x; + ec->mouse.last_up[button - 1].y = ec->y; + } + ec->mouse.current.mx = output->x; + ec->mouse.current.my = output->y; + /* also we don't pass the same params that went in - then again that */ + /* should be ok as we are just ending the action if it has an end */ + if (ec->cur_mouse_action) + { + if (ec->cur_mouse_action->func.end_mouse) + ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", ev); + else if (ec->cur_mouse_action->func.end) + ec->cur_mouse_action->func.end(E_OBJECT(ec), ""); + e_object_unref(E_OBJECT(ec->cur_mouse_action)); + ec->cur_mouse_action = NULL; + } + else + { + e_focus_event_mouse_up(ec); + } + if ((button >= 1) && (button <= 3)) + { + ec->mouse.last_up[button - 1].mx = output->x; + ec->mouse.last_up[button - 1].my = output->y; + ec->mouse.last_up[button - 1].x = ec->x; + ec->mouse.last_up[button - 1].y = ec->y; + } + + ec->drag.start = 0; +} + +E_API void +e_client_stay_within_canvas_margin(E_Client *ec) +{ + int new_x = ec->x; + int new_y = ec->y; + + if (ec->floating) + { + _e_client_stay_within_canvas_margin(ec, ec->x, ec->y, &new_x, &new_y); + + if ((ec->x != new_x) || (ec->y != new_y)) + evas_object_move(ec->frame, new_x, new_y); + } +} + +E_API void +e_client_mouse_move(E_Client *ec, Evas_Point *output) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (ec->iconic || e_client_util_ignored_get(ec)) return; + ec->mouse.current.mx = output->x; + ec->mouse.current.my = output->y; + if (ec->moving) + { + int x, y, new_x, new_y; + int new_w, new_h; + Eina_List *skiplist = NULL; + + if (action_handler_key) return; + if ((ec->moveinfo.down.button >= 1) && (ec->moveinfo.down.button <= 3)) + { + x = ec->mouse.last_down[ec->moveinfo.down.button - 1].x + + (ec->mouse.current.mx - ec->moveinfo.down.mx); + y = ec->mouse.last_down[ec->moveinfo.down.button - 1].y + + (ec->mouse.current.my - ec->moveinfo.down.my); + } + else + { + x = ec->moveinfo.down.x + + (ec->mouse.current.mx - ec->moveinfo.down.mx); + y = ec->moveinfo.down.y + + (ec->mouse.current.my - ec->moveinfo.down.my); + } + e_comp_object_frame_xy_adjust(ec->frame, x, y, &new_x, &new_y); + + skiplist = eina_list_append(skiplist, ec); + e_resist_client_position(skiplist, + ec->x, ec->y, ec->w, ec->h, + x, y, ec->w, ec->h, + &new_x, &new_y, &new_w, &new_h); + eina_list_free(skiplist); + + if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE) + _e_client_stay_within_canvas(ec, x, y, &new_x, &new_y); + + if (ec->floating) + _e_client_stay_within_canvas_margin(ec, x, y, &new_x, &new_y); + + ec->shelf_fix.x = 0; + ec->shelf_fix.y = 0; + ec->shelf_fix.modified = 0; + evas_object_move(ec->frame, new_x, new_y); + if (ec->zone) e_zone_flip_coords_handle(ec->zone, output->x, output->y); + } + else if (e_client_util_resizing_get(ec)) + { + if (action_handler_key) return; + _e_client_resize_handle(ec); + } + else if (ec->drag.start) + { + if ((ec->drag.x == -1) && (ec->drag.y == -1)) + { + ec->drag.x = output->x; + ec->drag.y = output->y; + } + else if (ec->zone) + { + int dx, dy; + + dx = ec->drag.x - output->x; + dy = ec->drag.y - output->y; + if (((dx * dx) + (dy * dy)) > (16 * 16)) + { + /* start drag! */ + if (ec->netwm.icons || ec->internal_icon) + { + Evas_Object *o = NULL; + int x = 0, y = 0, w = 0, h = 0; + const char *drag_types[] = { "enlightenment/border" }; + + REFD(ec, 1); + e_object_ref(E_OBJECT(ec)); + + client_drag = e_drag_new(output->x, output->y, + drag_types, 1, ec, -1, + NULL, + _e_client_cb_drag_finished); + client_drag->button_mask = evas_pointer_button_down_mask_get(e_comp->evas); + e_drag_resize(client_drag, w, h); + + /* FIXME: fallback icon for drag */ + o = evas_object_rectangle_add(client_drag->evas); + evas_object_color_set(o, 255, 255, 255, 255); + + e_drag_object_set(client_drag, o); + e_drag_start(client_drag, + output->x + (ec->drag.x - x), + output->y + (ec->drag.y - y)); + } + ec->drag.start = 0; + } + } + } +} +/////////////////////////////////////////////////////// + +E_API void +e_client_res_change_geometry_save(E_Client *ec) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + if (ec->pre_res_change.valid) return; + ec->pre_res_change.valid = 1; + ec->pre_res_change.x = ec->x; + ec->pre_res_change.y = ec->y; + ec->pre_res_change.w = ec->w; + ec->pre_res_change.h = ec->h; + ec->pre_res_change.saved.x = ec->saved.x; + ec->pre_res_change.saved.y = ec->saved.y; + ec->pre_res_change.saved.w = ec->saved.w; + ec->pre_res_change.saved.h = ec->saved.h; +} + +E_API void +e_client_res_change_geometry_restore(E_Client *ec) +{ + struct + { + unsigned char valid : 1; + int x, y, w, h; + struct + { + int x, y, w, h; + } saved; + } pre_res_change; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->pre_res_change.valid) return; + if (ec->new_client) return; + if (!ec->zone) return; + + memcpy(&pre_res_change, &ec->pre_res_change, sizeof(pre_res_change)); + + if (ec->fullscreen) + { + e_client_unfullscreen(ec); + e_client_fullscreen(ec, e_config->fullscreen_policy); + } + else if (ec->maximized != E_MAXIMIZE_NONE) + { + E_Maximize max; + + max = ec->maximized; + e_client_unmaximize(ec, E_MAXIMIZE_BOTH); + e_client_maximize(ec, max); + } + else + { + int x, y, w, h, zx, zy, zw, zh; + + ec->saved.x = ec->pre_res_change.saved.x; + ec->saved.y = ec->pre_res_change.saved.y; + ec->saved.w = ec->pre_res_change.saved.w; + ec->saved.h = ec->pre_res_change.saved.h; + + e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh); + + if (ec->saved.w > zw) + ec->saved.w = zw; + if ((ec->saved.x + ec->saved.w) > (zx + zw)) + ec->saved.x = zx + zw - ec->saved.w; + + if (ec->saved.h > zh) + ec->saved.h = zh; + if ((ec->saved.y + ec->saved.h) > (zy + zh)) + ec->saved.y = zy + zh - ec->saved.h; + + x = ec->pre_res_change.x; + y = ec->pre_res_change.y; + w = ec->pre_res_change.w; + h = ec->pre_res_change.h; + if (w > zw) + w = zw; + if (h > zh) + h = zh; + if ((x + w) > (zx + zw)) + x = zx + zw - w; + if ((y + h) > (zy + zh)) + y = zy + zh - h; + evas_object_geometry_set(ec->frame, x, y, w, h); + } + memcpy(&ec->pre_res_change, &pre_res_change, sizeof(pre_res_change)); +} + +E_API void +e_client_zone_set(E_Client *ec, E_Zone *zone) +{ + E_Event_Client_Zone_Set *ev; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + E_OBJECT_CHECK(zone); + E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); + if (ec->zone == zone) return; + + ev = E_NEW(E_Event_Client_Zone_Set, 1); + if (!ev) return; + + /* if the window does not lie in the new zone, move it so that it does */ + if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zone->x, zone->y, zone->w, zone->h)) + { + int x, y; + + if (ec->zone) + { + /* first guess -- get offset from old zone, and apply to new zone */ + x = zone->x + (ec->x - ec->zone->x); + y = zone->y + (ec->y - ec->zone->y); + } + else + x = ec->x, y = ec->y; + + /* keep window from hanging off bottom and left */ + if (x + ec->w > zone->x + zone->w) x += (zone->x + zone->w) - (x + ec->w); + if (y + ec->h > zone->y + zone->h) y += (zone->y + zone->h) - (y + ec->h); + + /* make sure to and left are on screen (if the window is larger than the zone, it will hang off the bottom / right) */ + if (x < zone->x) x = zone->x; + if (y < zone->y) y = zone->y; + + if (!E_INTERSECTS(x, y, ec->w, ec->h, zone->x, zone->y, zone->w, zone->h)) + { + /* still not in zone at all, so just move it to closest edge */ + if (x < zone->x) x = zone->x; + if (x >= zone->x + zone->w) x = zone->x + zone->w - ec->w; + if (y < zone->y) y = zone->y; + if (y >= zone->y + zone->h) y = zone->y + zone->h - ec->h; + } + evas_object_move(ec->frame, x, y); + } + + ec->zone = zone; + + if ((!ec->desk) || (ec->desk->zone != ec->zone)) + e_client_desk_set(ec, e_desk_current_get(ec->zone)); + + ev->ec = ec; + REFD(ec, 5); + e_object_ref(E_OBJECT(ec)); + ev->zone = zone; + e_object_ref(E_OBJECT(zone)); + + ecore_event_add(E_EVENT_CLIENT_ZONE_SET, ev, (Ecore_End_Cb)_e_client_event_zone_set_free, NULL); + + e_client_res_change_geometry_save(ec); + e_client_res_change_geometry_restore(ec); + ec->pre_res_change.valid = 0; +} + +E_API void +e_client_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h) +{ + int gx = 0; + int gy = 0; + int gw = 0; + int gh = 0; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + if (e_client_transform_core_enable_get(ec)) + { + gx = ec->transform_core.result.boundary.x; + gy = ec->transform_core.result.boundary.y; + gw = ec->transform_core.result.boundary.w; + gh = ec->transform_core.result.boundary.h; + } + else + { + if (ec->frame) + { + evas_object_geometry_get(ec->frame, &gx, &gy, &gw, &gh); + if (gw == 0 && gh == 0) + { + /* In this case, there is no image buffer in e_comp_object, thus it + * should return geometry value of ec itself. It usually happens if + * new ec is not mapped yet. + */ + gw = ec->w; + gh = ec->h; + + if ((ec->changes.pos) && + ((gx != ec->x) || (gy != ec->y))) + { + gx = ec->x; + gy = ec->y; + } + } + } + else + { + gx = ec->x; + gy = ec->y; + gw = ec->w; + gh = ec->h; + } + } + + if (x) *x = gx; + if (y) *y = gy; + if (w) *w = gw; + if (h) *h = gh; +} + +E_API E_Client * +e_client_above_get(const E_Client *ec) +{ + unsigned int x; + E_Client *ec2; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL); + if (EINA_INLIST_GET(ec)->next) //check current layer + { + EINA_INLIST_FOREACH(EINA_INLIST_GET(ec)->next, ec2) + { + if (ec == ec2) + { + ELOGF("FATAL", "CHECK the ec inlist next", ec); + continue; + } + if (!e_object_is_del(E_OBJECT(ec2))) + return ec2; + } + } + if (ec->layer == E_LAYER_CLIENT_CURSOR) return NULL; + if (e_comp_canvas_client_layer_map(ec->layer) == 9999) return NULL; + + /* go up the layers until we find one */ + for (x = e_comp_canvas_layer_map(ec->layer) + 1; x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_CURSOR); x++) + { + if (!e_comp->layers[x].clients) continue; + EINA_INLIST_FOREACH(e_comp->layers[x].clients, ec2) + { + if (ec == ec2) + { + ELOGF("FATAL", "EC exist above layer. ec layer_map:%d, cur layer_map:%d", + ec, e_comp_canvas_layer_map(ec->layer), x); + continue; + } + if (!e_object_is_del(E_OBJECT(ec2))) + return ec2; + } + } + return NULL; +} + +E_API E_Client * +e_client_below_get(const E_Client *ec) +{ + unsigned int x; + E_Client *ec2; + Eina_Inlist *l; + + E_OBJECT_CHECK_RETURN(ec, NULL); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL); + + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL); + if (EINA_INLIST_GET(ec)->prev) //check current layer + { + for (l = EINA_INLIST_GET(ec)->prev; l; l = l->prev) + { + ec2 = EINA_INLIST_CONTAINER_GET(l, E_Client); + if (ec == ec2) + { + ELOGF("FATAL", "CHECK the ec inlist prev", ec); + continue; + } + if (!e_object_is_del(E_OBJECT(ec2))) + return ec2; + } + } + + if (ec->layer == E_LAYER_CLIENT_DESKTOP) return NULL; + if (e_comp_canvas_client_layer_map(ec->layer) == 9999) return NULL; + + /* go down the layers until we find one */ + x = e_comp_canvas_layer_map(ec->layer); + if (x > 0) x--; + + for (; x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--) + { + if (!e_comp->layers[x].clients) continue; + EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2) + { + if (ec == ec2) + { + ELOGF("FATAL", "EC exist below layer. ec layer_map:%d, cur layer_map:%d", + ec, e_comp_canvas_layer_map(ec->layer), x); + continue; + } + if (!e_object_is_del(E_OBJECT(ec2))) + return ec2; + } + } + return NULL; +} + +E_API E_Client * +e_client_bottom_get(void) +{ + unsigned int x; + for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_CURSOR); x++) + { + E_Client *ec2; + + if (!e_comp->layers[x].clients) continue; + EINA_INLIST_FOREACH(e_comp->layers[x].clients, ec2) + if (!e_object_is_del(E_OBJECT(ec2))) + return ec2; + } + return NULL; +} + +E_API E_Client * +e_client_top_get(void) +{ + unsigned int x; + for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_CURSOR); x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--) + { + E_Client *ec2; + + if (!e_comp->layers[x].clients) continue; + EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2) + if (!e_object_is_del(E_OBJECT(ec2))) + return ec2; + } + return NULL; +} + +E_API unsigned int +e_clients_count(void) +{ + return eina_list_count(e_comp->clients); +} + + +/** + * Set a callback which will be called just prior to updating the + * move coordinates for a border + */ +E_API void +e_client_move_intercept_cb_set(E_Client *ec, E_Client_Move_Intercept_Cb cb) +{ + ec->move_intercept_cb = cb; +} + +/////////////////////////////////////// + +E_API E_Client_Hook * +e_client_hook_add(E_Client_Hook_Point hookpoint, E_Client_Hook_Cb func, const void *data) +{ + E_Client_Hook *ch; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_CLIENT_HOOK_LAST, NULL); + ch = E_NEW(E_Client_Hook, 1); + if (!ch) return NULL; + ch->hookpoint = hookpoint; + ch->func = func; + ch->data = (void*)data; + _e_client_hooks[hookpoint] = eina_inlist_append(_e_client_hooks[hookpoint], EINA_INLIST_GET(ch)); + return ch; +} + +E_API void +e_client_hook_del(E_Client_Hook *ch) +{ + ch->delete_me = 1; + if (_e_client_hooks_walking == 0) + { + _e_client_hooks[ch->hookpoint] = eina_inlist_remove(_e_client_hooks[ch->hookpoint], EINA_INLIST_GET(ch)); + free(ch); + } + else + _e_client_hooks_delete++; +} + +/////////////////////////////////////// + +E_API E_Client_Intercept_Hook * +e_client_intercept_hook_add(E_Client_Intercept_Hook_Point hookpoint, E_Client_Intercept_Hook_Cb func, const void *data) +{ + E_Client_Intercept_Hook *ch; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_CLIENT_INTERCEPT_HOOK_LAST, NULL); + ch = E_NEW(E_Client_Intercept_Hook, 1); + if (!ch) return NULL; + ch->hookpoint = hookpoint; + ch->func = func; + ch->data = (void*)data; + _e_client_intercept_hooks[hookpoint] = eina_inlist_append(_e_client_intercept_hooks[hookpoint], EINA_INLIST_GET(ch)); + return ch; +} + +E_API void +e_client_intercept_hook_del(E_Client_Intercept_Hook *ch) +{ + if (!ch) return; + + ch->delete_me = 1; + if (_e_client_intercept_hooks_walking == 0) + { + _e_client_intercept_hooks[ch->hookpoint] = + eina_inlist_remove(_e_client_intercept_hooks[ch->hookpoint], EINA_INLIST_GET(ch)); + free(ch); + } + else + _e_client_intercept_hooks_delete++; +} + +EINTERN void +e_client_focus_stack_lower(E_Client *ec) +{ + Eina_List *l = NULL; + E_Client *ec2 = NULL; + + EINA_SAFETY_ON_NULL_RETURN(ec); + if (focus_track_frozen > 0) return; + + focus_stack = eina_list_remove(focus_stack, ec); + + EINA_LIST_REVERSE_FOREACH(focus_stack, l, ec2) + { + if (ec2 == NULL) continue; + if (ec2->layer < ec->layer) continue; + + focus_stack = eina_list_append_relative_list(focus_stack, ec, l); + return; + } + + focus_stack = eina_list_prepend(focus_stack, ec); + return; +} + +E_API void +e_client_focus_latest_set(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (focus_track_frozen > 0) return; + + focus_stack = eina_list_remove(focus_stack, ec); + focus_stack = eina_list_prepend(focus_stack, ec); +} + +E_API void +e_client_focus_defer_set(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + + defer_focus_stack = eina_list_remove(defer_focus_stack, ec); + defer_focus_stack = eina_list_prepend(defer_focus_stack, ec); +} + +E_API void +e_client_focus_defer_unset(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + + defer_focus_stack = eina_list_remove(defer_focus_stack, ec); +} + +E_API Eina_Bool +e_client_focus_track_enabled(void) +{ + return !focus_track_frozen; +} + +E_API void +e_client_focus_track_freeze(void) +{ + focus_track_frozen++; +} + +E_API void +e_client_focus_track_thaw(void) +{ + if (focus_track_frozen) + focus_track_frozen--; +} + +E_API void +e_client_refocus(void) +{ + E_Client *ec; + const Eina_List *l; + + EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec) + if (ec->desk && ec->desk->visible && (!ec->iconic)) + { + if (e_comp->input_key_grabs || e_comp->input_mouse_grabs) break; + ELOGF("FOCUS", "focus set | refocus", ec); + evas_object_focus_set(ec->frame, 1); + break; + } +} + + +/* + * Sets the focus to the given client if necessary + * There are 3 cases of different focus_policy-configurations: + * + * - E_FOCUS_CLICK: just set the focus, the most simple one + * + * - E_FOCUS_MOUSE: focus is where the mouse is, so try to + * warp the pointer to the window. If this fails (because + * the pointer is already in the window), just set the focus. + * + * - E_FOCUS_SLOPPY: focus is where the mouse is or on the + * last window which was focused, if the mouse is on the + * desktop. So, we need to look if there is another window + * under the pointer and warp to pointer to the right + * one if so (also, we set the focus afterwards). In case + * there is no window under pointer, the pointer is on the + * desktop and so we just set the focus. + * + * + * This function is to be called when setting the focus was not + * explicitly triggered by the user (by moving the mouse or + * clicking for example), but implicitly (by closing a window, + * the last focused window should get focus). + * + */ +E_API void +e_client_focus_set_with_pointer(E_Client *ec) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + /* note: this is here as it seems there are enough apps that do not even + * expect us to emulate a look of focus but not actually set x input + * focus as we do - so simply abort any focuse set on such windows */ + /* be strict about accepting focus hint */ + if ((!ec->icccm.accepts_focus) && + (!ec->icccm.take_focus)) return; + if (ec->lock_focus_out) return; + if (ec == focused) return; + + TRACE_DS_BEGIN(CLIENT:FOCUS SET WITH POINTER); + ELOGF("FOCUS", "focus set | focus with pointer", ec); + evas_object_focus_set(ec->frame, 1); + + if (e_config->focus_policy == E_FOCUS_CLICK) + { + TRACE_DS_END(); + return; + } + if (!ec->visible) + { + TRACE_DS_END(); + return; + } + + TRACE_DS_END(); +} + +EINTERN void +e_client_focused_set(E_Client *ec) +{ + E_Client *ec2, *ec_unfocus = focused; + Eina_List *l, *ll; + + if (ec == focused) return; + + TRACE_DS_BEGIN(CLIENT:FOCUSED SET); + + ELOG("CLIENT FOCUS_SET", ec); + focused = ec; + if ((ec) && (ec->zone)) + { + ec->focused = 1; + e_client_urgent_set(ec, 0); + int x, total = ec->zone->desk_x_count * ec->zone->desk_y_count; + + for (x = 0; x < total; x++) + { + E_Desk *desk = ec->zone->desks[x]; + /* if there's any fullscreen non-parents on this desk, unfullscreen them */ + EINA_LIST_FOREACH_SAFE(desk->fullscreen_clients, l, ll, ec2) + { + if (ec2 == ec) continue; + if (e_object_is_del(E_OBJECT(ec2))) continue; + /* but only if it's the same desk or one of the clients is sticky */ + if ((desk == ec->desk) || (ec->sticky || ec2->sticky)) + { + if (!eina_list_data_find(ec->transients, ec2)) + e_client_unfullscreen(ec2); + } + } + } + } + + while ((ec_unfocus) && (ec_unfocus->zone)) + { + ec_unfocus->want_focus = ec_unfocus->focused = 0; + if (!e_object_is_del(E_OBJECT(ec_unfocus))) + e_focus_event_focus_out(ec_unfocus); + if (ec_unfocus->mouse.in && ec && (!e_client_util_is_popup(ec)) && + (e_config->focus_policy != E_FOCUS_CLICK)) + e_client_mouse_out(ec_unfocus, ec_unfocus->x - 1, ec_unfocus->y - 1); + + /* if there unfocus client is fullscreen and visible */ + if ((ec_unfocus->fullscreen) && (!ec_unfocus->iconic) && (!ec_unfocus->hidden) && + (ec_unfocus->zone == e_zone_current_get()) && + ((ec_unfocus->desk == e_desk_current_get(ec_unfocus->zone)) || (ec_unfocus->sticky))) + { + Eina_Bool have_vis_child = EINA_FALSE; + + /* if any of its children are visible */ + EINA_LIST_FOREACH(ec_unfocus->transients, l, ec2) + { + if ((ec2->zone == ec_unfocus->zone) && + ((ec2->desk == ec_unfocus->desk) || + (ec2->sticky) || (ec_unfocus->sticky))) + { + have_vis_child = EINA_TRUE; + break; + } + } + /* if no children are visible, unfullscreen */ + if ((!e_object_is_del(E_OBJECT(ec_unfocus))) && (!have_vis_child)) + e_client_unfullscreen(ec_unfocus); + } + + _e_client_hook_call(E_CLIENT_HOOK_FOCUS_UNSET, ec_unfocus); + /* only send event here if we're not being deleted */ + if ((!e_object_is_del(E_OBJECT(ec_unfocus))) && + (e_object_ref_get(E_OBJECT(ec_unfocus)) > 0)) + { + _e_client_event_simple(ec_unfocus, E_EVENT_CLIENT_FOCUS_OUT); + e_client_urgent_set(ec_unfocus, ec_unfocus->icccm.urgent); + } + + e_client_focus_defer_unset(ec_unfocus); + break; + } + if (!ec) + { + TRACE_DS_END(); + return; + } + + _e_client_hook_call(E_CLIENT_HOOK_FOCUS_SET, ec); + e_focus_event_focus_in(ec); + + if (!focus_track_frozen) + e_client_focus_latest_set(ec); + + e_hints_active_window_set(ec); + _e_client_event_simple(ec, E_EVENT_CLIENT_FOCUS_IN); + if (ec->sticky && ec->desk && (!ec->desk->visible)) + e_client_desk_set(ec, e_desk_current_get(ec->zone)); + + TRACE_DS_END(); +} + +E_API void +e_client_activate(E_Client *ec, Eina_Bool just_do_it) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + TRACE_DS_BEGIN(CLIENT:ACTIVATE); + + if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || + ((ec->parent) && + ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) || + ((ec->parent->focused) && + (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))) || + (just_do_it)) + { + ELOGF("COMP", "Set launching flag..", ec); + ec->launching = EINA_TRUE; + + ec->exp_iconify.not_raise = 0; + + if (ec->iconic) + { + if (!ec->lock_user_iconify) + e_client_uniconify(ec); + } + ELOG("Un-Set ICONIFY BY CLIENT", ec); + ec->exp_iconify.by_client = 0; + + if ((!ec->iconic) && (!ec->sticky)) + { + e_desk_show(ec->desk); + } + if (!ec->lock_user_stacking) + evas_object_raise(ec->frame); + if (ec->shaded || ec->shading) + e_client_unshade(ec, ec->shade_dir); + if (!ec->lock_focus_out) + { + E_Client *focus_ec = NULL; + E_Client *obscured_above = NULL; + + if (ec->transients) + focus_ec = e_client_transient_child_top_get(ec, EINA_TRUE); + + if (!focus_ec) + focus_ec = ec; + + obscured_above = _e_client_check_fully_contain_by_above(focus_ec, EINA_FALSE); + if (!obscured_above) + { + if (!e_policy_visibility_client_is_uniconic(ec)) + { + e_client_focus_defer_set(focus_ec); + e_client_focus_latest_set(focus_ec); + } + else + { + ELOGF("FOCUS", "focus set | client activate", ec); + evas_object_focus_set(focus_ec->frame, 1); + } + } + else + { + e_client_focus_defer_set(focus_ec); + e_client_focus_latest_set(focus_ec); + } + } + } + + TRACE_DS_END(); +} + +E_API E_Client * +e_client_focused_get(void) +{ + return focused; +} + +E_API Eina_List * +e_client_focus_stack_get(void) +{ + return focus_stack; +} + +YOLO E_API void +e_client_focus_stack_set(Eina_List *l) +{ + focus_stack = l; +} + +E_API Eina_List * +e_client_lost_windows_get(E_Zone *zone) +{ + Eina_List *list = NULL; + const Eina_List *l; + E_Client *ec; + int loss_overlap = 5; + + E_OBJECT_CHECK_RETURN(zone, NULL); + E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, NULL); + EINA_LIST_FOREACH(e_comp->clients, l, ec) + { + if (ec->zone != zone) continue; + if (e_client_util_ignored_get(ec)) continue; + + if (!E_INTERSECTS(ec->zone->x + loss_overlap, + ec->zone->y + loss_overlap, + ec->zone->w - (2 * loss_overlap), + ec->zone->h - (2 * loss_overlap), + ec->x, ec->y, ec->w, ec->h)) + { + list = eina_list_append(list, ec); + } + } + return list; +} + +/////////////////////////////////////// + +E_API void +e_client_shade(E_Client *ec, E_Direction dir) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if ((ec->shaded) || (ec->shading) || (ec->fullscreen) || + ((ec->maximized) && (!e_config->allow_manip))) return; + if (!e_util_strcmp("borderless", ec->bordername)) return; + if (!e_comp_object_frame_allowed(ec->frame)) return; + + e_hints_window_shaded_set(ec, 1); + e_hints_window_shade_direction_set(ec, dir); + ec->take_focus = 0; + ec->shading = 1; + ec->shade_dir = dir; + + evas_object_smart_callback_call(ec->frame, "shaded", (uintptr_t*)dir); +} + +E_API void +e_client_unshade(E_Client *ec, E_Direction dir) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if ((!ec->shaded) || (ec->shading)) + return; + + e_hints_window_shaded_set(ec, 0); + e_hints_window_shade_direction_set(ec, dir); + ec->shading = 1; + ec->shade_dir = 0; + + evas_object_smart_callback_call(ec->frame, "unshaded", (uintptr_t*)dir); +} + +/////////////////////////////////////// + +E_API void +e_client_maximize(E_Client *ec, E_Maximize max) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + if (!ec->zone) return; + if (!(max & E_MAXIMIZE_DIRECTION)) max |= E_MAXIMIZE_BOTH; + + if ((ec->shaded) || (ec->shading)) return; + evas_object_smart_callback_call(ec->frame, "maximize_pre", NULL); + /* Only allow changes in vertical/ horizontal maximization */ + if (((ec->maximized & E_MAXIMIZE_DIRECTION) == (max & E_MAXIMIZE_DIRECTION)) || + ((ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_BOTH)) return; + if (ec->new_client) + { + ec->changes.need_maximize = 1; + ec->maximized &= ~E_MAXIMIZE_TYPE; + ec->maximized |= max; + EC_CHANGED(ec); + return; + } + + if (ec->fullscreen) + e_client_unfullscreen(ec); + ec->pre_res_change.valid = 0; + if (!(ec->maximized & E_MAXIMIZE_HORIZONTAL)) + { + /* Horizontal hasn't been set */ + ec->saved.x = ec->client.x - ec->desk->geom.x; + ec->saved.w = ec->client.w; + } + if (!(ec->maximized & E_MAXIMIZE_VERTICAL)) + { + /* Vertical hasn't been set */ + ec->saved.y = ec->client.y - ec->desk->geom.y; + ec->saved.h = ec->client.h; + } + + ec->saved.zone = ec->zone->num; + e_hints_window_size_set(ec); + + _e_client_maximize(ec, max); + + /* Remove previous type */ + ec->maximized &= ~E_MAXIMIZE_TYPE; + /* Add new maximization. It must be added, so that VERTICAL + HORIZONTAL == BOTH */ + ec->maximized |= max; + ec->changes.need_unmaximize = 0; + + if ((ec->maximized & E_MAXIMIZE_DIRECTION) > E_MAXIMIZE_BOTH) + /* left/right maximize */ + e_hints_window_maximized_set(ec, 0, + ((ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_LEFT) || + ((ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_RIGHT)); + else + e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL, + ec->maximized & E_MAXIMIZE_VERTICAL); + evas_object_smart_callback_call(ec->frame, "maximize_done", NULL); +} + +E_API void +e_client_unmaximize(E_Client *ec, E_Maximize max) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if (!(max & E_MAXIMIZE_DIRECTION)) + { + CRI("BUG: Unmaximize call without direction!"); + return; + } + if (ec->new_client) + { + ec->changes.need_unmaximize = 1; + EC_CHANGED(ec); + return; + } + + if ((ec->shaded) || (ec->shading)) return; + evas_object_smart_callback_call(ec->frame, "unmaximize_pre", NULL); + /* Remove directions not used */ + max &= (ec->maximized & E_MAXIMIZE_DIRECTION); + /* Can only remove existing maximization directions */ + if (!max) return; + if (ec->maximized & E_MAXIMIZE_TYPE) + { + ec->pre_res_change.valid = 0; + ec->changes.need_maximize = 0; + + if ((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN) + { + E_Maximize tmp_max = ec->maximized; + + //un-set maximized state for updating frame. + ec->maximized = E_MAXIMIZE_NONE; + _e_client_frame_update(ec); + // re-set maximized state for unmaximize smart callback. + ec->maximized = tmp_max; + evas_object_smart_callback_call(ec->frame, "unfullscreen", NULL); + // un-set maximized state. + ec->maximized = E_MAXIMIZE_NONE; + e_client_util_move_resize_without_frame(ec, + ec->saved.x + ec->zone->x, + ec->saved.y + ec->zone->y, + ec->saved.w, ec->saved.h); + ec->saved.x = ec->saved.y = ec->saved.w = ec->saved.h = 0; + e_hints_window_size_unset(ec); + } + else + { + int w, h, x, y; + Eina_Bool horiz = EINA_FALSE, vert = EINA_FALSE; + + w = ec->client.w; + h = ec->client.h; + x = ec->client.x; + y = ec->client.y; + + if (max & E_MAXIMIZE_VERTICAL) + { + /* Remove vertical */ + h = ec->saved.h; + vert = EINA_TRUE; + y = ec->saved.y + ec->zone->y; + if ((max & E_MAXIMIZE_VERTICAL) == E_MAXIMIZE_VERTICAL) + { + ec->maximized &= ~E_MAXIMIZE_VERTICAL; + ec->maximized &= ~E_MAXIMIZE_LEFT; + ec->maximized &= ~E_MAXIMIZE_RIGHT; + } + if ((max & E_MAXIMIZE_LEFT) == E_MAXIMIZE_LEFT) + ec->maximized &= ~E_MAXIMIZE_LEFT; + if ((max & E_MAXIMIZE_RIGHT) == E_MAXIMIZE_RIGHT) + ec->maximized &= ~E_MAXIMIZE_RIGHT; + } + if (max & E_MAXIMIZE_HORIZONTAL) + { + /* Remove horizontal */ + w = ec->saved.w; + x = ec->saved.x + ec->zone->x; + horiz = EINA_TRUE; + ec->maximized &= ~E_MAXIMIZE_HORIZONTAL; + } + + if (!(ec->maximized & E_MAXIMIZE_DIRECTION)) + { + ec->maximized = E_MAXIMIZE_NONE; + _e_client_frame_update(ec); + evas_object_smart_callback_call(ec->frame, "unmaximize", NULL); + e_client_resize_limit(ec, &w, &h); + if (ec->layout.splited) + e_client_util_move_resize_without_frame(ec, x, y, w, h); + else + { + e_policy_visibility_client_defer_move(ec); + } + e_hints_window_size_unset(ec); + } + else + { + evas_object_smart_callback_call(ec->frame, "unmaximize", NULL); + e_client_resize_limit(ec, &w, &h); + if (ec->layout.splited) + e_client_util_move_resize_without_frame(ec, x, y, w, h); + else + { + e_policy_visibility_client_defer_move(ec); + } + + e_hints_window_size_set(ec); + } + if (vert) + ec->saved.h = ec->saved.y = 0; + if (horiz) + ec->saved.w = ec->saved.x = 0; + } + e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL, + ec->maximized & E_MAXIMIZE_VERTICAL); + } + evas_object_smart_callback_call(ec->frame, "unmaximize_done", NULL); + ec->changes.need_unmaximize = 0; +} + +E_API void +e_client_fullscreen(E_Client *ec, E_Fullscreen policy) +{ + int x, y, w, h; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + + if ((ec->shaded) || (ec->shading) || (ec->fullscreen)) return; + + _e_client_hook_call(E_CLIENT_HOOK_FULLSCREEN_PRE, ec); + + if (ec->skip_fullscreen) return; + if (!ec->desk->visible) return; + if (ec->new_client) + { + ec->need_fullscreen = 1; + return; + } + if (e_comp->nocomp_ec && (ec->desk == e_comp->nocomp_ec->desk)) + e_comp->nocomp_ec = ec; + ec->desk->fullscreen_clients = eina_list_append(ec->desk->fullscreen_clients, ec); + ec->pre_res_change.valid = 0; + + if (ec->maximized) + { + x = ec->saved.x; + y = ec->saved.y; + w = ec->saved.w; + h = ec->saved.h; + } + else + { + ec->saved.x = ec->client.x - ec->zone->x; + ec->saved.y = ec->client.y - ec->zone->y; + ec->saved.w = ec->client.w; + ec->saved.h = ec->client.h; + } + ec->saved.maximized = ec->maximized; + ec->saved.zone = ec->zone->num; + + if (ec->maximized) + { + e_client_unmaximize(ec, E_MAXIMIZE_BOTH); + ec->saved.x = x; + ec->saved.y = y; + ec->saved.w = w; + ec->saved.h = h; + } + e_hints_window_size_set(ec); + + ec->saved.layer = ec->layer; + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_FULLSCREEN); + + ec->fullscreen = 1; + if ((eina_list_count(e_comp->zones) > 1) || + (policy == E_FULLSCREEN_RESIZE)) + { + evas_object_geometry_set(ec->frame, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h); + } + else if (policy == E_FULLSCREEN_ZOOM) + { + /* compositor backends! */ + evas_object_smart_callback_call(ec->frame, "fullscreen_zoom", NULL); + } + + e_hints_window_fullscreen_set(ec, 1); + e_hints_window_size_unset(ec); + if (!e_client_util_ignored_get(ec)) + _e_client_frame_update(ec); + ec->fullscreen_policy = policy; + evas_object_smart_callback_call(ec->frame, "fullscreen", NULL); + + _e_client_event_simple(ec, E_EVENT_CLIENT_FULLSCREEN); +} + +E_API void +e_client_unfullscreen(E_Client *ec) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if ((ec->shaded) || (ec->shading)) return; + if (!ec->fullscreen) return; + ec->pre_res_change.valid = 0; + ec->fullscreen = 0; + ec->need_fullscreen = 0; + ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec); + + if (ec->fullscreen_policy == E_FULLSCREEN_ZOOM) + evas_object_smart_callback_call(ec->frame, "unfullscreen_zoom", NULL); + + if (!e_client_util_ignored_get(ec)) + _e_client_frame_update(ec); + ec->fullscreen_policy = 0; + evas_object_smart_callback_call(ec->frame, "unfullscreen", NULL); + e_client_util_move_resize_without_frame(ec, ec->zone->x + ec->saved.x, + ec->zone->y + ec->saved.y, + ec->saved.w, ec->saved.h); + + if (ec->saved.maximized) + e_client_maximize(ec, (e_config->maximize_policy & E_MAXIMIZE_TYPE) | + ec->saved.maximized); + + evas_object_layer_set(ec->frame, ec->saved.layer); + + e_hints_window_fullscreen_set(ec, 0); + _e_client_event_simple(ec, E_EVENT_CLIENT_UNFULLSCREEN); + + if (!ec->desk->fullscreen_clients) + e_comp_render_queue(); +} + +/////////////////////////////////////// + + +E_API void +e_client_iconify(E_Client *ec) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + ELOGF("TZVIS", "ICONIFY |not_raise:%d |by_client:%d", + ec, (unsigned int)ec->exp_iconify.not_raise, + ec->exp_iconify.by_client); + + if (!ec->zone) return; + if (ec->shading || ec->iconic) return; + if (ec->exp_iconify.skip_iconify && !ec->exp_iconify.by_client) return; + if (ec->exp_iconify.skip_by_remote) return; + if (!ec->comp_data || !ec->comp_data->mapped) + { + if (!ec->exp_iconify.by_client) + { + ELOGF("TZVIS", "Not mapped.. So, don't iconify", ec); + return; + } + else + { + ELOGF("TZVIS", "Not mapped.. But, iconify by user request", ec); + } + } + + TRACE_DS_BEGIN(CLIENT:ICONIFY); + + ec->iconic = 1; + ec->want_focus = ec->take_focus = 0; + ec->changes.visible = 0; + if (ec->fullscreen) + ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec); + e_client_comp_hidden_set(ec, 1); + evas_object_hide(ec->frame); + e_client_urgent_set(ec, ec->icccm.urgent); + + _e_client_event_simple(ec, E_EVENT_CLIENT_ICONIFY); + + if (e_config->transient.iconify) + { + E_Client *child; + Eina_List *list = eina_list_clone(ec->transients); + + EINA_LIST_FREE(list, child) + e_client_iconify(child); + } + + _e_client_hook_call(E_CLIENT_HOOK_ICONIFY, ec); + + TRACE_DS_END(); +} + +E_API void +e_client_uniconify(E_Client *ec) +{ + E_Desk *desk; + Eina_Bool not_raise; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + ELOGF("TZVIS", "UNICONIFY|not_raise:%d |by_client:%d\t| mapped:%d", + ec, (unsigned int)ec->exp_iconify.not_raise, + ec->exp_iconify.by_client, + ec->comp_data ? ec->comp_data->mapped : 0); + + if (!ec->zone) return; + if (ec->shading || (!ec->iconic)) return; + + TRACE_DS_BEGIN(CLIENT:UNICONIFY); + + desk = e_desk_current_get(ec->desk->zone); + e_client_desk_set(ec, desk); + not_raise = ec->exp_iconify.not_raise; + + if (e_config->transient.iconify) + { + E_Client *child; + Eina_List *list = eina_list_clone(ec->transients); + + EINA_LIST_FREE(list, child) + { + if (child->transient_policy == E_TRANSIENT_BELOW) + { + child->exp_iconify.not_raise = not_raise; + e_client_uniconify(child); + } + } + } + + if (!not_raise) + evas_object_raise(ec->frame); + + if (ec->internal) + { + ELOGF("TZVIS", "UNICONIFY|internal object force show", ec); + evas_object_show(ec->frame); + } + + if (ec->pixmap && e_pixmap_usable_get(ec->pixmap)) + { + if (ec->comp_data && ec->comp_data->mapped) + { + ELOGF("TZVIS", "UNICONIFY|object show", ec); + evas_object_show(ec->frame); + } + else + { + ELOGF("TZVIS", "UNICONIFY|object no show. currently unmapped", ec); + } + } + + e_client_comp_hidden_set(ec, 0); + ec->deskshow = ec->iconic = 0; + +#if 0 // focus should be set to the top window not uniconify window + if (ec->pixmap && e_pixmap_usable_get(ec->pixmap)) + evas_object_focus_set(ec->frame, 1); +#endif + + _e_client_event_simple(ec, E_EVENT_CLIENT_UNICONIFY); + + if (e_config->transient.iconify) + { + E_Client *child; + Eina_List *list = eina_list_clone(ec->transients); + + EINA_LIST_FREE(list, child) + { + if (child->transient_policy == E_TRANSIENT_ABOVE) + { + child->exp_iconify.not_raise = not_raise; + e_client_uniconify(child); + } + } + } + + _e_client_hook_call(E_CLIENT_HOOK_UNICONIFY, ec); + + ec->exp_iconify.not_raise = 0; + ec->exp_iconify.by_client = 0; + + TRACE_DS_END(); +} + +/////////////////////////////////////// + +E_API void +e_client_urgent_set(E_Client *ec, Eina_Bool urgent) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + if (!ec->zone) return; + + urgent = !!urgent; + if (urgent == ec->urgent) return; + _e_client_event_property(ec, E_CLIENT_PROPERTY_URGENCY); + if (urgent && (!ec->focused) && (!ec->want_focus)) + { + e_comp_object_signal_emit(ec->frame, "e,state,urgent", "e"); + ec->urgent = urgent; + } + else + { + e_comp_object_signal_emit(ec->frame, "e,state,not_urgent", "e"); + ec->urgent = 0; + } +} + +/////////////////////////////////////// + +E_API void +e_client_stick(E_Client *ec) +{ + E_Desk *desk; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if (ec->sticky) return; + desk = ec->desk; + ec->desk = NULL; + ec->sticky = 1; + ec->hidden = 0; + e_hints_window_sticky_set(ec, 1); + e_client_desk_set(ec, desk); + evas_object_smart_callback_call(ec->frame, "stick", NULL); + + if (e_config->transient.desktop) + { + E_Client *child; + Eina_List *list = eina_list_clone(ec->transients); + + EINA_LIST_FREE(list, child) + { + child->sticky = 1; + e_hints_window_sticky_set(child, 1); + evas_object_show(ec->frame); + } + } + + _e_client_event_property(ec, E_CLIENT_PROPERTY_STICKY); +} + +E_API void +e_client_unstick(E_Client *ec) +{ + E_Desk *desk; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + /* Set the desk before we unstick the client */ + if (!ec->sticky) return; + desk = e_desk_current_get(ec->zone); + ec->desk = NULL; + ec->hidden = ec->sticky = 0; + e_hints_window_sticky_set(ec, 0); + e_client_desk_set(ec, desk); + evas_object_smart_callback_call(ec->frame, "unstick", NULL); + + if (e_config->transient.desktop) + { + E_Client *child; + Eina_List *list = eina_list_clone(ec->transients); + + EINA_LIST_FREE(list, child) + { + child->sticky = 0; + e_hints_window_sticky_set(child, 0); + } + } + + _e_client_event_property(ec, E_CLIENT_PROPERTY_STICKY); + + e_client_desk_set(ec, e_desk_current_get(ec->zone)); +} + +E_API void +e_client_pinned_set(E_Client *ec, Eina_Bool set) +{ + E_Layer layer; + + EINA_SAFETY_ON_NULL_RETURN(ec); + ec->borderless = !!set; + ec->user_skip_winlist = !!set; + if (set) + layer = E_LAYER_CLIENT_BELOW; + else + layer = E_LAYER_CLIENT_NORMAL; + + evas_object_layer_set(ec->frame, layer); + + ec->border.changed = 1; + EC_CHANGED(ec); +} + +/////////////////////////////////////// + +E_API Eina_Bool +e_client_border_set(E_Client *ec, const char *name) +{ + Eina_Stringshare *pborder; + + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + if (!e_comp_object_frame_allowed(ec->frame)) return EINA_FALSE; + if (ec->border.changed) + CRI("CALLING WHEN border.changed SET!"); + + if (!e_util_strcmp(ec->border.name, name)) return EINA_TRUE; + if (ec->mwm.borderless && name && strcmp(name, "borderless")) + { + e_util_dialog_show(_("Client Error!"), _("Something has attempted to set a border when it shouldn't! Report this!")); + CRI("border change attempted for MWM borderless client!"); + } + pborder = ec->border.name; + ec->border.name = eina_stringshare_add(name); + if (e_comp_object_frame_theme_set(ec->frame, name)) + { + eina_stringshare_del(pborder); + return EINA_TRUE; + } + eina_stringshare_del(ec->border.name); + ec->border.name = pborder; + return EINA_FALSE; +} + +/////////////////////////////////////// + +E_API void +e_client_comp_hidden_set(E_Client *ec, Eina_Bool hidden) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + + hidden = !!hidden; + if (ec->comp_hidden == hidden) return; + ec->comp_hidden = hidden; + evas_object_smart_callback_call(ec->frame, "comp_hidden", NULL); +} + +/////////////////////////////////////// + +E_API void +e_client_act_move_keyboard(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (!ec->zone) return; + + if (!_e_client_move_begin(ec)) + return; + + _e_client_action_init(ec); + _e_client_action_move_timeout_add(); + if (!_e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec)) return; + evas_object_freeze_events_set(ec->frame, 1); + + if (!action_handler_key) + action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_client_move_key_down, NULL); + + if (!action_handler_mouse) + action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_client_move_mouse_down, NULL); +} + +E_API void +e_client_act_resize_keyboard(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (!ec->zone) return; + + ec->resize_mode = E_POINTER_RESIZE_TL; + ec->keyboard_resizing = 1; + if (!e_client_resize_begin(ec)) + { + ec->keyboard_resizing = 0; + return; + } + + _e_client_action_init(ec); + _e_client_action_resize_timeout_add(); + evas_object_freeze_events_set(ec->frame, 1); + + if (!action_handler_key) + action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_client_resize_key_down, NULL); + + if (!action_handler_mouse) + action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_client_resize_mouse_down, NULL); +} + +E_API void +e_client_act_move_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if (e_client_util_resizing_get(ec) || (ec->moving)) return; + if (ev) + { + char source[256]; + + snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button); + _e_client_moveinfo_gather(ec, source); + } + if (!_e_client_move_begin(ec)) + return; + + _e_client_action_init(ec); + e_zone_edge_disable(); +} + +E_API void +e_client_act_move_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if (!ec->moving) return; + e_zone_edge_enable(); + _e_client_move_end(ec); + e_zone_flip_coords_handle(ec->zone, -1, -1); + _e_client_action_finish(); +} + +E_API void +e_client_act_resize_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev, E_Pointer_Mode resize_mode) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if (ec->lock_user_size || ec->shaded || ec->shading) return; + if (e_client_util_resizing_get(ec) || (ec->moving)) return; + if (ev) + { + char source[256]; + snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button); + _e_client_moveinfo_gather(ec, source); + + if ((ec->floating) && + (resize_mode != E_POINTER_RESIZE_NONE)) + { + /* set resizing direction only for floating mode window */ + ec->resize_mode = resize_mode; + } + else + { + /* setting resize mothod of open-source style according to mouse position, + * but we don't know how it exactly does. */ + + /* Use canvas.x, canvas.y of event. + * Transformed coordinates has to be considered for accurate resize_mode + * rather than absolute coordinates. */ + if ((ev->canvas.x > (ec->x + ec->w / 5)) && + (ev->canvas.x < (ec->x + ec->w * 4 / 5))) + { + if (ev->canvas.y < (ec->y + ec->h / 2)) ec->resize_mode = E_POINTER_RESIZE_T; + else ec->resize_mode = E_POINTER_RESIZE_B; + } + else if (ev->canvas.x < (ec->x + ec->w / 2)) + { + if ((ev->canvas.y > (ec->y + ec->h / 5)) && (ev->canvas.y < (ec->y + ec->h * 4 / 5))) ec->resize_mode = E_POINTER_RESIZE_L; + else if (ev->canvas.y < (ec->y + ec->h / 2)) ec->resize_mode = E_POINTER_RESIZE_TL; + else ec->resize_mode = E_POINTER_RESIZE_BL; + } + else + { + if ((ev->canvas.y > (ec->y + ec->h / 5)) && (ev->canvas.y < (ec->y + ec->h * 4 / 5))) ec->resize_mode = E_POINTER_RESIZE_R; + else if (ev->canvas.y < (ec->y + ec->h / 2)) ec->resize_mode = E_POINTER_RESIZE_TR; + else ec->resize_mode = E_POINTER_RESIZE_BR; + } + } + } + if (!e_client_resize_begin(ec)) + return; + _e_client_action_init(ec); +} + +E_API void +e_client_act_resize_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if (e_client_util_resizing_get(ec)) + { + _e_client_resize_end(ec); + ec->changes.reset_gravity = 1; + if (!e_object_is_del(E_OBJECT(ec))) + EC_CHANGED(ec); + } + _e_client_action_finish(); +} + +E_API void +e_client_act_menu_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev, int key) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; +} + +E_API void +e_client_act_close_begin(E_Client *ec) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if (ec->lock_close) return; + if (ec->icccm.delete_request) + { + ec->delete_requested = 1; + evas_object_smart_callback_call(ec->frame, "delete_request", NULL); + } + else if (e_config->kill_if_close_not_possible) + { + e_client_act_kill_begin(ec); + } +} + +E_API void +e_client_act_kill_begin(E_Client *ec) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if (ec->internal) return; + if (ec->lock_close) return; + if ((ec->netwm.pid > 1) && (e_config->kill_process)) + { + kill(ec->netwm.pid, SIGINT); + ec->kill_timer = ecore_timer_add(e_config->kill_timer_wait, + _e_client_cb_kill_timer, ec); + } + else + evas_object_smart_callback_call(ec->frame, "kill_request", NULL); +} + +//////////////////////////////////////////// + +E_API void +e_client_ping(E_Client *ec) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + if (!e_config->ping_clients) return; + + EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(ec))); + + ec->ping_ok = 0; + evas_object_smart_callback_call(ec->frame, "ping", NULL); + ec->ping = ecore_loop_time_get(); + if (ec->ping_poller) ecore_poller_del(ec->ping_poller); + ec->ping_poller = ecore_poller_add(ECORE_POLLER_CORE, + e_config->ping_clients_interval, + _e_client_cb_ping_poller, ec); +} + +//////////////////////////////////////////// +E_API void +e_client_cursor_map_apply(E_Client *ec, int rotation, int x, int y) +{ + // TODO: remove(deprecate) this e_client_cursor_map_apply. +} + +E_API void +e_client_move_cancel(void) +{ + if (!ecmove) return; + if (ecmove->cur_mouse_action) + { + E_Client *ec; + + ec = ecmove; + e_object_ref(E_OBJECT(ec)); + if (ec->cur_mouse_action->func.end_mouse) + ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", NULL); + else if (ec->cur_mouse_action->func.end) + ec->cur_mouse_action->func.end(E_OBJECT(ec), ""); + e_object_unref(E_OBJECT(ec->cur_mouse_action)); + ec->cur_mouse_action = NULL; + e_object_unref(E_OBJECT(ec)); + } + else + _e_client_move_end(ecmove); +} + +E_API void +e_client_resize_cancel(void) +{ + if (!ecresize) return; + if (ecresize->cur_mouse_action) + { + E_Client *ec; + + ec = ecresize; + e_object_ref(E_OBJECT(ec)); + if (ec->cur_mouse_action->func.end_mouse) + ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", NULL); + else if (ec->cur_mouse_action->func.end) + ec->cur_mouse_action->func.end(E_OBJECT(ec), ""); + e_object_unref(E_OBJECT(ec->cur_mouse_action)); + ec->cur_mouse_action = NULL; + e_object_unref(E_OBJECT(ec)); + } + else + _e_client_resize_end(ecresize); +} + +E_API Eina_Bool +e_client_resize_begin(E_Client *ec) +{ + if ((ec->shaded) || (ec->shading) || + (ec->fullscreen) || (ec->lock_user_size)) + goto error; + if (!_e_client_action_input_win_new()) goto error; + ecresize = ec; + _e_client_hook_call(E_CLIENT_HOOK_RESIZE_BEGIN, ec); + if (ec->transformed) + _e_client_transform_resize_begin(ec); + if (!e_client_util_resizing_get(ec)) + { + if (ecresize == ec) ecresize = NULL; + _e_client_action_input_win_del(); + return EINA_FALSE; + } + if (!ec->lock_user_stacking) + { + if (e_config->border_raise_on_mouse_action) + evas_object_raise(ec->frame); + } + + if (e_comp->hwc) + e_comp_client_override_add(ec); + + return EINA_TRUE; +error: + ec->resize_mode = E_POINTER_RESIZE_NONE; + return EINA_FALSE; +} + + +//////////////////////////////////////////// + +E_API void +e_client_frame_recalc(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (!ec->frame) return; + evas_object_smart_callback_call(ec->frame, "frame_recalc", NULL); +} + +//////////////////////////////////////////// + +E_API void +e_client_signal_move_begin(E_Client *ec, const char *sig, const char *src EINA_UNUSED) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + + if (e_client_util_resizing_get(ec) || (ec->moving)) return; + _e_client_moveinfo_gather(ec, sig); + if (!_e_client_move_begin(ec)) return; + e_zone_edge_disable(); +} + +E_API void +e_client_signal_move_end(E_Client *ec, const char *sig EINA_UNUSED, const char *src EINA_UNUSED) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!ec->zone) return; + if (!ec->moving) return; + _e_client_move_end(ec); + e_zone_edge_enable(); + e_zone_flip_coords_handle(ec->zone, -1, -1); +} + +E_API void +e_client_signal_resize_begin(E_Client *ec, const char *dir, const char *sig, const char *src EINA_UNUSED) +{ + int resize_mode = E_POINTER_RESIZE_BR; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + if (e_client_util_resizing_get(ec) || (ec->moving)) return; + if (!strcmp(dir, "tl")) + { + resize_mode = E_POINTER_RESIZE_TL; + } + else if (!strcmp(dir, "t")) + { + resize_mode = E_POINTER_RESIZE_T; + } + else if (!strcmp(dir, "tr")) + { + resize_mode = E_POINTER_RESIZE_TR; + } + else if (!strcmp(dir, "r")) + { + resize_mode = E_POINTER_RESIZE_R; + } + else if (!strcmp(dir, "br")) + { + resize_mode = E_POINTER_RESIZE_BR; + } + else if (!strcmp(dir, "b")) + { + resize_mode = E_POINTER_RESIZE_B; + } + else if (!strcmp(dir, "bl")) + { + resize_mode = E_POINTER_RESIZE_BL; + } + else if (!strcmp(dir, "l")) + { + resize_mode = E_POINTER_RESIZE_L; + } + ec->resize_mode = resize_mode; + _e_client_moveinfo_gather(ec, sig); + if (!e_client_resize_begin(ec)) + return; +} + +E_API void +e_client_signal_resize_end(E_Client *ec, const char *dir EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED) +{ + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + if (!e_client_util_resizing_get(ec)) return; + _e_client_resize_handle(ec); + _e_client_resize_end(ec); + ec->changes.reset_gravity = 1; + EC_CHANGED(ec); +} + +//////////////////////////////////////////// + +E_API void +e_client_resize_limit(E_Client *ec, int *w, int *h) +{ + double a; + Eina_Bool inc_h; + + E_OBJECT_CHECK(ec); + E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE); + + inc_h = (*h - ec->h > 0); + if (ec->frame) + e_comp_object_frame_wh_unadjust(ec->frame, *w, *h, w, h); + if (*h < 1) *h = 1; + if (*w < 1) *w = 1; + if ((ec->icccm.base_w >= 0) && + (ec->icccm.base_h >= 0)) + { + int tw, th; + + tw = *w - ec->icccm.base_w; + th = *h - ec->icccm.base_h; + if (tw < 1) tw = 1; + if (th < 1) th = 1; + a = (double)(tw) / (double)(th); + if ((ec->icccm.min_aspect != 0.0) && + (a < ec->icccm.min_aspect)) + { + if (inc_h) + tw = th * ec->icccm.min_aspect; + else + th = tw / ec->icccm.max_aspect; + *w = tw + ec->icccm.base_w; + *h = th + ec->icccm.base_h; + } + else if ((ec->icccm.max_aspect != 0.0) && + (a > ec->icccm.max_aspect)) + { + tw = th * ec->icccm.max_aspect; + *w = tw + ec->icccm.base_w; + } + } + else + { + a = (double)*w / (double)*h; + if ((ec->icccm.min_aspect != 0.0) && + (a < ec->icccm.min_aspect)) + { + if (inc_h) + *w = *h * ec->icccm.min_aspect; + else + *h = *w / ec->icccm.min_aspect; + } + else if ((ec->icccm.max_aspect != 0.0) && + (a > ec->icccm.max_aspect)) + *w = *h * ec->icccm.max_aspect; + } + if (ec->icccm.step_w > 0) + { + if (ec->icccm.base_w >= 0) + *w = ec->icccm.base_w + + (((*w - ec->icccm.base_w) / ec->icccm.step_w) * + ec->icccm.step_w); + else + *w = ec->icccm.min_w + + (((*w - ec->icccm.min_w) / ec->icccm.step_w) * + ec->icccm.step_w); + } + if (ec->icccm.step_h > 0) + { + if (ec->icccm.base_h >= 0) + *h = ec->icccm.base_h + + (((*h - ec->icccm.base_h) / ec->icccm.step_h) * + ec->icccm.step_h); + else + *h = ec->icccm.min_h + + (((*h - ec->icccm.min_h) / ec->icccm.step_h) * + ec->icccm.step_h); + } + + if (*h < 1) *h = 1; + if (*w < 1) *w = 1; + + if ((ec->icccm.max_w > 0) && (*w > ec->icccm.max_w)) *w = ec->icccm.max_w; + else if (*w < ec->icccm.min_w) + *w = ec->icccm.min_w; + if ((ec->icccm.max_h > 0) && (*h > ec->icccm.max_h)) *h = ec->icccm.max_h; + else if (*h < ec->icccm.min_h) + *h = ec->icccm.min_h; + + if (ec->frame) + e_comp_object_frame_wh_adjust(ec->frame, *w, *h, w, h); +} + +//////////////////////////////////////////// + + + +E_API E_Client * +e_client_under_pointer_get(E_Desk *desk, E_Client *exclude) +{ + int x, y; + + /* We need to ensure that we can get the comp window for the + * zone of either the given desk or the desk of the excluded + * window, so return if neither is given */ + if (desk) + e_input_device_pointer_xy_get(NULL, &x, &y); + else if (exclude) + e_input_device_pointer_xy_get(NULL, &x, &y); + else + return NULL; + + if (!desk) + { + desk = exclude->desk; + if (!desk) + { + if (exclude->zone) + desk = e_desk_current_get(exclude->zone); + else + desk = e_desk_current_get(e_zone_current_get()); + } + } + + return desk ? _e_client_under_pointer_helper(desk, exclude, x, y) : NULL; +} + +E_API E_Client *e_client_under_position_get(E_Desk *desk, int x, int y, E_Client *exclude) +{ + if (!desk) return NULL; + + return _e_client_under_pointer_helper(desk, exclude, x, y); +} + +//////////////////////////////////////////// + +E_API int +e_client_pointer_warp_to_center_now(E_Client *ec) +{ + if (warp_client == ec) + { + e_input_device_pointer_warp(NULL, warp_to_x, warp_to_y); + warp_to = 0; + _e_client_pointer_warp_to_center_timer(NULL); + } + else + { + if (e_client_pointer_warp_to_center(ec)) + e_client_pointer_warp_to_center_now(ec); + } + return 1; +} + +E_API int +e_client_pointer_warp_to_center(E_Client *ec) +{ + int x, y; + E_Client *cec = NULL; + + if (!ec->zone) return 0; + /* Only warp the pointer if it is not already in the area of + * the given border */ + e_input_device_pointer_xy_get(NULL, &x, &y); + if ((x >= ec->x) && (x <= (ec->x + ec->w)) && + (y >= ec->y) && (y <= (ec->y + ec->h))) + { + cec = _e_client_under_pointer_helper(ec->desk, ec, x, y); + if (cec == ec) return 0; + } + + warp_to_x = ec->x + (ec->w / 2); + if (warp_to_x < (ec->zone->x + 1)) + warp_to_x = ec->zone->x + ((ec->x + ec->w - ec->zone->x) / 2); + else if (warp_to_x > (ec->zone->x + ec->zone->w)) + warp_to_x = (ec->zone->x + ec->zone->w + ec->x) / 2; + + warp_to_y = ec->y + (ec->h / 2); + if (warp_to_y < (ec->zone->y + 1)) + warp_to_y = ec->zone->y + ((ec->y + ec->h - ec->zone->y) / 2); + else if (warp_to_y > (ec->zone->y + ec->zone->h)) + warp_to_y = (ec->zone->y + ec->zone->h + ec->y) / 2; + + /* TODO: handle case where another border is over the exact center, + * find a place where the requested border is not overlapped? + * + if (!cec) cec = _e_client_under_pointer_helper(ec->desk, ec, x, y); + if (cec != ec) + { + } + */ + + warp_to = 1; + warp_client = ec; + e_input_device_pointer_xy_get(NULL, &warp_x[0], &warp_y[0]); + if (warp_timer) ecore_timer_del(warp_timer); + warp_timer = ecore_timer_add(0.01, _e_client_pointer_warp_to_center_timer, ec); + return 1; +} + +//////////////////////////////////////////// + +E_API void +e_client_redirected_set(E_Client *ec, Eina_Bool set) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (ec->input_only) return; + set = !!set; + if (ec->redirected == set) return; + if (set) + { + e_client_frame_recalc(ec); + if (!_e_client_hook_call(E_CLIENT_HOOK_REDIRECT, ec)) return; + } + else + { + if (!_e_client_hook_call(E_CLIENT_HOOK_UNREDIRECT, ec)) return; + } + e_comp_object_redirected_set(ec->frame, set); + ec->redirected = !!set; +} + +//////////////////////////////////////////// + +E_API Eina_Bool +e_client_is_stacking(const E_Client *ec) +{ + return e_comp->layers[e_comp_canvas_layer_map(ec->layer)].obj == ec->frame; +} + +E_API Eina_Bool +e_client_has_xwindow(const E_Client *ec) +{ + (void)ec; + return EINA_FALSE; +} + +//////////////////////////////////////////// + +E_API void +e_client_layout_cb_set(E_Client_Layout_Cb cb) +{ + if (_e_client_layout_cb && cb) + CRI("ATTEMPTING TO OVERWRITE EXISTING CLIENT LAYOUT HOOK!!!"); + _e_client_layout_cb = cb; +} + +//////////////////////////////////////////// + +E_API void +e_client_transform_update(E_Client *ec) +{ + if (e_client_util_resizing_get(ec)) + _e_client_transform_resize(ec); +} + +//////////////////////////////////////////// + +E_API void +e_client_transform_apply(E_Client *ec, double angle, double zoom, int cx, int cy) +{ + Evas_Map *map; + E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data; + E_Client *subc; + Eina_List *l; + + /* check if it's subsurface */ + if (cdata->sub.data) return; + + /* check if it's different with current state */ + if ((ec->transform.angle == angle) && + (ec->transform.zoom == zoom) && + (ec->transform.center.x == cx) && + (ec->transform.center.y == cy)) + return; + + /* use previous value if any required value is invalid */ + if (angle == -1.0) + angle = ec->transform.angle; + if (zoom == -1.0) + zoom = ec->transform.zoom; + if (!E_INSIDE(cx, cy, + ec->client.x, ec->client.y, + ec->client.w, ec->client.h)) + { + cx = ec->transform.center.x; + cy = ec->transform.center.y; + } + + if ((angle == 0) && (zoom == 1.0)) + { + e_client_transform_clear(ec); + return; + } + + map = evas_map_new(4); + evas_map_util_points_populate_from_object_full(map, ec->frame, 0); + + evas_map_util_rotate(map, angle, cx, cy); + _e_client_transform_geometry_save(ec, map); + + evas_map_util_zoom(map, zoom, zoom, cx, cy); + + evas_map_util_object_move_sync_set(map, EINA_TRUE); + evas_object_map_set(ec->frame, map); + evas_object_map_enable_set(ec->frame, EINA_TRUE); + + if (cdata->sub.below_obj) + { + evas_object_map_set(cdata->sub.below_obj, map); + evas_object_map_enable_set(cdata->sub.below_obj, EINA_TRUE); + } + + EINA_LIST_FOREACH(cdata->sub.list, l, subc) + _e_client_transform_sub_apply(subc, ec, zoom); + EINA_LIST_REVERSE_FOREACH(cdata->sub.below_list, l, subc) + _e_client_transform_sub_apply(subc, ec, zoom); + + evas_map_free(map); + + ec->transform.zoom = zoom; + ec->transform.angle = angle; + ec->transform.center.x = cx; + ec->transform.center.y = cy; + ec->transformed = EINA_TRUE; +} + +//////////////////////////////////////////// + +E_API void +e_client_transform_clear(E_Client *ec) +{ + E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data; + E_Client *subc; + Eina_List *l; + + evas_object_map_enable_set(ec->frame, EINA_FALSE); + evas_object_map_set(ec->frame, NULL); + + if (cdata->sub.below_obj) + { + evas_object_map_enable_set(cdata->sub.below_obj, EINA_FALSE); + evas_object_map_set(cdata->sub.below_obj, NULL); + } + + EINA_LIST_FOREACH(cdata->sub.list, l, subc) + _e_client_transform_sub_apply(subc, ec, 1.0); + EINA_LIST_REVERSE_FOREACH(cdata->sub.below_list, l, subc) + _e_client_transform_sub_apply(subc, ec, 1.0); + + ec->transform.zoom = 1.0; + ec->transform.angle = 0.0; + ec->transformed = EINA_FALSE; +} + +E_API Eina_Bool +e_client_transform_core_enable_get(E_Client *ec) +{ + if (!ec) return EINA_FALSE; + return ec->transform_core.result.enable; +} + +E_API void +e_client_transform_core_add(E_Client *ec, E_Util_Transform *transform) +{ + if (!ec) return; + if (!transform) return; + + // duplication check + if (ec->transform_core.transform_list && + eina_list_data_find(ec->transform_core.transform_list, transform) == transform) + { + return; + } + + ec->transform_core.transform_list = eina_list_append(ec->transform_core.transform_list, transform); + ec->transform_core.changed = EINA_TRUE; + e_util_transform_ref(transform); + // e_client_transform_core_update(ec); +} + +E_API void +e_client_transform_core_remove(E_Client *ec, E_Util_Transform *transform) +{ + if (!ec) return; + if (!transform) return; + + if (ec->transform_core.transform_list && + eina_list_data_find(ec->transform_core.transform_list, transform) == transform) + { + ec->transform_core.transform_list = eina_list_remove(ec->transform_core.transform_list, transform); + e_util_transform_unref(transform); + ec->transform_core.changed = EINA_TRUE; + } + + e_client_transform_core_update(ec); +} + +E_API void +e_client_transform_core_update(E_Client *ec) +{ + if (!ec) return; + if (ec->new_client) return; + if (!_e_client_transform_core_check_change(ec)) return; + + if (ec->transform_core.transform_list || ec->transform_core.parent.enable) + { + E_Util_Transform_Rect source_rect; + E_Util_Transform_Matrix matrix, boundary_matrix; + Eina_List *l; + Eina_Bool background; + E_Util_Transform *temp_trans; + + // 1. init state + ec->transform_core.result.enable = EINA_TRUE; + e_util_transform_rect_client_rect_get(&source_rect, ec); + e_util_transform_init(&ec->transform_core.result.transform); + + // 2. merge transform + EINA_LIST_FOREACH(ec->transform_core.transform_list, l, temp_trans) + { + e_util_transform_merge(&ec->transform_core.result.transform, temp_trans); + } + + // 2.5 check viewport + if (e_util_transform_viewport_flag_get(&ec->transform_core.result.transform)) + { + int vx = 0, vy = 0, vw = 0, vh = 0; + e_util_transform_viewport_get(&ec->transform_core.result.transform, &vx, &vy, &vw, &vh); + e_util_transform_rect_init(&source_rect, vx, vy, vw, vh); + } + + // 3. apply background transform + matrix = e_util_transform_convert_to_matrix(&ec->transform_core.result.transform, &source_rect); + + if (e_util_transform_bg_transform_flag_get(&ec->transform_core.result.transform)) + { + boundary_matrix = e_util_transform_bg_convert_to_matrix(&ec->transform_core.result.transform, &source_rect); + background = EINA_TRUE; + } + else + { + background = EINA_FALSE; + boundary_matrix = matrix; + } + + if (background != ec->transform_core.background) + { + if (background) + { + e_comp_object_transform_bg_set(ec->frame, EINA_TRUE); + } + else + { + e_comp_object_transform_bg_set(ec->frame, EINA_FALSE); + } + + ec->transform_core.background = background; + } + + // 3.1 if 24bit window then set transp rect + if (!ec->argb) + { + int angle = 0; + + e_util_transform_rotation_round_get(&ec->transform_core.result.transform, 0, 0, &angle); + angle %= 90; + + if (angle == 0) // when transform angle is 0, 90, 180, 270, 360. then set transp rect + e_comp_object_transform_transp_set(ec->frame, EINA_TRUE); + else + e_comp_object_transform_transp_set(ec->frame, EINA_FALSE); + } + else + e_comp_object_transform_transp_set(ec->frame, EINA_FALSE); + + // 3.5 parent matrix multiply + if (ec->transform_core.parent.enable) + { + matrix = e_util_transform_matrix_multiply(&ec->transform_core.parent.matrix, + &matrix); + boundary_matrix = e_util_transform_matrix_multiply(&ec->transform_core.parent.matrix, + &boundary_matrix); + } + + // 4. apply matrix to vertices + ec->transform_core.result.matrix = matrix; + ec->transform_core.result.inv_matrix = e_util_transform_matrix_inverse_get(&matrix); + ec->transform_core.result.vertices = e_util_transform_rect_to_vertices(&source_rect); + ec->transform_core.result.boundary.vertices = e_util_transform_rect_to_vertices(&source_rect); + ec->transform_core.result.vertices = e_util_transform_matrix_multiply_rect_vertex(&matrix, + &ec->transform_core.result.vertices); + ec->transform_core.result.boundary.vertices = e_util_transform_matrix_multiply_rect_vertex(&boundary_matrix, + &ec->transform_core.result.boundary.vertices); + + // 5. apply vertices + e_comp_object_transform_transp_vertices_set(ec->frame, &ec->transform_core.result.vertices); + e_comp_object_transform_bg_vertices_set(ec->frame, &ec->transform_core.result.boundary.vertices); + _e_client_transform_core_boundary_update(ec, &ec->transform_core.result.boundary.vertices); + _e_client_transform_core_vertices_apply(ec, ec->frame, &ec->transform_core.result.vertices, &ec->transform_core.result.transform); + + // 6. subsurface update' + _e_client_transform_core_sub_update(ec, &ec->transform_core.result.vertices); + + if (!e_object_is_del(E_OBJECT(ec))) + _e_client_hook_call(E_CLIENT_HOOK_TRANSFORM_CHANGE, ec); + } + else + { + if (ec->transform_core.result.enable) + { + ec->transform_core.result.enable = EINA_FALSE; + _e_client_transform_core_vertices_apply(ec, ec->frame, NULL, NULL); + e_comp_object_transform_bg_set(ec->frame, EINA_FALSE); + ec->transform_core.background = EINA_FALSE; + e_comp_object_transform_transp_set(ec->frame, EINA_FALSE); + _e_client_transform_core_sub_update(ec, NULL); + + if (!e_object_is_del(E_OBJECT(ec))) + _e_client_hook_call(E_CLIENT_HOOK_TRANSFORM_CHANGE, ec); + } + } + + e_client_visibility_calculate(); +} + +E_API int +e_client_transform_core_transform_count_get(E_Client *ec) +{ + if (!ec) return 0; + if (!ec->transform_core.transform_list) return 0; + return eina_list_count(ec->transform_core.transform_list); +} + +E_API E_Util_Transform* +e_client_transform_core_transform_get(E_Client *ec, int index) +{ + if (!ec) return NULL; + if (!ec->transform_core.transform_list) return NULL; + if (index < 0 || index >= e_client_transform_core_transform_count_get(ec)) + return NULL; + + return (E_Util_Transform*)eina_list_nth(ec->transform_core.transform_list, index); +} + +E_API void +e_client_transform_core_input_transform(E_Client *ec, int x, int y, int *out_x, int *out_y) +{ + E_Util_Transform_Vertex vertex, result_vertex; + + if (!ec) return; + if (!e_client_transform_core_enable_get(ec)) return; + + e_util_transform_vertex_init(&vertex, x, y, 0.0, 1.0); + + result_vertex = e_util_transform_matrix_multiply_vertex(&ec->transform_core.result.inv_matrix, &vertex); + e_util_transform_vertex_pos_round_get(&result_vertex, out_x, out_y, NULL, NULL); +} + +E_API void +e_client_transform_core_input_inv_transform(E_Client *ec, int x, int y, int *out_x, int *out_y) +{ + E_Util_Transform_Vertex vertex, result_vertex; + + if (!ec) return; + if (!e_client_transform_core_enable_get(ec)) return; + + e_util_transform_vertex_init(&vertex, x, y, 0.0, 1.0); + + result_vertex = e_util_transform_matrix_multiply_vertex(&ec->transform_core.result.matrix, &vertex); + e_util_transform_vertex_pos_round_get(&result_vertex, out_x, out_y, NULL, NULL); +} + +E_API void +e_client_transform_core_input_inv_rect_transform(E_Client *ec, int x, int y, int *out_x, int *out_y) +{ + if (!ec) return; + if (!e_client_transform_core_enable_get(ec)) return; + + e_util_transform_matrix_inv_rect_coords_get(&ec->transform_core.result.transform, + &ec->transform_core.result.vertices, + ec->zone->w, ec->zone->h, + x, y, out_x, out_y); +} + +E_API E_Pixmap * +e_client_pixmap_change(E_Client *ec, E_Pixmap *newcp) +{ + E_Pixmap_Type oldtype, newtype; + E_Pixmap *oldcp; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(ec->pixmap, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(newcp, NULL); + + oldcp = ec->pixmap; + + oldtype = e_pixmap_type_get(oldcp); + if (oldtype >= E_PIXMAP_TYPE_MAX) return NULL; + + newtype = e_pixmap_type_get(newcp); + if (newtype >= E_PIXMAP_TYPE_MAX) return NULL; + + if (eina_hash_find(clients_hash[oldtype], &oldcp)) + eina_hash_del_by_key(clients_hash[oldtype], &oldcp); + e_pixmap_client_set(oldcp, NULL); + + ec->pixmap = newcp; + e_pixmap_client_set(newcp, ec); + + eina_hash_add(clients_hash[newtype], &newcp, ec); + + return oldcp; +} + +E_API void +e_client_window_role_set(E_Client *ec, const char *role) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + + if (eina_stringshare_replace(&ec->icccm.window_role, role)) + _e_client_hook_call(E_CLIENT_HOOK_WINDOW_ROLE_CHANGE, ec); +} + +E_API Eina_Bool +e_client_key_send(E_Client *ec, int keycode, Eina_Bool pressed, Evas_Device *dev, unsigned int time) +{ + Eina_Bool res; + + res = e_comp_wl_key_send(ec, keycode, pressed, dev, time); + + return res; +} + +E_API Eina_Bool +e_client_touch_send(E_Client *ec, int idx, int x, int y, Eina_Bool pressed, Evas_Device *dev, double radius_x, double radius_y, double pressure, double angle, unsigned int time) +{ + Eina_Bool res; + + res = e_comp_wl_touch_send(ec, idx, x, y, pressed, dev, radius_x, radius_y, pressure, angle, time); + + return res; +} + +E_API Eina_Bool +e_client_touch_update_send(E_Client *ec, int idx, int x, int y, Evas_Device *dev, double radius_x, double radius_y, double pressure, double angle, unsigned int time) +{ + Eina_Bool res; + + res = e_comp_wl_touch_update_send(ec, idx, x, y, dev, radius_x, radius_y, pressure, angle, time); + + return res; +} + +E_API Eina_Bool +e_client_touch_cancel_send(E_Client *ec) +{ + Eina_Bool res; + + res = e_comp_wl_touch_cancel_send(ec); + + return res; +} + +E_API Eina_Bool +e_client_mouse_button_send(E_Client *ec, int buttons, Eina_Bool pressed, Evas_Device *dev, unsigned int time) +{ + Eina_Bool res; + + res = e_comp_wl_mouse_button_send(ec, buttons, pressed, dev, time); + + return res; +} + +E_API Eina_Bool +e_client_mouse_move_send(E_Client *ec, int x, int y, Evas_Device *dev, unsigned int time) +{ + Eina_Bool res; + + res = e_comp_wl_mouse_move_send(ec, x, y, dev, time); + + return res; +} + +E_API Eina_Bool +e_client_mouse_wheel_send(E_Client *ec, int direction, int z, Evas_Device *dev, unsigned int time) +{ + Eina_Bool res; + + res = e_comp_wl_mouse_wheel_send(ec, direction, z, dev, time); + + return res; +} + +E_API Eina_Bool +e_client_mouse_in_send(E_Client *ec, int x, int y, Evas_Device *dev, unsigned int time) +{ + Eina_Bool res; + + res = e_comp_wl_mouse_in_send(ec, x, y, dev, time); + + return res; +} + +E_API Eina_Bool +e_client_mouse_out_send(E_Client *ec, Evas_Device *dev, unsigned int time) +{ + Eina_Bool res; + + res = e_comp_wl_mouse_out_send(ec, dev, time); + + return res; +} + +E_API Eina_Bool +e_client_video_client_has(E_Client *ec) +{ + return e_comp_wl_video_subsurface_has(ec); +} + +E_API Eina_Bool +e_client_normal_client_has(E_Client *ec) +{ + return e_comp_wl_normal_subsurface_has(ec); +} + +E_API Eina_Bool +e_client_cursor_hide(E_Client *ec) +{ + return e_comp_wl_cursor_hide(ec); +} + +E_API void +e_client_visibility_force_obscured_set(E_Client *ec, Eina_Bool set) +{ + if (!ec) return; + + ELOGF("TZVIS", "VIS_FORCE_OBSCURED :%d", ec, set); + + ec->visibility.force_obscured = set; + e_client_visibility_calculate(); +} + +/* tizen_move_resize */ +EINTERN Eina_Bool +e_client_pending_geometry_has(E_Client *ec) +{ + if (!eina_list_count(ec->surface_sync.pending_geometry)) + return EINA_FALSE; + + return ec->surface_sync.wait_commit; +} + +EINTERN void +e_client_pending_geometry_flush(E_Client *ec) +{ + E_Client_Pending_Geometry *geo; + + if (!eina_list_count(ec->surface_sync.pending_geometry)) + { + EINA_LIST_FREE(ec->surface_sync.pending_geometry, geo) + { + E_FREE(geo); + } + ec->surface_sync.wait_commit = EINA_FALSE; + ELOGF("POSSIZE", "pending geometry has flushed", ec); + } +} diff --git a/src/bin/e_client_common.h b/src/bin/e_client_common.h new file mode 100644 index 0000000000..de61fc32f1 --- /dev/null +++ b/src/bin/e_client_common.h @@ -0,0 +1,1336 @@ +#ifdef E_TYPEDEFS + +#if 0//ndef HAVE_IOT +typedef enum _E_Client_Screen_Limit +{ + E_CLIENT_OFFSCREEN_LIMIT_ALLOW_PARTIAL = 0, + E_CLIENT_OFFSCREEN_LIMIT_ALLOW_FULL = 1, + E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE = 2 +} E_Client_Screen_Limit; + +typedef enum _E_Icon_Preference +{ + E_ICON_PREF_E_DEFAULT, + E_ICON_PREF_NETWM, + E_ICON_PREF_USER +} E_Icon_Preference; + +typedef enum _E_Direction +{ + E_DIRECTION_UP, + E_DIRECTION_DOWN, + E_DIRECTION_LEFT, + E_DIRECTION_RIGHT +} E_Direction; + +typedef enum _E_Transition +{ + E_TRANSITION_LINEAR = 0, + E_TRANSITION_SINUSOIDAL = 1, + E_TRANSITION_ACCELERATE = 2, + E_TRANSITION_DECELERATE = 3, + E_TRANSITION_ACCELERATE_LOTS = 4, + E_TRANSITION_DECELERATE_LOTS = 5, + E_TRANSITION_SINUSOIDAL_LOTS = 6, + E_TRANSITION_BOUNCE = 7, + E_TRANSITION_BOUNCE_LOTS = 8 +} E_Transition; + +typedef enum _E_Stacking +{ + E_STACKING_NONE, + E_STACKING_ABOVE, + E_STACKING_BELOW +} E_Stacking; + +typedef enum _E_Focus_Policy +{ + E_FOCUS_CLICK, + E_FOCUS_MOUSE, + E_FOCUS_SLOPPY, + E_FOCUS_LAST, +} E_Focus_Policy; + +typedef enum _E_Focus_Policy_Ext +{ + E_FOCUS_EXT_NONE, + E_FOCUS_EXT_TOP_STACK, +} E_Focus_Policy_Ext; + +typedef enum +{ + /* same as ecore-x types */ + E_WINDOW_TYPE_UNKNOWN = 0, + E_WINDOW_TYPE_DESKTOP, + E_WINDOW_TYPE_DOCK, + E_WINDOW_TYPE_TOOLBAR, + E_WINDOW_TYPE_MENU, + E_WINDOW_TYPE_UTILITY, + E_WINDOW_TYPE_SPLASH, + E_WINDOW_TYPE_DIALOG, + E_WINDOW_TYPE_NORMAL, + E_WINDOW_TYPE_DROPDOWN_MENU, + E_WINDOW_TYPE_POPUP_MENU, + E_WINDOW_TYPE_TOOLTIP, + E_WINDOW_TYPE_NOTIFICATION, + E_WINDOW_TYPE_COMBO, + E_WINDOW_TYPE_DND, + /* since UNKNOWN was used improperly in comp matching, + * this value is a placeholder to indicate that we want + * only type UNKNOWN windows + */ + E_WINDOW_TYPE_REAL_UNKNOWN = 999 +} E_Window_Type; + +typedef enum _E_Focus_Setting +{ + E_FOCUS_NONE, + E_FOCUS_NEW_WINDOW, + E_FOCUS_NEW_DIALOG, + E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED +} E_Focus_Setting; + +typedef enum _E_Maximize +{ + E_MAXIMIZE_NONE = 0x00000000, + E_MAXIMIZE_FULLSCREEN = 0x00000001, + E_MAXIMIZE_SMART = 0x00000002, + E_MAXIMIZE_EXPAND = 0x00000003, + E_MAXIMIZE_FILL = 0x00000004, + E_MAXIMIZE_TYPE = 0x0000000f, + E_MAXIMIZE_VERTICAL = 0x00000010, + E_MAXIMIZE_HORIZONTAL = 0x00000020, + E_MAXIMIZE_BOTH = 0x00000030, + E_MAXIMIZE_LEFT = 0x00000070, + E_MAXIMIZE_RIGHT = 0x000000b0, + E_MAXIMIZE_DIRECTION = 0x000000f0 +} E_Maximize; + +// TODO: should be removed - yigl +typedef enum _E_Fullscreen +{ + /* Resize window */ + E_FULLSCREEN_RESIZE, + /* Change screen resolution and resize window */ + E_FULLSCREEN_ZOOM +} E_Fullscreen; + +typedef enum _E_Transient +{ + E_TRANSIENT_ABOVE, + E_TRANSIENT_BELOW, +} E_Transient; + +typedef enum _E_Window_Placement +{ + E_WINDOW_PLACEMENT_SMART, + E_WINDOW_PLACEMENT_ANTIGADGET, + E_WINDOW_PLACEMENT_CURSOR, + E_WINDOW_PLACEMENT_MANUAL +} E_Window_Placement; +#endif//HAVE_IOT + +typedef enum E_Client_Property +{ + E_CLIENT_PROPERTY_NONE = 0, + E_CLIENT_PROPERTY_SIZE = (1 << 0), + E_CLIENT_PROPERTY_POS = (1 << 1), + E_CLIENT_PROPERTY_TITLE = (1 << 2), + E_CLIENT_PROPERTY_ICON = (1 << 3), + E_CLIENT_PROPERTY_URGENCY = (1 << 4), + E_CLIENT_PROPERTY_GRAVITY = (1 << 5), + E_CLIENT_PROPERTY_NETWM_STATE = (1 << 6), + E_CLIENT_PROPERTY_STICKY = (1 << 7), + E_CLIENT_PROPERTY_CLIENT_TYPE = (1 << 8), +} E_Client_Property; + +#if 0//ndef HAVE_IOT +#ifdef _F_E_VIRTUAL_KEYBOARD_TYPE_ +typedef enum _E_Virtual_Keyboard_Window_Type +{ + E_VIRTUAL_KEYBOARD_WINDOW_TYPE_NONE = 0, + E_VIRTUAL_KEYBOARD_WINDOW_TYPE_KEYPAD = 1, + E_VIRTUAL_KEYBOARD_WINDOW_TYPE_PREDICTION = 2, + E_VIRTUAL_KEYBOARD_WINDOW_TYPE_MAGNIFIER = 3, + E_VIRTUAL_KEYBOARD_WINDOW_TYPE_POPUP = 4, +} E_Virtual_Keyboard_Window_Type; +#endif + +#ifdef _F_ZONE_WINDOW_ROTATION_ +typedef enum _E_Client_Rotation_Type +{ + E_CLIENT_ROTATION_TYPE_NORMAL = 0, + E_CLIENT_ROTATION_TYPE_DEPENDENT = 1 +} E_Client_Rotation_Type; +#endif + +typedef enum _E_Visibility +{ + E_VISIBILITY_UNKNOWN = -1, + E_VISIBILITY_UNOBSCURED = 0, + E_VISIBILITY_PARTIALLY_OBSCURED = 1, + E_VISIBILITY_FULLY_OBSCURED = 2, + E_VISIBILITY_PRE_UNOBSCURED = 3, +} E_Visibility; + +typedef enum _E_Changable_Layer_Type +{ + E_CHANGABLE_LAYER_TYPE_TRANSIENT = 0, + E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION = 1, + E_CHANGABLE_LAYER_TYPE_MAX +} E_Changable_Layer_Type; + +typedef enum _E_Indicator_Visible_Type +{ + E_INDICATOR_VISIBLE_TYPE_HIDDEN = 0, + E_INDICATOR_VISIBLE_TYPE_SHOWN, +} E_Indicator_Visible_Type; + +typedef enum _E_Indicator_State +{ + E_INDICATOR_STATE_UNKNOWN = 0, + E_INDICATOR_STATE_OFF, + E_INDICATOR_STATE_ON +} E_Indicator_State; + +typedef enum _E_Indicator_Opacity_Mode +{ + E_INDICATOR_OPACITY_MODE_UNKNOWN = 0, + E_INDICATOR_OPACITY_MODE_OPAQUE, + E_INDICATOR_OPACITY_MODE_TRANSLUCENT, + E_INDICATOR_OPACITY_MODE_TRANSPARENT, + E_INDICATOR_OPACITY_MODE_BG_TRANSPARENT, +} E_Indicator_Opacity_Mode; +#endif//HAVE_IOT + +typedef struct E_Client E_Client; +typedef struct E_Event_Client E_Event_Client; +typedef struct _E_Event_Client_Property E_Event_Client_Property; +typedef struct _E_Client_Hook E_Client_Hook; +typedef struct _E_Client_Intercept_Hook E_Client_Intercept_Hook; + +#if 0//ndef HAVE_IOT +typedef struct _E_Client_Pending_Resize E_Client_Pending_Resize; +typedef struct _E_Client_Pending_Geometry E_Client_Pending_Geometry; +typedef struct E_Event_Client_Zone_Set E_Event_Client_Zone_Set; +typedef struct E_Event_Client_Desk_Set E_Event_Client_Desk_Set; + +#ifdef _F_ZONE_WINDOW_ROTATION_ +typedef struct E_Event_Client E_Event_Client_Rotation_Change_Begin; +typedef struct E_Event_Client E_Event_Client_Rotation_Change_Cancel; +typedef struct E_Event_Client E_Event_Client_Rotation_Change_End; +#endif +#endif//HAVE_IOT + +typedef enum _E_Client_Hook_Point +{ + E_CLIENT_HOOK_EVAL_PRE_FETCH, + E_CLIENT_HOOK_EVAL_FETCH, + E_CLIENT_HOOK_EVAL_PRE_POST_FETCH, + E_CLIENT_HOOK_EVAL_POST_FETCH, + E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN, + E_CLIENT_HOOK_EVAL_POST_FRAME_ASSIGN, + E_CLIENT_HOOK_EVAL_PRE_NEW_CLIENT, + E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT, + E_CLIENT_HOOK_EVAL_END, + E_CLIENT_HOOK_FOCUS_SET, + E_CLIENT_HOOK_FOCUS_UNSET, + E_CLIENT_HOOK_NEW_CLIENT, + E_CLIENT_HOOK_DESK_SET, + E_CLIENT_HOOK_MOVE_BEGIN, + E_CLIENT_HOOK_MOVE_UPDATE, + E_CLIENT_HOOK_MOVE_END, + E_CLIENT_HOOK_RESIZE_BEGIN, + E_CLIENT_HOOK_RESIZE_UPDATE, + E_CLIENT_HOOK_RESIZE_END, + E_CLIENT_HOOK_FULLSCREEN_PRE, + E_CLIENT_HOOK_DEL, + E_CLIENT_HOOK_UNREDIRECT, + E_CLIENT_HOOK_REDIRECT, +#ifdef _F_E_CLIENT_NEW_CLIENT_POST_HOOK_ + E_CLIENT_HOOK_NEW_CLIENT_POST, +#endif + E_CLIENT_HOOK_EVAL_VISIBILITY, + E_CLIENT_HOOK_ICONIFY, + E_CLIENT_HOOK_UNICONIFY, + E_CLIENT_HOOK_AUX_HINT_CHANGE, + E_CLIENT_HOOK_WINDOW_ROLE_CHANGE, + E_CLIENT_HOOK_CAL_VISIBILITY_DISPLAY_OFF, + E_CLIENT_HOOK_TRANSFORM_CHANGE, + E_CLIENT_HOOK_LAST, +} E_Client_Hook_Point; + +typedef enum _E_Client_Intercept_Hook_Point +{ + E_CLIENT_INTERCEPT_HOOK_FOCUS_REVERT, + E_CLIENT_INTERCEPT_HOOK_LAST, +} E_Client_Intercept_Hook_Point; + +typedef void (*E_Client_Hook_Cb)(void *data, E_Client *ec); +typedef Eina_Bool (*E_Client_Intercept_Hook_Cb)(void *data, E_Client *ec); +#if 0//ndef HAVE_IOT +typedef void (*E_Client_Move_Intercept_Cb)(E_Client *, int x, int y); +typedef void (*E_Client_Layout_Cb)(void); +#endif//HAVE_IOT + +#else + +#define E_CLIENT_TYPE (int)0xE0b01002 + +struct E_Event_Client +{ + E_Client *ec; +}; + +struct _E_Event_Client_Property +{ + E_Client *ec; + unsigned int property; +}; + +struct _E_Client_Hook +{ + EINA_INLIST; + E_Client_Hook_Point hookpoint; + E_Client_Hook_Cb func; + void *data; + unsigned char delete_me : 1; +}; + +struct _E_Client_Intercept_Hook +{ + EINA_INLIST; + E_Client_Intercept_Hook_Point hookpoint; + E_Client_Intercept_Hook_Cb func; + void *data; + unsigned char delete_me : 1; +}; + +#if 0//ndef HAVE_IOT +struct E_Event_Client_Desk_Set +{ + E_Client *ec; + E_Desk *desk; +}; + +struct E_Event_Client_Zone_Set +{ + E_Client *ec; + E_Zone *zone; +}; + +struct _E_Client_Pending_Resize +{ + int w, h; + unsigned int serial; +}; + +typedef enum +{ + E_GEOMETRY_NONE = 0, + E_GEOMETRY_POS = (1 << 0), + E_GEOMETRY_SIZE = (1 << 1) +} E_Client_Demand_Geometry; + +struct _E_Client_Pending_Geometry +{ + E_Client_Demand_Geometry mode; + int x, y, w, h; + unsigned int serial; +}; +#endif//HAVE_IOT + +struct E_Client +{ + E_Object e_obj_inherit; + EINA_INLIST; + +#if 0//ndef HAVE_IOT + E_Pixmap *pixmap; + int depth; + int x, y, w, h; //frame+client geom + struct { + int x, y, w, h; //frame+client geom before move or resize callback + } pre_cb; + Eina_Rectangle client; //client geom + Evas_Object *frame; //comp object + E_Zone *zone; + E_Desk *desk; + + Ecore_Poller *ping_poller; + Ecore_Timer *kill_timer; + + E_Client *modal; + + E_Client *leader; + Eina_List *group; + + E_Client *parent; + Eina_List *transients; + + E_Layer layer; + + Eina_Rectangle *shape_rects; + unsigned int shape_rects_num; + + Eina_Rectangle *shape_input_rects; + unsigned int shape_input_rects_num; + + Eina_Stringshare *internal_icon; + Eina_Stringshare *internal_icon_key; + + E_Direction shade_dir; +#endif//HAVE_IOT + E_Comp_Client_Data *comp_data; +#if 0//ndef HAVE_IOT + E_Action *cur_mouse_action; + + int border_size; //size of client's border + + struct + { + struct + { + int x, y, w, h; + int mx, my; + } current, last_down[3], last_up[3]; + Eina_Bool in : 1; + } mouse; + + struct + { + struct + { + int x, y, w, h; + int mx, my; + int button; + } down; + } moveinfo; + + unsigned char ignore_first_unmap; + E_Pointer_Mode resize_mode; + + struct + { + Eina_Bool mapping_change : 1; + Eina_Bool iconic_shading : 1; + } hacks; + + struct + { + unsigned char changed : 1; + unsigned char user_selected : 1; + Eina_Stringshare *name; + } border; + + struct + { + int x, y, w, h; + E_Layer layer; + int zone; + E_Maximize maximized; + } saved; + + struct + { + unsigned char valid : 1; + int x, y, w, h; + struct + { + int x, y, w, h; + } saved; + } pre_res_change; + + unsigned char shaped : 1; + unsigned char argb : 1; + + /* ICCCM */ + struct + { + Eina_Stringshare *title; + Eina_Stringshare *name; + Eina_Stringshare *class; + Eina_Stringshare *icon_name; + Eina_Stringshare *machine; + int min_w, min_h; + int max_w, max_h; + int base_w, base_h; + int step_w, step_h; + int start_x, start_y; + double min_aspect, max_aspect; + Ecore_Window icon_window; + Ecore_Window window_group; + Ecore_Window transient_for; + Ecore_Window client_leader; + Eina_Stringshare *window_role; + unsigned char take_focus : 1; + unsigned char accepts_focus : 1; + unsigned char urgent : 1; + unsigned char delete_request : 1; + unsigned char request_pos : 1; + struct + { + int argc; + char **argv; + } command; + struct + { + unsigned char title : 1; + unsigned char name_class : 1; + unsigned char icon_name : 1; + unsigned char machine : 1; + unsigned char hints : 1; + unsigned char size_pos_hints : 1; + unsigned char protocol : 1; + unsigned char transient_for : 1; + unsigned char client_leader : 1; + unsigned char window_role : 1; + unsigned char state : 1; + unsigned char command : 1; + } fetch; + } icccm; + + /* MWM */ + struct + { + unsigned char exists : 1; + unsigned char borderless : 1; + struct + { + unsigned char hints : 1; + } fetch; + } mwm; + + /* NetWM */ + struct + { + pid_t pid; + unsigned int desktop; + Eina_Stringshare *name; + Eina_Stringshare *icon_name; + + Ecore_X_Icon *icons; + + int num_icons; + unsigned int user_time; + unsigned char opacity; + Eina_Bool opacity_changed : 1; // prevent fetching opacity next prop change + struct + { + int left; + int right; + int top; + int bottom; + int left_start_y; + int left_end_y; + int right_start_y; + int right_end_y; + int top_start_x; + int top_end_x; + int bottom_start_x; + int bottom_end_x; + } strut; + unsigned char ping : 1; + struct + { + unsigned char request : 1; + unsigned char alarm : 1; + unsigned int wait; + unsigned int serial; + double send_time; + } sync; + + /* NetWM Window state */ + struct + { + unsigned char modal : 1; + unsigned char sticky : 1; + unsigned char maximized_v : 1; + unsigned char maximized_h : 1; + unsigned char shaded : 1; + unsigned char skip_taskbar : 1; + unsigned char skip_pager : 1; + unsigned char hidden : 1; + unsigned char fullscreen : 1; + E_Stacking stacking; + } state; + + /* NetWM Window allowed actions */ + struct + { + unsigned char move : 1; + unsigned char resize : 1; + unsigned char minimize : 1; + unsigned char shade : 1; + unsigned char stick : 1; + unsigned char maximized_h : 1; + unsigned char maximized_v : 1; + unsigned char fullscreen : 1; + unsigned char change_desktop : 1; + unsigned char close : 1; + } action; + E_Window_Type type; + E_Window_Type *extra_types; + int extra_types_num; + int startup_id; + + struct + { + unsigned char name : 1; + unsigned char icon_name : 1; + unsigned char icon : 1; + unsigned char user_time : 1; + unsigned char strut : 1; + unsigned char type : 1; + unsigned char state : 1; + unsigned char opacity : 1; + /* No, fetch on new_client, shouldn't be changed after map. + unsigned char pid : 1; + */ + /* No, ignore this + unsigned char desktop : 1; + */ + } fetch; + + struct + { + unsigned char state : 1; + } update; + } netwm; + + /* Extra e stuff */ + struct + { + struct + { + struct + { + int x, y; + + unsigned char updated : 1; + } video_position; + Ecore_Window video_parent; + E_Client *video_parent_client; + Eina_List *video_child; + struct + { + Eina_Stringshare *name; + Eina_Stringshare **available_list; + Eina_Stringshare *set; + Eina_Stringshare *wait; + E_Desk *wait_desk; + E_Object_Delfn *wait_desk_delfn; + int num; + unsigned char wait_for_done : 1; + unsigned char use : 1; + } profile; + unsigned char centered : 1; + unsigned char video : 1; +#ifdef _F_ZONE_WINDOW_ROTATION_ + struct + { + E_Client_Rotation_Type type; + struct + { + int prev, curr, next, reserve; + } ang; + struct + { + int x, y, w, h; + } geom[4]; + unsigned char support : 1; + unsigned char geom_hint: 1; + unsigned char pending_change_request : 1; + unsigned char pending_show : 1; // newly created window that has to be rotated will be show after rotating done. + // so, it will be used pending e_border_show called at main eval time. + unsigned char wait_for_done: 1; + unsigned char app_set : 1; // app wants to communicate with the window manager + int rot; // decided rotation by the window manager + int preferred_rot; // app specified rotation + int *available_rots; // app specified available rotations + unsigned int count; // number of elements of available rotations + unsigned int nopending_render : 1; // app wants to show rendering jobs before sending rotation_done + // it is set by 'wm.policy.win.rot.render.nopending' aux hint + } rot; +#endif + } state; + + struct + { +#ifdef _F_ZONE_WINDOW_ROTATION_ + struct + { + unsigned char support : 1; + unsigned char geom_hint : 1; + unsigned char app_set : 1; // app wants to communicate with the window manager + unsigned char preferred_rot : 1; // app specified rotation + unsigned char available_rots : 1; // app specified available rotations + unsigned char need_rotation : 1; + } rot; +#endif + unsigned char state : 1; + unsigned char opaque : 1; + unsigned char video_parent : 1; + unsigned char video_position : 1; + unsigned char profile : 1; + } fetch; + } e; + + struct + { + struct + { + unsigned char state : 1; + unsigned char vkbd : 1; + } fetch; + unsigned char have_property : 1; + unsigned char vkbd : 1; +#ifdef _F_E_VIRTUAL_KEYBOARD_TYPE_ + E_Virtual_Keyboard_Window_Type win_type; +#endif + unsigned char floating : 1; + } vkbd; + + struct + { + unsigned char visible : 1; + unsigned char pos : 1; + unsigned char size : 1; + unsigned char stack : 1; + unsigned char prop : 1; + unsigned char border : 1; + unsigned char reset_gravity : 1; + unsigned char shading : 1; + unsigned char shaded : 1; + unsigned char shape : 1; + unsigned char shape_input : 1; + unsigned char icon : 1; + Eina_Bool internal_state : 1; + Eina_Bool need_maximize : 1; + Eina_Bool need_unmaximize : 1; +#ifdef _F_ZONE_WINDOW_ROTATION_ + Eina_Bool rotation : 1; +#endif + Eina_Bool accepts_focus : 1; + Eina_Bool tz_position : 1; /* true when new position is set using tizen_position interface */ + unsigned char title : 1; + } changes; + + struct + { + int opaque; + int obscured; + unsigned char changed : 1; + Eina_Bool skip : 1; + Eina_Bool force_obscured : 1; + int last_sent_type; + } visibility; + + struct + { + double zoom; + double angle; + + Evas_Point center; + Evas_Point adjusted; + + struct + { + double x, y, z; + } saved[4]; + } transform; + + unsigned int visible : 1; // client is set to be visible by display server (never use this) + unsigned int hidden : 1; // set when window has been hidden by api and should not be shown + unsigned int moving : 1; + unsigned int focused : 1; + unsigned int new_client : 1; + unsigned int re_manage : 1; // client is persisting from before E restart + unsigned int placed : 1; + unsigned int shading : 1; + unsigned int shaded : 1; + unsigned int iconic : 1; + unsigned int deskshow : 1; + unsigned int sticky : 1; + unsigned int urgent : 1; + unsigned int shaped_input : 1; + unsigned int need_shape_merge : 1; + unsigned int need_shape_export : 1; + unsigned int fullscreen : 1; + unsigned int need_fullscreen : 1; + unsigned int skip_fullscreen : 1; + unsigned int already_unparented : 1; + unsigned int need_reparent : 1; + unsigned int button_grabbed : 1; + unsigned int delete_requested : 1; + unsigned int ping_ok : 1; + unsigned int hung : 1; + unsigned int take_focus : 1; + unsigned int want_focus : 1; + unsigned int user_skip_winlist : 1; + E_Maximize maximized; + E_Fullscreen fullscreen_policy; // TODO: should be removed - yigl + E_Transient transient_policy; + unsigned int borderless : 1; + unsigned char offer_resistance : 1; + Eina_Stringshare *bordername; + + unsigned int lock_user_location : 1; /*DONE*/ + unsigned int lock_client_location : 1; /*DONE*/ + unsigned int lock_user_size : 1; /*DONE*/ + unsigned int lock_client_size : 1; /*DONE*/ + unsigned int lock_user_stacking : 1; /*DONE*/ + unsigned int lock_client_stacking : 1; /*DONE*/ + unsigned int lock_user_iconify : 1; /*DONE*/ + unsigned int lock_client_iconify : 1; /*DONE*/ + unsigned int lock_user_desk : 1; + unsigned int lock_client_desk : 1; + unsigned int lock_user_sticky : 1; /*DONE*/ + unsigned int lock_client_sticky : 1; /*DONE*/ + unsigned int lock_user_shade : 1; /*DONE*/ + unsigned int lock_client_shade : 1; /*DONE*/ + unsigned int lock_user_maximize : 1; /*DONE*/ + unsigned int lock_client_maximize : 1; /*DONE*/ + unsigned int lock_user_fullscreen : 1; /*DONE*/ + unsigned int lock_client_fullscreen : 1; /*DONE*/ + unsigned int lock_border : 1; /*DONE*/ + unsigned int lock_close : 1; /*DONE*/ + unsigned int lock_focus_in : 1; /*DONE*/ + unsigned int lock_focus_out : 1; /*DONE*/ + unsigned int lock_life : 1; /*DONE*/ + + unsigned int stolen : 1; + + unsigned int internal : 1; + unsigned int internal_no_remember : 1; /* TODO: should be removed */ + unsigned int internal_no_reopen : 1; + Eina_Bool dead : 1; + + Evas_Object *internal_elm_win; + + double ping; + + unsigned char changed : 1; + + unsigned char icon_preference; + + struct + { + int x, y; + int modified; + } shelf_fix; + + Eina_List *stick_desks; + Evas_Object *color_editor; + E_Dialog *border_prop_dialog; + Eina_List *pending_resize; + + struct + { + unsigned char start : 1; + int x, y; + } drag; + + E_Client_Move_Intercept_Cb move_intercept_cb; + void *remember; /* TODO: should be removed */ + + unsigned char comp_hidden : 1; + + unsigned char post_move : 1; + unsigned char post_resize : 1; + unsigned char post_show : 1; + unsigned char during_lost : 1; + + Ecore_Idle_Enterer *post_job; + + E_Focus_Policy focus_policy_override; + + Eina_Bool override : 1; + Eina_Bool input_only : 1; + Eina_Bool dialog : 1; + Eina_Bool tooltip : 1; + Eina_Bool redirected : 1; + Eina_Bool unredirected_single : 1; //window has been selectively unredirected + Eina_Bool shape_changed : 1; + Eina_Bool layer_block : 1; // client is doing crazy stuff and should not be relayered in protocol + Eina_Bool layer_pending : 1; // change inlist stack but postpone evas stack + Eina_Bool ignored : 1; // client is comp-ignored + Eina_Bool no_shape_cut : 1; // client shape should not be cut + Eina_Bool maximize_override : 1; // client is doing crazy stuff and should "just do it" when moving/resizing + Eina_Bool transformed : 1; + Eina_Bool keyboard_resizing : 1; + Eina_Bool gesture_disable : 1; + Eina_Bool floating : 1; //client is set as floating mode + Eina_Bool first_mapped : 1; + Eina_Bool post_raise : 1; + Eina_Bool post_lower : 1; + Eina_Bool animatable : 1; //client is animatable (can apply animation) + + Eina_Bool on_post_updates : 1; // client is on the post update list + uuid_t uuid; +#endif//HAVE_IOT + + int client_type; //e_client_type + +#if 0//ndef HAVE_IOT + struct + { + unsigned char by_client : 1; + unsigned char not_raise : 1; + unsigned char skip_iconify : 1; + unsigned char skip_by_remote : 1; // skip iconify by remote surface client + unsigned char deiconify_update : 1; // wait client render if deiconify_update is 1 + unsigned char buffer_flush : 1; // 0: no flush, 1: flush buffer when iconify + } exp_iconify; + + struct + { + Eina_Bool set; + Eina_Bool saved; + E_Layer saved_layer; // original layer + } changable_layer[E_CHANGABLE_LAYER_TYPE_MAX]; + + struct + { + Eina_List *transform_list; + Eina_Bool background; + Eina_Bool changed; + + struct + { + int client_x, client_y, client_w, client_h; + int frame_w, frame_h; + } backup; + + struct + { + Eina_Bool enable; + E_Util_Transform_Matrix matrix; + E_Util_Transform_Matrix inv_matrix; + E_Util_Transform_Rect_Vertex vertices; + E_Util_Transform transform; + + struct + { + E_Util_Transform_Rect_Vertex vertices; + int x, y, w, h; + } boundary; + + } result; + + struct + { + Eina_Bool enable; + E_Util_Transform_Matrix matrix; + } parent; + } transform_core; + + struct + { + unsigned char resizable : 1; // or scalable + unsigned char splited : 1; + int s_id; // split(slot) id + } layout; + + Ecore_Timer *map_timer; + Eina_Bool pointer_enter_sent; + + Eina_Bool launching : 1; + Eina_Bool extra_animating : 1; + Eina_Bool bg_state : 1; + + struct + { + E_Indicator_State state; + E_Indicator_Opacity_Mode opacity_mode; + E_Indicator_Visible_Type visible_type; + } indicator; + + E_Plane_Renderer_Client *renderer_client; + + struct + { + Eina_Bool provider : 1; + Eina_Bool consumer : 1; + int bind_ref; + } remote_surface; + + Eina_Bool is_cursor : 1; // The client is a cursor client + + int effect_type; + Eina_Bool use_splash : 1; + Eina_Bool saved_img : 1; // indicates that window has been saved as the image file even once + Eina_Bool skip_save_img: 1; // indicates that window doesn't want to save its image file + + E_Hwc_Window *hwc_window; // hwc window for the tdm_hwc. + int comp_override; + + struct + { + Eina_Bool wait_commit : 1; + unsigned int serial; + Eina_List *pending_geometry; // E_Client_Pending_Geometry + } surface_sync; + + Eina_Bool on_render_list : 1; // client is on the render list + + // flag to check event pairing + struct + { + Eina_Bool add : 1; // ADD / REMOVE + Eina_Bool show : 1; // SHOW / HIDE + } reg_ev; + + Evas_Object *magnifier_proxy; // The proxy object used by magnifier + Eina_Bool is_magnifier : 1; // The client is a magnifier client +#endif//HAVE_IOT +}; + +#define e_client_focus_policy_click(ec) \ + ((ec->focus_policy_override == E_FOCUS_CLICK) || (e_config->focus_policy == E_FOCUS_CLICK)) + +/* macro for finding misuse of changed flag */ +#if 0 +# define EC_CHANGED(EC) \ + do { \ + if (e_object_is_del(E_OBJECT(EC))) \ + EINA_LOG_CRIT("CHANGED SET ON DELETED CLIENT!"); \ + EC->changed = 1; \ + INF("%s:%d - EC CHANGED: %p", __FILE__, __LINE__, EC); \ + } while (0) +#else +# define EC_CHANGED(EC) EC->changed = 1 +#endif + +#define E_CLIENT_FOREACH(EC) \ + for (EC = e_client_bottom_get(); EC; EC = e_client_above_get(EC)) + +#define E_CLIENT_REVERSE_FOREACH(EC) \ + for (EC = e_client_top_get(); EC; EC = e_client_below_get(EC)) + + +E_API extern int E_EVENT_CLIENT_ADD; +E_API extern int E_EVENT_CLIENT_REMOVE; +E_API extern int E_EVENT_CLIENT_ZONE_SET; +E_API extern int E_EVENT_CLIENT_DESK_SET; +E_API extern int E_EVENT_CLIENT_RESIZE; +E_API extern int E_EVENT_CLIENT_MOVE; +E_API extern int E_EVENT_CLIENT_SHOW; +E_API extern int E_EVENT_CLIENT_HIDE; +E_API extern int E_EVENT_CLIENT_ICONIFY; +E_API extern int E_EVENT_CLIENT_UNICONIFY; +E_API extern int E_EVENT_CLIENT_STACK; +E_API extern int E_EVENT_CLIENT_FOCUS_IN; +E_API extern int E_EVENT_CLIENT_FOCUS_OUT; +E_API extern int E_EVENT_CLIENT_PROPERTY; +E_API extern int E_EVENT_CLIENT_FULLSCREEN; +E_API extern int E_EVENT_CLIENT_UNFULLSCREEN; +#ifdef _F_ZONE_WINDOW_ROTATION_ +E_API extern int E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN; +E_API extern int E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL; +E_API extern int E_EVENT_CLIENT_ROTATION_CHANGE_END; +#endif +E_API extern int E_EVENT_CLIENT_VISIBILITY_CHANGE; +E_API extern int E_EVENT_CLIENT_BUFFER_CHANGE; + +EINTERN void e_client_idler_before(void); +EINTERN Eina_Bool e_client_init(void); +EINTERN void e_client_shutdown(void); +E_API E_Client *e_client_new(E_Pixmap *cp, int first_map, int internal); +E_API void e_client_unignore(E_Client *ec); +E_API void e_client_desk_set(E_Client *ec, E_Desk *desk); +E_API Eina_Bool e_client_comp_grabbed_get(void); +E_API E_Client *e_client_action_get(void); +E_API E_Client *e_client_warping_get(void); +E_API Eina_List *e_clients_immortal_list(void); +E_API void e_client_mouse_in(E_Client *ec, int x, int y); +E_API void e_client_mouse_out(E_Client *ec, int x, int y); +E_API void e_client_mouse_wheel(E_Client *ec, Evas_Point *output, E_Binding_Event_Wheel *ev); +E_API void e_client_mouse_down(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button *ev); +E_API void e_client_mouse_up(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button* ev); +E_API void e_client_mouse_move(E_Client *ec, Evas_Point *output); +E_API void e_client_res_change_geometry_save(E_Client *bd); +E_API void e_client_res_change_geometry_restore(E_Client *ec); +E_API void e_client_zone_set(E_Client *ec, E_Zone *zone); +E_API void e_client_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h); +E_API E_Client *e_client_above_get(const E_Client *ec); +E_API E_Client *e_client_below_get(const E_Client *ec); +E_API E_Client *e_client_bottom_get(void); +E_API E_Client *e_client_top_get(void); +E_API unsigned int e_clients_count(void); +E_API void e_client_move_intercept_cb_set(E_Client *ec, E_Client_Move_Intercept_Cb cb); +E_API E_Client_Hook *e_client_hook_add(E_Client_Hook_Point hookpoint, E_Client_Hook_Cb func, const void *data); +E_API void e_client_hook_del(E_Client_Hook *ch); +E_API E_Client_Intercept_Hook *e_client_intercept_hook_add(E_Client_Intercept_Hook_Point hookpoint, E_Client_Intercept_Hook_Cb func, const void *data); +E_API void e_client_intercept_hook_del(E_Client_Intercept_Hook *ch); +EINTERN void e_client_focus_stack_lower(E_Client *ec); +E_API void e_client_focus_latest_set(E_Client *ec); +E_API void e_client_focus_defer_set(E_Client *ec); +E_API void e_client_focus_defer_unset(E_Client *ec); +E_API Eina_Bool e_client_focus_track_enabled(void); +E_API void e_client_focus_track_freeze(void); +E_API void e_client_focus_track_thaw(void); +E_API void e_client_refocus(void); +E_API void e_client_focus_set_with_pointer(E_Client *ec); +E_API void e_client_activate(E_Client *ec, Eina_Bool just_do_it); +E_API E_Client *e_client_focused_get(void); +E_API Eina_List *e_client_focus_stack_get(void); +E_API Eina_List *e_client_lost_windows_get(E_Zone *zone); +E_API void e_client_shade(E_Client *ec, E_Direction dir); +E_API void e_client_unshade(E_Client *ec, E_Direction dir); +E_API void e_client_maximize(E_Client *ec, E_Maximize max); +E_API void e_client_unmaximize(E_Client *ec, E_Maximize max); +E_API void e_client_fullscreen(E_Client *ec, E_Fullscreen policy); +E_API void e_client_unfullscreen(E_Client *ec); +E_API void e_client_iconify(E_Client *ec); +E_API void e_client_uniconify(E_Client *ec); +E_API void e_client_urgent_set(E_Client *ec, Eina_Bool urgent); +E_API void e_client_stick(E_Client *ec); +E_API void e_client_unstick(E_Client *ec); +E_API void e_client_pinned_set(E_Client *ec, Eina_Bool set); +E_API void e_client_comp_hidden_set(E_Client *ec, Eina_Bool hidden); +E_API Eina_Bool e_client_border_set(E_Client *ec, const char *name); +E_API void e_client_act_move_keyboard(E_Client *ec); +E_API void e_client_act_resize_keyboard(E_Client *ec); +E_API void e_client_act_move_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev); +E_API void e_client_act_move_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED); +E_API void e_client_act_resize_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev, E_Pointer_Mode resize_mode); +E_API void e_client_act_resize_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED); +E_API void e_client_act_menu_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev, int key); +E_API void e_client_act_close_begin(E_Client *ec); +E_API void e_client_act_kill_begin(E_Client *ec); +E_API Evas_Object *e_client_icon_add(E_Client *ec, Evas *evas); +E_API void e_client_ping(E_Client *cw); +E_API void e_client_move_cancel(void); +E_API void e_client_resize_cancel(void); +E_API Eina_Bool e_client_resize_begin(E_Client *ec); +E_API void e_client_frame_recalc(E_Client *ec); +E_API void e_client_signal_move_begin(E_Client *ec, const char *sig, const char *src EINA_UNUSED); +E_API void e_client_signal_move_end(E_Client *ec, const char *sig EINA_UNUSED, const char *src EINA_UNUSED); +E_API void e_client_signal_resize_begin(E_Client *ec, const char *dir, const char *sig, const char *src EINA_UNUSED); +E_API void e_client_signal_resize_end(E_Client *ec, const char *dir EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED); +E_API void e_client_resize_limit(E_Client *ec, int *w, int *h); +E_API E_Client *e_client_under_pointer_get(E_Desk *desk, E_Client *exclude); +E_API E_Client *e_client_under_position_get(E_Desk *desk, int x, int y, E_Client *exclude); +E_API int e_client_pointer_warp_to_center_now(E_Client *ec); +E_API int e_client_pointer_warp_to_center(E_Client *ec); +E_API void e_client_redirected_set(E_Client *ec, Eina_Bool set); +E_API Eina_Bool e_client_is_stacking(const E_Client *ec); +E_API Eina_Bool e_client_has_xwindow(const E_Client *ec); +E_API Eina_Bool e_client_desk_window_profile_available_check(E_Client *ec, const char *profile); +E_API void e_client_desk_window_profile_wait_desk_set(E_Client *ec, E_Desk *desk); +E_API void e_client_layout_cb_set(E_Client_Layout_Cb cb); +E_API E_Client *e_client_transient_child_top_get(E_Client *ec, Eina_Bool consider_focus); +E_API void e_client_visibility_calculate(void); +E_API void e_client_visibility_skip_set(E_Client *ec, Eina_Bool skip); +E_API void e_client_post_raise_lower_set(E_Client *ec, Eina_Bool raise_set, Eina_Bool lower_set); +E_API Eina_Bool e_client_first_mapped_get(E_Client *ec); + +E_API void e_client_transform_update(E_Client *ec); +E_API void e_client_transform_apply(E_Client *ec, double degree, double zoom, int cx, int cy); +E_API void e_client_transform_clear(E_Client *ec); +E_API void e_client_cursor_map_apply(E_Client *ec, int rotation, int x, int y); + +YOLO E_API void e_client_focus_stack_set(Eina_List *l); + +E_API Eina_Bool e_client_transform_core_enable_get(E_Client *ec); +E_API void e_client_transform_core_add(E_Client *ec, E_Util_Transform *transform); +E_API void e_client_transform_core_remove(E_Client *ec, E_Util_Transform *transform); +E_API void e_client_transform_core_update(E_Client *ec); +E_API int e_client_transform_core_transform_count_get(E_Client *ec); +E_API E_Util_Transform *e_client_transform_core_transform_get(E_Client *ec, int index); +E_API void e_client_transform_core_input_transform(E_Client *ec, int x, int y, int *out_x, int *out_y); +E_API void e_client_transform_core_input_inv_transform(E_Client *ec, int x, int y, int *out_x, int *out_y); +E_API void e_client_transform_core_input_inv_rect_transform(E_Client *ec, int x, int y, int *out_x, int *out_y); + +E_API E_Pixmap *e_client_pixmap_change(E_Client *ec, E_Pixmap *newcp); +E_API void e_client_window_role_set(E_Client *ec, const char *role); + +E_API Eina_Bool e_client_key_send(E_Client *ec, int keycode, Eina_Bool pressed, Evas_Device *dev, unsigned int time); +E_API Eina_Bool e_client_touch_send(E_Client *ec, int idx, int x, int y, Eina_Bool pressed, Evas_Device *dev, double radius_x, double radius_y, double pressure, double angle, unsigned int time); +E_API Eina_Bool e_client_touch_update_send(E_Client *ec, int idx, int x, int y, Evas_Device *dev, double radius_x, double radius_y, double pressure, double angle, unsigned int time); +E_API Eina_Bool e_client_touch_cancel_send(E_Client *ec); +E_API Eina_Bool e_client_mouse_button_send(E_Client *ec, int buttons, Eina_Bool pressed, Evas_Device *dev, unsigned int time); +E_API Eina_Bool e_client_mouse_move_send(E_Client *ec, int x, int y, Evas_Device *dev, unsigned int time); +E_API Eina_Bool e_client_mouse_wheel_send(E_Client *ec, int direction, int z, Evas_Device *dev, unsigned int time); +E_API Eina_Bool e_client_mouse_in_send(E_Client *ec, int x, int y, Evas_Device *dev, unsigned int time); +E_API Eina_Bool e_client_mouse_out_send(E_Client *ec, Evas_Device *dev, unsigned int time); + +E_API Eina_Bool e_client_video_client_has(E_Client *ec); +E_API Eina_Bool e_client_normal_client_has(E_Client *ec); + +E_API Eina_Bool e_client_cursor_hide(E_Client *ec); + +E_API void e_client_visibility_force_obscured_set(E_Client *ec, Eina_Bool set); + +E_API void e_client_stay_within_canvas_margin(E_Client *ec); + +EINTERN void e_client_revert_focus(E_Client *ec); +EINTERN Eina_Bool e_client_check_above_focused(E_Client *ec); + +EINTERN void e_client_pending_geometry_flush(E_Client *ec); +EINTERN Eina_Bool e_client_pending_geometry_has(E_Client *ec); + +/** + * Move window to coordinates that do not account client decorations yet. + * + * This call will consider given position does not account client + * decoration, so these values (e_comp_object_frame) will be + * accounted automatically. This is specially useful when it is a new + * client and has not be evaluated yet, in this case + * the frame will be zeroed and no information is known. It + * will mark pending requests so client will be accounted on + * evalutation phase. + * + * @parm x horizontal position to place window. + * @parm y vertical position to place window. + * + * @see e_client_move() + */ +static inline void +e_client_util_move_without_frame(E_Client *ec, int x, int y) +{ + if (!ec) return; + e_comp_object_frame_xy_adjust(ec->frame, x, y, &x, &y); + evas_object_move(ec->frame, x, y); +} + +/** + * Resize window to values that do not account client decorations yet. + * + * This call will consider given size and does not for account client + * decoration, so these values (e_comp_object_frame) will be + * accounted for automatically. This is specially useful when it is a new + * client and has not been evaluated yet, in this case + * e_comp_object_frame will be zeroed and no information is known. It + * will mark pending requests so the client will be accounted for on + * evalutation phase. + * + * @parm w horizontal window size. + * @parm h vertical window size. + * + * @see e_client_resize() + */ +static inline void +e_client_util_resize_without_frame(E_Client *ec, int w, int h) +{ + if (!ec) return; + e_comp_object_frame_wh_adjust(ec->frame, w, h, &w, &h); + evas_object_resize(ec->frame, w, h); + e_client_stay_within_canvas_margin(ec); +} + +/** + * Move and resize window to values that do not account for client decorations yet. + * + * This call will consider given values already accounts client + * decorations, so it will not be considered later. This will just + * work properly with clients that have being evaluated and client + * decorations are known (e_comp_object_frame). + * + * @parm x horizontal position to place window. + * @parm y vertical position to place window. + * @parm w horizontal window size. + * @parm h vertical window size. + * + * @see e_client_move_resize() + */ +static inline void +e_client_util_move_resize_without_frame(E_Client *ec, int x, int y, int w, int h) +{ + e_client_util_move_without_frame(ec, x, y); + e_client_util_resize_without_frame(ec, w, h); +} + +static inline Eina_Bool +e_client_util_ignored_get(const E_Client *ec) +{ + if (!ec) return EINA_TRUE; + return ec->override || ec->input_only || ec->ignored; +} + +static inline Eina_Bool +e_client_util_desk_visible(const E_Client *ec, const E_Desk *desk) +{ + if (!ec) return EINA_FALSE; + return !ec->desk || ec->sticky || (ec->desk == desk); +} + +static inline Ecore_Window +e_client_util_pwin_get(const E_Client *ec) +{ + if (!ec) return 0; + if (!ec->pixmap) return 0; + return e_pixmap_parent_window_get(ec->pixmap); +} + +static inline Ecore_Window +e_client_util_win_get(const E_Client *ec) +{ + if (!ec) return 0; + if (!ec->pixmap) return 0; + return e_pixmap_window_get(ec->pixmap); +} + +static inline Eina_Bool +e_client_util_resizing_get(const E_Client *ec) +{ + if (!ec) return EINA_FALSE; + return (ec->resize_mode != E_POINTER_RESIZE_NONE); +} + +static inline Eina_Bool +e_client_util_borderless(const E_Client *ec) +{ + if (!ec) return EINA_FALSE; + return (ec->borderless || ec->mwm.borderless || (!ec->border.name) || (!strcmp(ec->border.name, "borderless"))); +} + +static inline Eina_Bool +e_client_util_shadow_state_get(const E_Client *ec) +{ + Eina_Bool on; + if (!ec) return EINA_FALSE; + if (ec->shaped) return EINA_FALSE; + if (ec->argb) + { + return (!ec->borderless) && (ec->bordername || (ec->border.name && strcmp(ec->border.name, "borderless"))); + } + on = !ec->e.state.video; + if (on) + on = !ec->fullscreen; + return on; +} + +static inline Eina_Stringshare * +e_client_util_name_get(const E_Client *ec) +{ + if (!ec) return NULL; + if (ec->netwm.name) + return ec->netwm.name; + else if (ec->icccm.title) + return ec->icccm.title; + return NULL; +} + +static inline Eina_Bool +e_client_util_is_popup(const E_Client *ec) +{ + if (!ec) return EINA_FALSE; + switch (ec->netwm.type) + { + case E_WINDOW_TYPE_MENU: + case E_WINDOW_TYPE_SPLASH: + case E_WINDOW_TYPE_DROPDOWN_MENU: + case E_WINDOW_TYPE_POPUP_MENU: + case E_WINDOW_TYPE_TOOLTIP: + case E_WINDOW_TYPE_NOTIFICATION: + case E_WINDOW_TYPE_COMBO: + case E_WINDOW_TYPE_DND: + return EINA_TRUE; + default: break; + } + return EINA_FALSE; +} + +#endif diff --git a/src/bin/e_includes.h b/src/bin/e_includes.h index c2193a2351..41dd6bc1a6 100644 --- a/src/bin/e_includes.h +++ b/src/bin/e_includes.h @@ -4,9 +4,11 @@ #include "e_error.h" #include "e_zone.h" #include "e_desk.h" +#ifndef ENABLE_IOT #include "e_pixmap.h" #include "e_comp_object.h" #include "e_util_transform.h" +#endif//ENABLE_IOT #include "e_client.h" #include "e_pointer.h" #include "e_config.h" diff --git a/src/bin/e_includes_iot.h b/src/bin/e_includes_iot.h new file mode 100644 index 0000000000..498cc4901c --- /dev/null +++ b/src/bin/e_includes_iot.h @@ -0,0 +1,108 @@ +#include "e_object.h" +#include "e_user.h" +#include "e_path.h" +#include "e_error.h" +#ifndef HAVE_IOT +#include "e_zone.h" +#include "e_desk.h" +#include "e_pixmap.h" +#include "e_comp_object.h" +#include "e_util_transform.h" +#endif//HAVE_IOT +#include "e_client_common.h" +#ifndef HAVE_IOT +#include "e_pointer.h" +#endif//HAVE_IOT +#include "e_config.h" +#include "e_config_data.h" +#include "e_module.h" +#ifndef HAVE_IOT +#include "e_icon.h" +#include "e_init.h" +#include "e_focus.h" +#include "e_place.h" +#include "e_resist.h" +#endif//HAVE_IOT +#include "e_signals.h" +#ifndef HAVE_IOT +#include "e_layout.h" +#include "e_theme.h" +#include "e_dnd.h" +#include "e_bindings.h" +#include "e_actions.h" +#include "e_test_helper.h" +#include "e_info_server.h" +#include "e_maximize.h" +#endif//HAVE_IOT +#include "e_prefix.h" +#ifndef HAVE_IOT +#include "e_grabinput.h" +#include "e_bg.h" +#include "e_win.h" +#include "e_zoomap.h" +#include "e_dialog.h" +#include "e_screensaver.h" +#include "e_dpms.h" +#include "e_eom.h" +#include "e_obj_dialog.h" +#include "e_mouse.h" +#include "e_msgbus.h" +#include "e_scale.h" +#endif//HAVE_IOT +#include "e_env.h" +#include "e_log.h" +#ifndef HAVE_IOT +#include "e_dbusmenu.h" +#include "e_comp_screen.h" +#include "e_comp.h" +#endif//HAVE_IOT +#include "e_comp_cfdata.h" +#ifndef HAVE_IOT +#include "e_comp_canvas.h" +#include "e_utils.h"//evas dependent +#include "e_hints.h" +#include "e_plane.h" +#include "e_plane_renderer.h" +#include "e_output.h" +#include "e_hwc.h" +#include "e_hwc_planes.h" +#include "e_hwc_windows.h" +#include "e_hwc_window.h" +#include "e_hwc_window_queue.h" +#include "e_comp_wl.h"//evas dependent +#include "e_comp_wl_data.h" +#include "e_comp_wl_input.h"//evas dependent +#include "e_uuid_store.h" +#ifdef HAVE_WAYLAND_TBM +# include "e_comp_wl_tbm.h" +#endif +#include "e_comp_wl_rsm.h" +#include "e_comp_wl_screenshooter.h" +#include "e_comp_wl_viewport.h" +#include "e_comp_wl_shell.h" +#include "e_policy.h" +#include "e_policy_conformant.h" +#include "e_policy_visibility.h" +#include "e_magnifier.h" +#include "e_process.h" +#include "e_splitlayout.h" +#include "e_slot.h" +#endif//HAVE_IOT +#include "e_privilege.h" +#include "e_security.h" +#include "e_main.h" +#include "e_keyrouter.h" +#ifndef HAVE_IOT +#include "e_gesture.h" +#include "e_dbus_conn.h" +#include "e_xdg_shell_v6.h" +#endif//HAVE_IOT +#include "e_input.h" +#include "e_devicemgr.h" +#ifndef HAVE_IOT +#include "e_video_debug.h" +#include "e_client_video.h" +#include "e_zone_video.h" +#include "e_comp_wl_video.h" +#include "e_comp_wl_video_buffer.h" +#endif//HAVE_IOT diff --git a/src/bin/e_info_server_common.c b/src/bin/e_info_server_common.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bin/e_iot.h b/src/bin/e_iot.h new file mode 100644 index 0000000000..441bd00e8f --- /dev/null +++ b/src/bin/e_iot.h @@ -0,0 +1,7 @@ +#ifndef E_IOT_H +#define E_IOT_H + +#define HAVE_IOT 1 +#include "e.h" + +#endif diff --git a/src/bin/e_main.c b/src/bin/e_main.c index 8ea60671cd..72123953f6 100644 --- a/src/bin/e_main.c +++ b/src/bin/e_main.c @@ -129,6 +129,9 @@ static Eina_Inlist *_e_main_hooks[] = E_API Eina_Bool starting = EINA_TRUE; E_API Eina_Bool stopping = EINA_FALSE; +static Eina_Bool _e_profile_headless = 0; +static Eina_Bool _e_conf_ro = 0; + static Eina_Bool _xdg_check_str(const char *env, const char *str) { @@ -319,6 +322,7 @@ int main(int argc, char **argv) { char *s = NULL; + char *e_profile = NULL; struct sigaction action; #ifdef __linux__ @@ -414,6 +418,24 @@ main(int argc, char **argv) _e_main_parse_arguments(argc, argv); TSE("Parse Arguments Done"); + TSB("Get E_CONF_PROFILE"); + e_profile = e_util_env_get("E_CONF_PROFILE"); + + if (!e_profile) + { + fprintf(stderr, "Failed to get E_CONF_PROFILE !"); + goto failed; + } + TSE("Get E_CONF_PROFILE Done"); + + if (!strncmp(e_profile, "tizen-headless", 14)) + { + _e_profile_headless = 1; + _e_conf_ro = 1;//experimental + e_util_env_set("E_CONF_RO", "1"); + } + E_FREE(e_profile); + /*** Initialize Core EFL Libraries We Need ***/ TSB("Eet Init"); @@ -475,6 +497,9 @@ main(int argc, char **argv) TSE("Ecore_File Init Done"); _e_main_shutdown_push(ecore_file_shutdown); + + if (_e_profile_headless) goto do_ecore_event_init; + TSB("E_Util_File_Monitor Init"); e_util_file_monitor_init(); TSE("E_Util_File_Monitor Init Done"); @@ -494,9 +519,19 @@ main(int argc, char **argv) } TSE("Ecore_Evas Init Done"); +do_ecore_event_init: + /* As we're not calling ecore_event_init() here, therefore there will be no chance + * to call ecore_event_init(). Thus, we call ecore_event_init() here. + */ + TSB("Ecore_Event Init"); + ecore_event_init(); + TSE("Ecore_Event Init Done"); + /* e doesn't sync to compositor - it should be one */ ecore_evas_app_comp_sync_set(0); + if (_e_profile_headless) goto do_skip_edje_init; + TSB("Edje Init"); if (!edje_init()) { @@ -508,6 +543,8 @@ main(int argc, char **argv) /*** Initialize E Subsystems We Need ***/ +do_skip_edje_init: + TSB("E User Init"); if (!e_user_init()) { @@ -558,6 +595,8 @@ main(int argc, char **argv) TSE("E Paths Init Done"); _e_main_shutdown_push(_e_main_path_shutdown); + if (_e_profile_headless) goto do_e_module_event_init; + ecore_animator_frametime_set(1.0 / e_config->framerate); TSB("E_Theme Init"); @@ -600,6 +639,7 @@ main(int argc, char **argv) } TRACE_DS_END(); +do_e_module_event_init: e_module_event_init(); TSB("E_Pointer Init"); diff --git a/src/bin/e_main_iot.c b/src/bin/e_main_iot.c new file mode 100644 index 0000000000..be5607c3cc --- /dev/null +++ b/src/bin/e_main_iot.c @@ -0,0 +1,1319 @@ +#include "e_iot.h" +#ifdef __linux__ +# include +#endif +#ifdef HAVE_SYSTEMD +# include +#endif + +#define MAX_LEVEL 80 + +#define TS_DO +#ifdef TS_DO +# define TS(x) \ + { \ + t1 = ecore_time_unix_get(); \ + printf("ESTART: %1.5f [%1.5f] - %s\n", t1 - t0, t1 - t2, x); \ + t2 = t1; \ + } + +# define TSB(x) \ + do { \ + TRACE_DS_BEGIN(ESTART: %s, x); \ + TS(x); \ + } while (0) +# define TSE(x) \ + do { \ + TRACE_DS_END(); \ + TS(x); \ + } while (0) +# define TSM(x) \ + do { \ + TRACE_DS_MARK(ESTART: %s, x); \ + TS(x); \ + } while (0) +static double t0, t1, t2; +#else +# define TS(x) +# define TSB(x) +# define TSE(x) +# define TSM(x) +#endif +/* + * i need to make more use of these when i'm baffled as to when something is + * up. other hooks: + * + * void *(*__malloc_hook)(size_t size, const void *caller); + * + * void *(*__realloc_hook)(void *ptr, size_t size, const void *caller); + * + * void *(*__memalign_hook)(size_t alignment, size_t size, + * const void *caller); + * + * void (*__free_hook)(void *ptr, const void *caller); + * + * void (*__malloc_initialize_hook)(void); + * + * void (*__after_morecore_hook)(void); + * + + static void my_init_hook(void); + static void my_free_hook(void *p, const void *caller); + + static void (*old_free_hook)(void *ptr, const void *caller) = NULL; + void (*__free_hook)(void *ptr, const void *caller); + + void (*__malloc_initialize_hook) (void) = my_init_hook; + static void + my_init_hook(void) + { + old_free_hook = __free_hook; + __free_hook = my_free_hook; + } + + //void *magicfree = NULL; + + static void + my_free_hook(void *p, const void *caller) + { + __free_hook = old_free_hook; + // if ((p) && (p == magicfree)) + // { + // printf("CAUGHT!!!!! %p ...\n", p); + // abort(); + // } + free(p); + __free_hook = my_free_hook; + } + */ + +/* local function prototypes */ +static void _e_main_shutdown(int errcode); +static void _e_main_shutdown_push(int (*func)(void)); +static void _e_main_parse_arguments(int argc, char **argv); +static Eina_Bool _e_main_cb_signal_exit(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED); +static Eina_Bool _e_main_cb_signal_hup(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED); +static int _e_main_dirs_init(void); +static int _e_main_dirs_shutdown(void); +static int _e_main_path_init(void); +static int _e_main_path_shutdown(void); +static int _e_main_screens_init(void); +static int _e_main_screens_shutdown(void); +static void _e_main_desk_save(void); +static void _e_main_desk_restore(void); +static Eina_Bool _e_main_cb_idle_before(void *data EINA_UNUSED); +static Eina_Bool _e_main_cb_idle_after(void *data EINA_UNUSED); +static void _e_main_create_wm_ready(void); +static void _e_main_hooks_clean(void); +static void _e_main_hook_call(E_Main_Hook_Point hookpoint, void *data EINA_UNUSED); + +/* local variables */ +static int _e_main_lvl = 0; +static int(*_e_main_shutdown_func[MAX_LEVEL]) (void); + +static Ecore_Idle_Enterer *_idle_before = NULL; +static Ecore_Idle_Enterer *_idle_after = NULL; + +static Eina_List *hooks = NULL; + +static int _e_main_hooks_delete = 0; +static int _e_main_hooks_walking = 0; + +static Eina_Inlist *_e_main_hooks[] = +{ + [E_MAIN_HOOK_MODULE_LOAD_DONE] = NULL, + [E_MAIN_HOOK_E_INFO_READY] = NULL +}; + +/* external variables */ +E_API Eina_Bool starting = EINA_TRUE; +E_API Eina_Bool stopping = EINA_FALSE; + +static Eina_Bool _e_profile_headless = 0; +static Eina_Bool _e_conf_ro = 0; + +static Eina_Bool +_xdg_check_str(const char *env, const char *str) +{ + const char *p; + size_t len; + + len = strlen(str); + for (p = strstr(env, str); p; p++, p = strstr(p, str)) + { + if ((!p[len]) || (p[len] == ':')) return EINA_TRUE; + } + return EINA_FALSE; +} + +static void +_xdg_data_dirs_augment(void) +{ + char *s; + const char *p = e_prefix_get(); + char newpath[4096], buf[4096]; + + if (!p) return; + + s = e_util_env_get("XDG_DATA_DIRS"); + if (s) + { + Eina_Bool pfxdata, pfx; + + pfxdata = !_xdg_check_str(s, e_prefix_data_get()); + snprintf(newpath, sizeof(newpath), "%s/share", p); + pfx = !_xdg_check_str(s, newpath); + if (pfxdata || pfx) + { + snprintf(buf, sizeof(buf), "%s%s%s%s%s", + pfxdata ? e_prefix_data_get() : "", + pfxdata ? ":" : "", + pfx ? newpath : "", + pfx ? ":" : "", + s); + e_util_env_set("XDG_DATA_DIRS", buf); + } + E_FREE(s); + } + else + { + snprintf(buf, sizeof(buf), "%s:%s/share:/usr/local/share:/usr/share", e_prefix_data_get(), p); + e_util_env_set("XDG_DATA_DIRS", buf); + } + + s = e_util_env_get("XDG_CONFIG_DIRS"); + snprintf(newpath, sizeof(newpath), "%s/etc/xdg", p); + if (s) + { + if (!_xdg_check_str(s, newpath)) + { + snprintf(buf, sizeof(buf), "%s:%s", newpath, s); + e_util_env_set("XDG_CONFIG_DIRS", buf); + } + E_FREE(s); + } + else + { + snprintf(buf, sizeof(buf), "%s:/etc/xdg", newpath); + e_util_env_set("XDG_CONFIG_DIRS", buf); + } + + s = e_util_env_get("XDG_RUNTIME_DIR"); + if (s) + E_FREE(s); + else + { + const char *dir; + + snprintf(buf, sizeof(buf), "/tmp/xdg-XXXXXX"); + dir = mkdtemp(buf); + if (!dir) dir = "/tmp"; + else + { + e_util_env_set("XDG_RUNTIME_DIR", dir); + snprintf(buf, sizeof(buf), "%s/.e-deleteme", dir); + ecore_file_mkdir(buf); + } + } + + /* set menu prefix so we get our e menu */ + s = e_util_env_get("XDG_MENU_PREFIX"); + if (s) + E_FREE(s); + else + e_util_env_set("XDG_MENU_PREFIX", "e-"); +} + +static Eina_Bool +_e_main_subsystem_defer(void *data EINA_UNUSED) +{ + TRACE_DS_BEGIN(MAIN:SUBSYSTEMS DEFER); + + /* try to init delayed subsystems */ + + TRACE_DS_BEGIN(MAIN:DEFERRED INTERNAL SUBSYSTEMS INIT); + + TSB("[DEFERRED] DPMS Init"); + if (!e_dpms_init()) + { + e_error_message_show(_("Enlightenment cannot set up dpms.\n")); + goto failed; + } + TSE("[DEFERRED] DPMS Init Done"); + _e_main_shutdown_push(e_dpms_shutdown); + + TSB("[DEFERRED] Screens Init: win"); + if (!e_win_init()) + { + e_error_message_show(_("Enlightenment cannot setup elementary trap!\n")); + goto failed; + } + TSE("[DEFERRED] Screens Init: win Done"); + + TSB("[DEFERRED] E_Dnd Init"); + if (!e_dnd_init()) + { + e_error_message_show(_("Enlightenment cannot set up its dnd system.\n")); + goto failed; + } + TSE("[DEFERRED] E_Dnd Init Done"); + _e_main_shutdown_push(e_dnd_shutdown); + + TSB("[DEFERRED] E_Scale Init"); + if (!e_scale_init()) + { + e_error_message_show(_("Enlightenment cannot set up its scale system.\n")); + goto failed; + } + TSE("[DEFERRED] E_Scale Init Done"); + _e_main_shutdown_push(e_scale_shutdown); + + TSB("[DEFERRED] E_Test_Helper Init"); + e_test_helper_init(); + _e_main_shutdown_push(e_test_helper_shutdown); + TSE("[DEFERRED] E_Test_Helper Done"); + + TSB("[DEFERRED] E_INFO_SERVER Init"); + e_info_server_init(); + _e_main_shutdown_push(e_info_server_shutdown); + TSE("[DEFERRED] E_INFO_SERVER Done"); + + TRACE_DS_END(); + TRACE_DS_BEGIN(MAIN:DEFERRED COMP JOB); + + /* try to do deferred job of any subsystems*/ + TSB("[DEFERRED] Compositor's deferred job"); + e_comp_deferred_job(); + TSE("[DEFERRED] Compositor's deferred job Done"); + + if (e_config->use_e_policy) + { + TSB("[DEFERRED] E_Policy's deferred job"); + e_policy_deferred_job(); + TSE("[DEFERRED] E_Policy's deferred job Done"); + } + + TSB("[DEFERRED] E_Module's deferred job"); + e_module_deferred_job(); + TSE("[DEFERRED] E_Module's deferred job Done"); + + TRACE_DS_END(); + TRACE_DS_END(); + return ECORE_CALLBACK_DONE; + +failed: + TSE("INIT FAILED"); + TRACE_DS_END(); + TRACE_DS_END(); + _e_main_shutdown(-1); + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_e_main_deferred_job_schedule(void *d EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED) +{ + PRCTL("[Winsys] all modules loaded"); + ecore_idler_add(_e_main_subsystem_defer, NULL); + return ECORE_CALLBACK_DONE; +} + +/* externally accessible functions */ +int +main(int argc, char **argv) +{ + char *s = NULL; + char *e_profile = NULL; + struct sigaction action; + +#ifdef __linux__ +# ifdef PR_SET_PTRACER +# ifdef PR_SET_PTRACER_ANY + prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY); +# endif +# endif +#endif +#ifdef TS_DO + t0 = t1 = t2 = ecore_time_unix_get(); + printf("ESTART(main) %1.5f\n", t0); +#endif + TRACE_DS_BEGIN(MAIN:BEGIN STARTUP); + TSB("Begin Startup"); + PRCTL("[Winsys] start of main"); + + /* trap deadly bug signals and allow some form of sane recovery */ + /* or ability to gdb attach and debug at this point - better than your */ + /* wm/desktop vanishing and not knowing what happened */ + + /* don't install SIGBUS handler */ + /* Wayland shm sets up a sigbus handler for catching invalid shm region */ + /* access. If we setup our sigbus handler here, then the wl-shm sigbus */ + /* handler will not function properly */ + s = e_util_env_get("NOTIFY_SOCKET"); + if (s) + E_FREE(s); + else + { + TSB("Signal Trap"); + action.sa_sigaction = e_sigseg_act; + action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; + sigemptyset(&action.sa_mask); + sigaction(SIGSEGV, &action, NULL); + + action.sa_sigaction = e_sigill_act; + action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; + sigemptyset(&action.sa_mask); + sigaction(SIGILL, &action, NULL); + + action.sa_sigaction = e_sigfpe_act; + action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; + sigemptyset(&action.sa_mask); + sigaction(SIGFPE, &action, NULL); + + action.sa_sigaction = e_sigabrt_act; + action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; + sigemptyset(&action.sa_mask); + sigaction(SIGABRT, &action, NULL); + TSE("Signal Trap Done"); + } + + TSB("Eina Init"); + if (!eina_init()) + { + e_error_message_show(_("Enlightenment cannot initialize Eina!\n")); + goto failed; + } + TSE("Eina Init Done"); + _e_main_shutdown_push(eina_shutdown); + +#ifdef OBJECT_HASH_CHECK + TSB("E_Object Hash Init"); + e_object_hash_init(); + TSE("E_Object Hash Init Done"); +#endif + + TSB("E_Log Init"); + if (!e_log_init()) + { + e_error_message_show(_("Enlightenment could not create a logging domain!\n")); + goto failed; + } + TSE("E_Log Init Done"); + _e_main_shutdown_push(e_log_shutdown); + + TSB("Determine Prefix"); + if (!e_prefix_determine(argv[0])) + { + fprintf(stderr, + "ERROR: Enlightenment cannot determine it's installed\n" + " prefix from the system or argv[0].\n" + " This is because it is not on Linux AND has been\n" + " executed strangely. This is unusual.\n"); + } + TSE("Determine Prefix Done"); + + /* for debugging by redirecting stdout of e to a log file to tail */ + setvbuf(stdout, NULL, _IONBF, 0); + + TSB("Parse Arguments"); + _e_main_parse_arguments(argc, argv); + TSE("Parse Arguments Done"); + + TSB("Get E_CONF_PROFILE"); + e_profile = e_util_env_get("E_CONF_PROFILE"); + + if (!e_profile) + { + fprintf(stderr, "Failed to get E_CONF_PROFILE !"); + goto failed; + } + TSE("Get E_CONF_PROFILE Done"); + + if (!strncmp(e_profile, "tizen-headless", 14)) + { + _e_profile_headless = 1; + _e_conf_ro = 1;//experimental + e_util_env_set("E_CONF_RO", "1"); + } + E_FREE(e_profile); + + /*** Initialize Core EFL Libraries We Need ***/ + + TSB("Eet Init"); + if (!eet_init()) + { + e_error_message_show(_("Enlightenment cannot initialize Eet!\n")); + goto failed; + } + TSE("Eet Init Done"); + _e_main_shutdown_push(eet_shutdown); + + /* Allow ecore to not load system modules. + * Without it ecore_init will block until dbus authentication + * and registration are complete. + */ + ecore_app_no_system_modules(); + + TSB("Ecore Init"); + if (!ecore_init()) + { + e_error_message_show(_("Enlightenment cannot initialize Ecore!\n")); + goto failed; + } + TSE("Ecore Init Done"); + _e_main_shutdown_push(ecore_shutdown); + + TSB("EIO Init"); + if (!eio_init()) + { + e_error_message_show(_("Enlightenment cannot initialize EIO!\n")); + goto failed; + } + TSE("EIO Init Done"); + _e_main_shutdown_push(eio_shutdown); + + TSB("Ecore Event Handlers"); + if (!ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, + _e_main_cb_signal_exit, NULL)) + { + e_error_message_show(_("Enlightenment cannot set up an exit signal handler.\n" + "Perhaps you are out of memory?")); + goto failed; + } + if (!ecore_event_handler_add(ECORE_EVENT_SIGNAL_HUP, + _e_main_cb_signal_hup, NULL)) + { + e_error_message_show(_("Enlightenment cannot set up a HUP signal handler.\n" + "Perhaps you are out of memory?")); + goto failed; + } + TSE("Ecore Event Handlers Done"); + + TSB("Ecore_File Init"); + if (!ecore_file_init()) + { + e_error_message_show(_("Enlightenment cannot initialize Ecore_File!\n")); + goto failed; + } + TSE("Ecore_File Init Done"); + _e_main_shutdown_push(ecore_file_shutdown); + + + if (_e_profile_headless) goto do_ecore_event_init; + + TSB("E_Util_File_Monitor Init"); + e_util_file_monitor_init(); + TSE("E_Util_File_Monitor Init Done"); + _e_main_shutdown_push(e_util_file_monitor_shutdown); + + _idle_before = ecore_idle_enterer_before_add(_e_main_cb_idle_before, NULL); + + TSB("XDG_DATA_DIRS Init"); + _xdg_data_dirs_augment(); + TSE("XDG_DATA_DIRS Init Done"); + + TSB("Ecore_Evas Init"); + if (!ecore_evas_init()) + { + e_error_message_show(_("Enlightenment cannot initialize Ecore_Evas!\n")); + goto failed; + } + TSE("Ecore_Evas Init Done"); + +do_ecore_event_init: + /* As we're not calling ecore_event_init() here, therefore there will be no chance + * to call ecore_event_init(). Thus, we call ecore_event_init() here. + */ + TSB("Ecore_Event Init"); + ecore_event_init(); + TSE("Ecore_Event Init Done"); + + /* e doesn't sync to compositor - it should be one */ + ecore_evas_app_comp_sync_set(0); + + if (_e_profile_headless) goto do_skip_edje_init; + + TSB("Edje Init"); + if (!edje_init()) + { + e_error_message_show(_("Enlightenment cannot initialize Edje!\n")); + goto failed; + } + TSE("Edje Init Done"); + _e_main_shutdown_push(edje_shutdown); + + /*** Initialize E Subsystems We Need ***/ + +do_skip_edje_init: + + TSB("E User Init"); + if (!e_user_init()) + { + e_error_message_show(_("Enlightenment cannot set up user home path\n")); + goto failed; + } + TSE("E User Init Done"); + _e_main_shutdown_push(e_user_shutdown); + + TSB("E Directories Init"); + /* setup directories we will be using for configurations storage etc. */ + if (!_e_main_dirs_init()) + { + e_error_message_show(_("Enlightenment cannot create directories in your home directory.\n" + "Perhaps you have no home directory or the disk is full?")); + goto failed; + } + TSE("E Directories Init Done"); + _e_main_shutdown_push(_e_main_dirs_shutdown); + + TSB("E_Config Init"); + if (!e_config_init()) + { + e_error_message_show(_("Enlightenment cannot set up its config system.\n")); + goto failed; + } + TSE("E_Config Init Done"); + _e_main_shutdown_push(e_config_shutdown); + + TSB("E_Env Init"); + if (!e_env_init()) + { + e_error_message_show(_("Enlightenment cannot set up its environment.\n")); + goto failed; + } + TSE("E_Env Init Done"); + _e_main_shutdown_push(e_env_shutdown); + + ecore_exe_run_priority_set(e_config->priority); + + TSB("E Paths Init"); + if (!_e_main_path_init()) + { + e_error_message_show(_("Enlightenment cannot set up paths for finding files.\n" + "Perhaps you are out of memory?")); + goto failed; + } + TSE("E Paths Init Done"); + _e_main_shutdown_push(_e_main_path_shutdown); + + if (_e_profile_headless) goto do_e_module_event_init; + + ecore_animator_frametime_set(1.0 / e_config->framerate); + + TSB("E_Theme Init"); + if (!e_theme_init()) + { + e_error_message_show(_("Enlightenment cannot set up its theme system.\n")); + goto failed; + } + TSE("E_Theme Init Done"); + _e_main_shutdown_push(e_theme_shutdown); + + TSB("E_Actions Init"); + if (!e_actions_init()) + { + e_error_message_show(_("Enlightenment cannot set up its actions system.\n")); + goto failed; + } + TSE("E_Actions Init Done"); + _e_main_shutdown_push(e_actions_shutdown); + + /* these just add event handlers and can't fail + * timestamping them is dumb. + */ + e_screensaver_preinit(); + e_zone_init(); + e_desk_init(); + e_slot_init(); + e_magnifier_init(); + + TRACE_DS_BEGIN(MAIN:WAIT /dev/dri/card0); + if (e_config->sleep_for_dri) + { + while(access("/dev/dri/card0", F_OK) != 0) + { + struct timespec req, rem; + req.tv_sec = 0; + req.tv_nsec = 50000000L; + nanosleep(&req, &rem); + } + } + TRACE_DS_END(); + +do_e_module_event_init: + e_module_event_init(); + + TSB("E_Pointer Init"); + if (!e_pointer_init()) + { + e_error_message_show(_("Enlightenment cannot set up its pointer system.\n")); + goto failed; + } + TSE("E_Pointer Init Done"); + _e_main_shutdown_push(e_pointer_shutdown); + + TRACE_DS_BEGIN(MAIN:SCREEN INIT); + TSB("Screens Init"); + if (!_e_main_screens_init()) + { + e_error_message_show(_("Enlightenment set up window management for all the screens on your system\n" + "failed. Perhaps another window manager is running?\n")); + goto failed; + } + TSE("Screens Init Done"); + _e_main_shutdown_push(_e_main_screens_shutdown); + TRACE_DS_END(); + + TSB("E_Devicemgr Init"); + if (!e_devicemgr_init()) + { + e_error_message_show(_("Enlightenment cannot set up its device_manager system.\n")); + goto failed; + } + TSE("E_Devicemgr Init Done"); + _e_main_shutdown_push(e_devicemgr_shutdown); + + TSB("E_Keyrouter Init"); + if (!e_keyrouter_init()) + { + e_error_message_show(_("Enlightenment cannot set up its keyrouting system.\n")); + goto failed; + } + TSE("E_Keyrouter Init Done"); + _e_main_shutdown_push(e_keyrouter_shutdown); + + if (e_config->eom_enable) + { + TSB("Eom Init"); + if (!e_eom_init()) + { + e_error_message_show(_("Enlightenment cannot set up eom.\n")); + goto failed; + } + TSE("Eom Init Done"); + _e_main_shutdown_push(e_eom_shutdown); + } + + TSB("E_Screensaver Init"); + if (!e_screensaver_init()) + { + e_error_message_show(_("Enlightenment cannot configure the X screensaver.\n")); + goto failed; + } + TSE("E_Screensaver Init Done"); + _e_main_shutdown_push(e_screensaver_shutdown); + + TSB("E_Comp Freeze"); + e_comp_all_freeze(); + TSE("E_Comp Freeze Done"); + + TSB("E_Grabinput Init"); + if (!e_grabinput_init()) + { + e_error_message_show(_("Enlightenment cannot set up its grab input handling system.\n")); + goto failed; + } + TSE("E_Grabinput Init Done"); + _e_main_shutdown_push(e_grabinput_shutdown); + + TS("E_Gesture Init"); + e_gesture_init(); + _e_main_shutdown_push(e_gesture_shutdown); + + ecore_event_handler_add(E_EVENT_MODULE_INIT_END, _e_main_deferred_job_schedule, NULL); + + TSB("E_Module Init"); + if (!e_module_init()) + { + e_error_message_show(_("Enlightenment cannot set up its module system.\n")); + goto failed; + } + TSE("E_Module Init Done"); + _e_main_shutdown_push(e_module_shutdown); + + TSB("E_Mouse Init"); + if (!e_mouse_update()) + { + e_error_message_show(_("Enlightenment cannot configure the mouse settings.\n")); + goto failed; + } + TSE("E_Mouse Init Done"); + + TSB("E_Icon Init"); + if (!e_icon_init()) + { + e_error_message_show(_("Enlightenment cannot initialize the Icon Cache system.\n")); + goto failed; + } + TSE("E_Icon Init Done"); + _e_main_shutdown_push(e_icon_shutdown); + + if (e_config->use_e_policy) + { + TSB("E_Policy Init"); + if (!e_policy_init()) + { + e_error_message_show(_("Enlightenment cannot setup policy system!\n")); + goto failed; + } + TSE("E_Policy Init Done"); + _e_main_shutdown_push(e_policy_shutdown); + } + + TSB("E_Process Init"); + if (!e_process_init()) + { + e_error_message_show(_("Enlightenment cannot setup process managing system!\n")); + goto failed; + } + TSE("E_Process Init Done"); + _e_main_shutdown_push(e_process_shutdown); + + TSB("E_Security Init"); + if (!e_security_init()) + { + e_error_message_show(_("Enlightenment cannot setup security system!\n")); + goto failed; + } + TSE("E_Security Init Done"); + _e_main_shutdown_push(e_security_shutdown); + + TSB("Load Modules"); + e_module_all_load(); + TSE("Load Modules Done"); + + TSB("E_Comp Thaw"); + e_comp_all_thaw(); + TSE("E_Comp Thaw Done"); + + _idle_after = ecore_idle_enterer_add(_e_main_cb_idle_after, NULL); + + starting = EINA_FALSE; + + TSM("MAIN LOOP AT LAST"); + + if (e_config->create_wm_ready) + _e_main_create_wm_ready(); + + TRACE_DS_END(); + +#ifdef HAVE_SYSTEMD + TSM("[WM] Send start-up completion"); + sd_notify(0, "READY=1"); +#else + TSM("[WM] Skip sending start-up completion. (no systemd)"); +#endif + ecore_main_loop_begin(); + + ELOGF("COMP", "STOPPING enlightenment...", NULL); + stopping = EINA_TRUE; + + _e_main_desk_save(); + e_comp_internal_save(); + + _e_main_shutdown(0); + + e_prefix_shutdown(); + + return 0; + +failed: + TSE("INIT FAILED"); + TRACE_DS_END(); + _e_main_shutdown(-1); +} + +E_API double +e_main_ts(const char *str) +{ + double ret; + t1 = ecore_time_unix_get(); + printf("ESTART: %1.5f [%1.5f] - %s\n", t1 - t0, t1 - t2, str); + ret = t1 - t2; + t2 = t1; + return ret; +} + +E_API double +e_main_ts_begin(const char *str) +{ + TRACE_DS_BEGIN(ESTART: %s, str); + return e_main_ts(str); +} + +E_API double +e_main_ts_end(const char *str) +{ + TRACE_DS_END(); + return e_main_ts(str); +} + +/* local functions */ +static void +_e_main_shutdown(int errcode) +{ + int i = 0; + char buf[PATH_MAX]; + char *dir; + + printf("E: Begin Shutdown Procedure!\n"); + + E_FREE_LIST(hooks, e_main_hook_del); + + if (_idle_before) ecore_idle_enterer_del(_idle_before); + _idle_before = NULL; + if (_idle_after) ecore_idle_enterer_del(_idle_after); + _idle_after = NULL; + + dir = e_util_env_get("XDG_RUNTIME_DIR"); + if (dir) + { + char buf_env[PATH_MAX]; + snprintf(buf_env, sizeof(buf_env), "%s", dir); + snprintf(buf, sizeof(buf), "%s/.e-deleteme", buf_env); + if (ecore_file_exists(buf)) ecore_file_recursive_rm(buf_env); + E_FREE(dir); + } + for (i = (_e_main_lvl - 1); i >= 0; i--) + (*_e_main_shutdown_func[i])(); +#ifdef OBJECT_HASH_CHECK + e_object_hash_shutdown(); +#endif + if (errcode < 0) exit(errcode); +} + +static void +_e_main_shutdown_push(int (*func)(void)) +{ + _e_main_lvl++; + if (_e_main_lvl > MAX_LEVEL) + { + _e_main_lvl--; + e_error_message_show("WARNING: too many init levels. MAX = %i\n", + MAX_LEVEL); + return; + } + _e_main_shutdown_func[_e_main_lvl - 1] = func; +} + +static void +_e_main_parse_arguments(int argc, char **argv) +{ + int i = 0; + + /* handle some command-line parameters */ + for (i = 1; i < argc; i++) + { + if ((!strcmp(argv[i], "-profile")) && (i < (argc - 1))) + { + i++; + if (!getenv("E_CONF_PROFILE")) + e_util_env_set("E_CONF_PROFILE", argv[i]); + } + else if ((!strcmp(argv[i], "-version")) || + (!strcmp(argv[i], "--version"))) + { + printf(_("Version: %s\n"), PACKAGE_VERSION); + _e_main_shutdown(-1); + } + else if ((!strcmp(argv[i], "-h")) || + (!strcmp(argv[i], "-help")) || + (!strcmp(argv[i], "--help"))) + { + printf + (_( + "Options:\n" + "\t-profile CONF_PROFILE\n" + "\t\tUse the configuration profile CONF_PROFILE instead of the user selected default or just \"default\".\n" + "\t-version\n" + ) + ); + _e_main_shutdown(-1); + } + } +} + +static Eina_Bool +_e_main_cb_signal_exit(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED) +{ + /* called on ctrl-c, kill (pid) (also SIGINT, SIGTERM and SIGQIT) */ + ecore_main_loop_quit(); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_e_main_cb_signal_hup(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED) +{ + ecore_main_loop_quit(); + return ECORE_CALLBACK_RENEW; +} + +static int +_e_main_dirs_init(void) +{ + if(getenv("E_CONF_RO")) + { + return 1; + } + + const char *base; + const char *dirs[] = + { + "backgrounds", + "config", + "themes", + NULL + }; + + base = e_user_dir_get(); + if (ecore_file_mksubdirs(base, dirs) != sizeof(dirs) / sizeof(dirs[0]) - 1) + { + e_error_message_show("Could not create one of the required " + "subdirectories of '%s'\n", base); + return 0; + } + + return 1; +} + +static int +_e_main_dirs_shutdown(void) +{ + return 1; +} + +static int +_e_main_path_init(void) +{ + char buf[PATH_MAX]; + + /* setup data paths */ + path_data = e_path_new(); + if (!path_data) + { + e_error_message_show("Cannot allocate path for path_data\n"); + return 0; + } + e_prefix_data_concat_static(buf, "data"); + e_path_default_path_append(path_data, buf); + + /* setup image paths */ + path_images = e_path_new(); + if (!path_images) + { + e_error_message_show("Cannot allocate path for path_images\n"); + return 0; + } + e_user_dir_concat_static(buf, "/images"); + e_path_default_path_append(path_images, buf); + e_prefix_data_concat_static(buf, "data/images"); + e_path_default_path_append(path_images, buf); + + /* setup font paths */ + path_fonts = e_path_new(); + if (!path_fonts) + { + e_error_message_show("Cannot allocate path for path_fonts\n"); + return 0; + } + e_user_dir_concat_static(buf, "/fonts"); + e_path_default_path_append(path_fonts, buf); + e_prefix_data_concat_static(buf, "data/fonts"); + e_path_default_path_append(path_fonts, buf); + + /* setup icon paths */ + path_icons = e_path_new(); + if (!path_icons) + { + e_error_message_show("Cannot allocate path for path_icons\n"); + return 0; + } + e_user_dir_concat_static(buf, "/icons"); + e_path_default_path_append(path_icons, buf); + e_prefix_data_concat_static(buf, "data/icons"); + e_path_default_path_append(path_icons, buf); + + /* setup module paths */ + path_modules = e_path_new(); + if (!path_modules) + { + e_error_message_show("Cannot allocate path for path_modules\n"); + return 0; + } + e_user_dir_concat_static(buf, "/modules"); + e_path_default_path_append(path_modules, buf); + snprintf(buf, sizeof(buf), "%s/enlightenment/modules", e_prefix_lib_get()); + e_path_default_path_append(path_modules, buf); + /* FIXME: eventually this has to go - moduels should have installers that + * add appropriate install paths (if not installed to user homedir) to + * e's module search dirs + */ + snprintf(buf, sizeof(buf), "%s/enlightenment/modules_extra", e_prefix_lib_get()); + e_path_default_path_append(path_modules, buf); + + /* setup background paths */ + path_backgrounds = e_path_new(); + if (!path_backgrounds) + { + e_error_message_show("Cannot allocate path for path_backgrounds\n"); + return 0; + } + e_user_dir_concat_static(buf, "/backgrounds"); + e_path_default_path_append(path_backgrounds, buf); + e_prefix_data_concat_static(buf, "data/backgrounds"); + e_path_default_path_append(path_backgrounds, buf); + + path_messages = e_path_new(); + if (!path_messages) + { + e_error_message_show("Cannot allocate path for path_messages\n"); + return 0; + } + e_user_dir_concat_static(buf, "/locale"); + e_path_default_path_append(path_messages, buf); + e_path_default_path_append(path_messages, e_prefix_locale_get()); + + return 1; +} + +static int +_e_main_path_shutdown(void) +{ + if (path_data) + { + e_object_del(E_OBJECT(path_data)); + path_data = NULL; + } + if (path_images) + { + e_object_del(E_OBJECT(path_images)); + path_images = NULL; + } + if (path_fonts) + { + e_object_del(E_OBJECT(path_fonts)); + path_fonts = NULL; + } + if (path_icons) + { + e_object_del(E_OBJECT(path_icons)); + path_icons = NULL; + } + if (path_modules) + { + e_object_del(E_OBJECT(path_modules)); + path_modules = NULL; + } + if (path_backgrounds) + { + e_object_del(E_OBJECT(path_backgrounds)); + path_backgrounds = NULL; + } + if (path_messages) + { + e_object_del(E_OBJECT(path_messages)); + path_messages = NULL; + } + return 1; +} + +static int +_e_main_screens_init(void) +{ + TSB("\tscreens: client"); + if (!e_client_init()) return 0; + TSE("\tscreens: client Done"); + + TSB("Compositor Init"); + PRCTL("[Winsys] start of compositor init"); + if (!e_comp_init()) + { + e_error_message_show(_("Enlightenment cannot create a compositor.\n")); + _e_main_shutdown(-1); + } + TSE("Compositor Init Done"); + + PRCTL("[Winsys] end of compositor init"); + _e_main_desk_restore(); + + return 1; +} + +static int +_e_main_screens_shutdown(void) +{ + e_win_shutdown(); + e_comp_shutdown(); + e_client_shutdown(); + + e_magnifier_shutdown(); + e_slot_shutdown(); + e_desk_shutdown(); + e_zone_shutdown(); + return 1; +} + +static void +_e_main_desk_save(void) +{ + const Eina_List *l; + char env[1024], name[1024]; + E_Zone *zone; + + EINA_LIST_FOREACH(e_comp->zones, l, zone) + { + snprintf(name, sizeof(name), "DESK_%d_%d", 0, zone->num); + snprintf(env, sizeof(env), "%d,%d", zone->desk_x_current, zone->desk_y_current); + e_util_env_set(name, env); + } +} + +static void +_e_main_desk_restore(void) +{ + E_Client *ec; + + E_CLIENT_REVERSE_FOREACH(ec) + if ((!e_client_util_ignored_get(ec)) && e_client_util_desk_visible(ec, e_desk_current_get(ec->zone))) + { + ec->want_focus = ec->take_focus = 1; + break; + } +} + +static Eina_Bool +_e_main_cb_idle_before(void *data EINA_UNUSED) +{ + e_client_idler_before(); + edje_thaw(); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_e_main_cb_idle_after(void *data EINA_UNUSED) +{ + static int first_idle = 1; + + eet_clearcache(); + edje_freeze(); + + if (first_idle) + { + TSM("SLEEP"); + first_idle = 0; + } + + return ECORE_CALLBACK_RENEW; +} + +static void +_e_main_create_wm_ready(void) +{ + FILE *_wmready_checker = NULL; + const char *path_wm_ready = "/run/.wm_ready"; + + if (!e_util_file_realpath_check(path_wm_ready, EINA_TRUE)) + { + WRN("%s is maybe link, so delete it\n", path_wm_ready); + } + + _wmready_checker = fopen(path_wm_ready, "wb"); + if (_wmready_checker) + { + TSM("[WM] WINDOW MANAGER is READY!!!"); + PRCTL("[Winsys] WINDOW MANAGER is READY!!!"); + fclose(_wmready_checker); + + /*TODO: Next lines should be removed. */ + FILE *_tmp_wm_ready_checker; + + _tmp_wm_ready_checker = fopen(path_wm_ready, "wb"); + + if (_tmp_wm_ready_checker) + { + TSM("[WM] temporary wm_ready path is created."); + PRCTL("[Winsys] temporary wm_ready path is created."); + fclose(_tmp_wm_ready_checker); + } + else + { + TSM("[WM] temporary wm_ready path create failed."); + PRCTL("[Winsys] temporary wm_ready path create failed."); + } + } + else + { + TSM("[WM] WINDOW MANAGER is READY. BUT, failed to create .wm_ready file."); + PRCTL("[Winsys] WINDOW MANAGER is READY. BUT, failed to create .wm_ready file."); + } +} + +static void +_e_main_hooks_clean(void) +{ + Eina_Inlist *l; + E_Main_Hook *mh; + unsigned int x; + + for (x = 0; x < E_MAIN_HOOK_LAST; x++) + EINA_INLIST_FOREACH_SAFE(_e_main_hooks[x], l, mh) + { + if (!mh->delete_me) continue; + _e_main_hooks[x] = eina_inlist_remove(_e_main_hooks[x], + EINA_INLIST_GET(mh)); + free(mh); + } +} + +static void +_e_main_hook_call(E_Main_Hook_Point hookpoint, void *data EINA_UNUSED) +{ + E_Main_Hook *mh; + + _e_main_hooks_walking++; + EINA_INLIST_FOREACH(_e_main_hooks[hookpoint], mh) + { + if (mh->delete_me) continue; + mh->func(mh->data); + } + _e_main_hooks_walking--; + if ((_e_main_hooks_walking == 0) && (_e_main_hooks_delete > 0)) + _e_main_hooks_clean(); +} + +E_API E_Main_Hook * +e_main_hook_add(E_Main_Hook_Point hookpoint, E_Main_Hook_Cb func, const void *data) +{ + E_Main_Hook *mh; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_MAIN_HOOK_LAST, NULL); + mh = E_NEW(E_Main_Hook, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(mh, NULL); + mh->hookpoint = hookpoint; + mh->func = func; + mh->data = (void*)data; + _e_main_hooks[hookpoint] = eina_inlist_append(_e_main_hooks[hookpoint], + EINA_INLIST_GET(mh)); + return mh; +} + +E_API void +e_main_hook_del(E_Main_Hook *mh) +{ + mh->delete_me = 1; + if (_e_main_hooks_walking == 0) + { + _e_main_hooks[mh->hookpoint] = eina_inlist_remove(_e_main_hooks[mh->hookpoint], + EINA_INLIST_GET(mh)); + free(mh); + } + else + _e_main_hooks_delete++; +} + +E_API void +e_main_hook_call(E_Main_Hook_Point hookpoint) +{ + if ((hookpoint < 0) || (hookpoint >= E_MAIN_HOOK_LAST)) return; + + _e_main_hook_call(hookpoint, NULL); +} -- 2.34.1