summaryrefslogtreecommitdiff
path: root/src/bin/e_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/e_client.c')
-rw-r--r--src/bin/e_client.c4465
1 files changed, 4465 insertions, 0 deletions
diff --git a/src/bin/e_client.c b/src/bin/e_client.c
new file mode 100644
index 0000000000..c55e4d47fe
--- /dev/null
+++ b/src/bin/e_client.c
@@ -0,0 +1,4465 @@
+#include "e.h"
+
+static Eina_List *_e_client_hooks = NULL;
+static int _e_client_hooks_delete = 0;
+static int _e_client_hooks_walking = 0;
+
+EAPI int E_EVENT_CLIENT_ADD = -1;
+EAPI int E_EVENT_CLIENT_REMOVE = -1;
+EAPI int E_EVENT_CLIENT_ZONE_SET = -1;
+EAPI int E_EVENT_CLIENT_DESK_SET = -1;
+EAPI int E_EVENT_CLIENT_RESIZE = -1;
+EAPI int E_EVENT_CLIENT_MOVE = -1;
+EAPI int E_EVENT_CLIENT_SHOW = -1;
+EAPI int E_EVENT_CLIENT_HIDE = -1;
+EAPI int E_EVENT_CLIENT_ICONIFY = -1;
+EAPI int E_EVENT_CLIENT_UNICONIFY = -1;
+EAPI int E_EVENT_CLIENT_STICK = -1;
+EAPI int E_EVENT_CLIENT_UNSTICK = -1;
+EAPI int E_EVENT_CLIENT_STACK = -1;
+EAPI int E_EVENT_CLIENT_FOCUS_IN = -1;
+EAPI int E_EVENT_CLIENT_FOCUS_OUT = -1;
+EAPI int E_EVENT_CLIENT_PROPERTY = -1;
+EAPI int E_EVENT_CLIENT_FULLSCREEN = -1;
+EAPI int E_EVENT_CLIENT_UNFULLSCREEN = -1;
+
+static Eina_Hash *clients_hash = NULL; // pixmap->client
+
+static 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 *raise_stack = NULL;
+
+static Eina_Bool comp_grabbed = EINA_FALSE;
+
+static Eina_List *handlers = NULL;
+//static Eina_Bool client_grabbed = EINA_FALSE;
+
+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};
+
+EINTERN void e_client_focused_set(E_Client *ec);
+
+
+///////////////////////////////////////////
+
+static Eina_Bool
+_e_client_cb_efreet_cache_update(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
+{
+ E_Comp *c;
+ const Eina_List *l, *ll;
+ E_Client *ec;
+
+ /* mark all clients for desktop/icon updates */
+ EINA_LIST_FOREACH(e_comp_list(), l, c)
+ EINA_LIST_FOREACH(c->clients, ll, ec)
+ {
+ E_FREE_FUNC(ec->desktop, efreet_desktop_free);
+ if (e_object_is_del(E_OBJECT(ec))) continue;
+ ec->changes.icon = 1;
+ EC_CHANGED(ec);
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_e_client_cb_config_icon_theme(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
+{
+ E_Comp *c;
+ const Eina_List *l, *ll;
+ E_Client *ec;
+
+ /* mark all clients for desktop/icon updates */
+ EINA_LIST_FOREACH(e_comp_list(), l, c)
+ EINA_LIST_FOREACH(c->clients, ll, ec)
+ {
+ if (e_object_is_del(E_OBJECT(ec))) continue;
+ ec->changes.icon = 1;
+ EC_CHANGED(ec);
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_e_client_cb_config_mode(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
+{
+ E_Comp *c;
+ const Eina_List *l, *ll;
+ E_Client *ec;
+ E_Layer layer;
+
+ /* move fullscreen borders above everything */
+
+ if (e_config->mode.presentation)
+ layer = E_LAYER_CLIENT_TOP;
+ else if (!e_config->allow_above_fullscreen)
+ layer = E_LAYER_CLIENT_FULLSCREEN;
+ else
+ return ECORE_CALLBACK_RENEW;
+
+ EINA_LIST_FOREACH(e_comp_list(), l, c)
+ EINA_LIST_FOREACH(c->clients, ll, ec)
+ {
+ if (e_object_is_del(E_OBJECT(ec))) continue;
+ if ((ec->fullscreen) || (ec->need_fullscreen))
+ {
+ ec->fullscreen = 0;
+ evas_object_layer_set(ec->frame, layer);
+ ec->fullscreen = 1;
+ }
+ }
+ 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)
+{
+ E_Comp *c;
+ const Eina_List *l, *ll;
+ E_Client *ec;
+
+ EINA_LIST_FOREACH(e_comp_list(), l, c)
+ EINA_LIST_FOREACH(c->clients, ll, 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;
+ e_object_unref(E_OBJECT(ec));
+ client_drag = NULL;
+}
+////////////////////////////////////////////////
+
+
+static Eina_Bool
+_e_client_pointer_warp_to_center_timer(void *data EINA_UNUSED)
+{
+ if (warp_to)
+ {
+ int x, y;
+ double spd;
+
+ ecore_evas_pointer_xy_get(warp_client->comp->ee, &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 = e_config->pointer_warp_speed;
+ 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;
+ }
+ ecore_evas_pointer_warp(warp_client->comp->ee, 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)
+ {
+ 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_List *l, *ln;
+ E_Client_Hook *ch;
+
+ EINA_LIST_FOREACH_SAFE(_e_client_hooks, l, ln, ch)
+ {
+ if (ch->delete_me)
+ {
+ _e_client_hooks = eina_list_remove_list(_e_client_hooks, l);
+ free(ch);
+ }
+ }
+}
+
+static Eina_Bool
+_e_client_hook_call(E_Client_Hook_Point hookpoint, E_Client *ec)
+{
+ Eina_List *l;
+ E_Client_Hook *ch;
+
+ e_object_ref(E_OBJECT(ec));
+ _e_client_hooks_walking++;
+ EINA_LIST_FOREACH(_e_client_hooks, l, ch)
+ {
+ if (ch->delete_me) continue;
+ if (ch->hookpoint == hookpoint) ch->func(ch->data, ec);
+ }
+ _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_event_simple_free(void *d EINA_UNUSED, E_Event_Client *ev)
+{
+ 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);
+ ev->ec = ec;
+ 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_property(E_Client *ec, int prop)
+{
+ E_Event_Client_Property *ev;
+
+ ev = E_NEW(E_Event_Client_Property, 1);
+ ev->ec = ec;
+ ev->property = prop;
+ 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)
+{
+ 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)
+{
+ e_object_unref(E_OBJECT(ev->ec));
+ e_object_unref(E_OBJECT(ev->zone));
+ free(ev);
+}
+
+////////////////////////////////////////////////
+
+static int
+_e_client_action_input_win_del(E_Comp *c)
+{
+ if (!comp_grabbed) return 0;
+
+ e_comp_ungrab_input(c, 1, 1);
+ comp_grabbed = 0;
+ return 1;
+}
+
+static void
+_e_client_action_finish(void)
+{
+ if (comp_grabbed)
+ _e_client_action_input_win_del(action_client ? action_client->comp : e_comp_get(NULL));
+
+ 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);
+ action_client = NULL;
+}
+
+static void
+_e_client_revert_focus(E_Client *ec)
+{
+ E_Client *pec;
+ E_Desk *desk;
+
+ if (stopping) return;
+ if (!ec->focused) return;
+ desk = e_desk_current_get(ec->zone);
+ if (ec->desk == desk)
+ evas_object_focus_set(ec->frame, 0);
+
+ if ((ec->parent) &&
+ (ec->parent->desk == desk) && (ec->parent->modal == ec))
+ evas_object_focus_set(ec->parent->frame, 1);
+ else if (e_config->focus_revert_on_hide_or_close)
+ {
+ Eina_Bool unlock = ec->lock_focus_out;
+ ec->lock_focus_out = 1;
+ e_desk_last_focused_focus(desk);
+ ec->lock_focus_out = unlock;
+ }
+ else if (e_config->focus_policy == E_FOCUS_MOUSE)
+ {
+ pec = e_client_under_pointer_get(desk, ec);
+ if (pec)
+ evas_object_focus_set(pec->frame, 1);
+ }
+}
+
+static void
+_e_client_free(E_Client *ec)
+{
+ if (ec->focused)
+ e_client_focused_set(NULL);
+ e_comp_object_redirected_set(ec->frame, 0);
+ e_comp_object_render_update_del(ec->frame);
+
+ if (ec->fullscreen)
+ {
+ ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
+ if (!ec->desk->fullscreen_clients)
+ e_comp_render_queue(ec->comp);
+ }
+ if (ec->new_client)
+ ec->comp->new_clients--;
+ if (ec->e.state.profile.use)
+ {
+ 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.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;
+ }
+ if (ec->internal_ecore_evas)
+ {
+ e_canvas_del(ec->internal_ecore_evas);
+ E_FREE_FUNC(ec->internal_ecore_evas, ecore_evas_free);
+ }
+ E_FREE_FUNC(ec->desktop, efreet_desktop_free);
+ 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);
+
+ if (ec->remember)
+ {
+ E_Remember *rem;
+
+ rem = ec->remember;
+ ec->remember = NULL;
+ e_remember_unuse(rem);
+ }
+ 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);
+ raise_stack = eina_list_remove(raise_stack, ec);
+
+ e_hints_client_list_set();
+ evas_object_del(ec->frame);
+ free(ec);
+}
+
+static void
+_e_client_del(E_Client *ec)
+{
+ E_Client *child;
+
+ ec->changed = 0;
+ focus_stack = eina_list_remove(focus_stack, ec);
+ raise_stack = eina_list_remove(raise_stack, ec);
+ if (ec->exe_inst)
+ {
+ if (ec->exe_inst->phony && (eina_list_count(ec->exe_inst->clients) == 1))
+ e_exec_phony_del(ec->exe_inst);
+ else
+ ec->exe_inst->clients = eina_list_remove(ec->exe_inst->clients, ec);
+ ec->exe_inst = 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();
+ e_pointer_type_pop(ec->comp->pointer, ec, NULL);
+
+ 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 (ec->border_menu) e_menu_deactivate(ec->border_menu);
+ if (!stopping) e_client_comp_hidden_set(ec, 1);
+
+ E_FREE_FUNC(ec->border_locks_dialog, e_object_del);
+ E_FREE_FUNC(ec->border_remember_dialog, e_object_del);
+ E_FREE_FUNC(ec->border_border_dialog, e_object_del);
+ E_FREE_FUNC(ec->border_prop_dialog, e_object_del);
+ e_int_client_menu_del(ec);
+ E_FREE_FUNC(ec->raise_timer, ecore_timer_del);
+
+ if (ec->internal_ecore_evas)
+ ecore_evas_hide(ec->internal_ecore_evas);
+
+ 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);
+
+ if ((!ec->new_client) && (!stopping))
+ _e_client_event_simple(ec, E_EVENT_CLIENT_REMOVE);
+
+ 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;
+
+ eina_hash_del_by_key(clients_hash, &ec->pixmap);
+ ec->comp->clients = eina_list_remove(ec->comp->clients, ec);
+ e_comp_object_render_update_del(ec->frame);
+ if (e_pixmap_free(ec->pixmap))
+ e_pixmap_client_set(ec->pixmap, NULL);
+ ec->pixmap = NULL;
+}
+
+///////////////////////////////////////////
+
+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 (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(E_Client *ec)
+{
+ comp_grabbed = e_comp_grab_input(ec->comp, 1, 1);
+ if (!comp_grabbed) _e_client_action_input_win_del(ec->comp);
+ 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;
+
+ action_client = ec;
+}
+
+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->lock_user_stacking)
+ {
+ if (e_config->border_raise_on_mouse_action)
+ evas_object_raise(ec->frame);
+ }
+ if ((ec->fullscreen) || (ec->lock_user_location))
+ return 0;
+
+/*
+ if (client_grabbed && !e_grabinput_get(e_client_util_pwin_get(ec), 0, e_client_util_pwin_get(ec)))
+ {
+ client_grabbed = 0;
+ return 0;
+ }
+*/
+ if (!_e_client_action_input_win_new(ec)) return 0;
+ ecmove = ec;
+ _e_client_hook_call(E_CLIENT_HOOK_MOVE_BEGIN, ec);
+
+ return 1;
+}
+
+static int
+_e_client_move_end(E_Client *ec)
+{
+ //if (client_grabbed)
+ //{
+ //e_grabinput_release(e_client_util_pwin_get(ec), e_client_util_pwin_get(ec));
+ //client_grabbed = 0;
+ //}
+ _e_client_action_input_win_del(ec->comp);
+ e_pointer_mode_pop(ec, E_POINTER_MOVE);
+ ec->moving = 0;
+ _e_client_hook_call(E_CLIENT_HOOK_MOVE_END, 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:
+ _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!");
+
+ _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;
+
+ 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(ec->comp, 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;
+ 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->comp);
+ e_pointer_mode_pop(ec, ec->resize_mode);
+ 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_NONE,
+ ec->maximized & E_MAXIMIZE_NONE);
+
+ _e_client_hook_call(E_CLIENT_HOOK_RESIZE_END, 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;
+
+ 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:
+ _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!");
+
+ _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;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(raise_stack, l, cec)
+ {
+ /* If a border was specified which should be excluded from the list
+ * (because it will be closed shortly for example), skip */
+ if ((exclude) && (cec == exclude)) continue;
+ if ((desk) && (cec->desk != desk)) 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;
+
+ x = ec->zone->x;
+ y = ec->zone->y;
+ w = ec->zone->w;
+ h = ec->zone->h;
+
+ if (eina_list_count(ec->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(ec->comp, (x - w + 5), y);
+ zone_right = e_comp_zone_xy_get(ec->comp, (x + w + 5), y);
+ zone_above = e_comp_zone_xy_get(ec->comp, x, (y - h + 5));
+ zone_below = e_comp_zone_xy_get(ec->comp, x, (y + h + 5));
+
+ if (!(zone_above) && (y))
+ zone_above = e_comp_zone_xy_get(ec->comp, x, (h - 5));
+
+ if (!(zone_left) && (x))
+ zone_left = e_comp_zone_xy_get(ec->comp, (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_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)
+ 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))
+ {
+ if (e_config->edge_flip_dragging)
+ {
+ Eina_Bool lf, rf, tf, bf;
+
+ lf = rf = tf = bf = EINA_TRUE;
+
+ if (ec->zone->desk_x_count <= 1) lf = rf = EINA_FALSE;
+ else if (!e_config->desk_flip_wrap)
+ {
+ if (ec->zone->desk_x_current == 0) lf = EINA_FALSE;
+ if (ec->zone->desk_x_current == (ec->zone->desk_x_count - 1)) rf = EINA_FALSE;
+ }
+
+ if (ec->zone->desk_y_count <= 1) tf = bf = EINA_FALSE;
+ else if (!e_config->desk_flip_wrap)
+ {
+ if (ec->zone->desk_y_current == 0) tf = EINA_FALSE;
+ if (ec->zone->desk_y_current == (ec->zone->desk_y_count - 1)) bf = EINA_FALSE;
+ }
+
+ if (!(lf) && (ec->x <= loss_overlap) && !(ec->zone->flip.switching))
+ _e_client_reset_lost_window(ec);
+
+ if (!(rf) && (ec->x >= (ec->zone->w - loss_overlap)) && !(ec->zone->flip.switching))
+ _e_client_reset_lost_window(ec);
+
+ if (!(tf) && (ec->y <= loss_overlap) && !(ec->zone->flip.switching))
+ _e_client_reset_lost_window(ec);
+
+ if (!(bf) && (ec->y >= (ec->zone->h - loss_overlap)) && !(ec->zone->flip.switching))
+ _e_client_reset_lost_window(ec);
+ }
+
+ if (!e_config->edge_flip_dragging)
+ _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 (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(ec->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();
+ e_pointer_type_pop(ec->comp->pointer, ec, NULL);
+
+ if (!ec->iconic) e_hints_window_hidden_set(ec);
+
+ if (!ec->hidden)
+ {
+ ec->visible = 0;
+ ec->changes.visible = 1;
+ EC_CHANGED(ec);
+ if (ec->focused)
+ _e_client_revert_focus(ec);
+ }
+
+ ec->post_show = 0;
+
+ if (ec->new_client || ec->iconic) return;
+ _e_client_event_simple(ec, E_EVENT_CLIENT_HIDE);
+}
+
+static void
+_e_client_cb_evas_shade_done(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ E_Client *ec = data;
+
+ 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;
+
+ ec->pre_res_change.valid = 0;
+ if (ec->internal_ecore_evas)
+ {
+ EC_CHANGED(ec);
+ ec->changes.pos = 1;
+ }
+
+ _e_client_event_simple(ec, E_EVENT_CLIENT_MOVE);
+
+ _e_client_zone_update(ec);
+ if (ec->moving)
+ _e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec);
+}
+
+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;
+
+ ec->pre_res_change.valid = 0;
+ if (ec->internal_ecore_evas || (!ec->netwm.sync.request))
+ {
+ EC_CHANGED(ec);
+ ec->changes.size = 1;
+ }
+ if (ec->shaped)
+ {
+ ec->need_shape_merge = 1;
+ ec->need_shape_export = 1;
+ EC_CHANGED(ec);
+ }
+ else if (ec->shaped_input)
+ {
+ ec->need_shape_merge = 1;
+ EC_CHANGED(ec);
+ }
+
+ _e_client_event_simple(ec, E_EVENT_CLIENT_RESIZE);
+
+ _e_client_zone_update(ec);
+
+ _e_client_hook_call(E_CLIENT_HOOK_RESIZE_UPDATE, ec);
+}
+
+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 (!ec->hidden)
+ {
+ ec->visible = 1;
+ ec->changes.visible = 1;
+ EC_CHANGED(ec);
+ }
+ if (!ec->iconic)
+ _e_client_event_simple(data, E_EVENT_CLIENT_SHOW);
+}
+
+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_config->transient.raise && ec->transients)
+ {
+ Eina_List *list = eina_list_clone(ec->transients);
+ E_Client *child, *below = NULL;
+
+ E_LIST_REVERSE_FREE(list, child)
+ {
+ /* Don't stack iconic transients. If the user wants these shown,
+ * thats another option.
+ */
+ if (child->iconic) continue;
+ if (below)
+ evas_object_stack_below(child->frame, below->frame);
+ else
+ evas_object_stack_above(child->frame, ec->frame);
+ below = child;
+ }
+ }
+
+ e_remember_update(ec);
+ _e_client_event_simple(ec, E_EVENT_CLIENT_STACK);
+}
+
+////////////////////////////////////////////////
+
+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;
+
+ zx = zy = zw = zh = 0;
+
+ switch (max & E_MAXIMIZE_TYPE)
+ {
+ case E_MAXIMIZE_NONE:
+ /* Ignore */
+ break;
+
+ case E_MAXIMIZE_FULLSCREEN:
+ w = ec->zone->w;
+ h = ec->zone->h;
+
+ evas_object_smart_callback_call(ec->frame, "fullscreen", NULL);
+ e_client_resize_limit(ec, &w, &h);
+ /* center x-direction */
+ x1 = ec->zone->x + (ec->zone->w - w) / 2;
+ /* center y-direction */
+ yy1 = ec->zone->y + (ec->zone->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->zone->x, ec->zone->y, w / 2, h);
+ break;
+
+ case E_MAXIMIZE_RIGHT:
+ evas_object_geometry_set(ec->frame, x1, ec->zone->y, w / 2, h);
+ break;
+ }
+ break;
+
+ case E_MAXIMIZE_SMART:
+ case E_MAXIMIZE_EXPAND:
+ e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
+ w = zw, h = zh;
+
+ evas_object_smart_callback_call(ec->frame, "maximize", NULL);
+ e_client_resize_limit(ec, &w, &h);
+ 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;
+ else
+ w = zw;
+
+ if (ech < zh)
+ h = ech;
+ else
+ h = zh;
+
+ 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, x1, zy, w, zh);
+ break;
+
+ case E_MAXIMIZE_HORIZONTAL:
+ evas_object_geometry_set(ec->frame, zx, yy1, zw, 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->zone->x;
+ yy1 = ec->zone->y;
+ x2 = ec->zone->x + ec->zone->w;
+ y2 = ec->zone->y + ec->zone->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->zone->x, ec->zone->y, w / 2, h);
+ break;
+
+ case E_MAXIMIZE_RIGHT:
+ evas_object_geometry_set(ec->frame, x1, ec->zone->y, w / 2, h);
+ break;
+ }
+ break;
+ }
+}
+
+////////////////////////////////////////////////
+
+static void
+_e_client_eval(E_Client *ec)
+{
+ int rem_change = 0;
+ 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;
+ }
+
+ if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_NEW_CLIENT, ec)) return;
+
+ if (ec->new_client && (!e_client_util_ignored_get(ec)))
+ {
+ 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 */
+ 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;
+ }
+ if (ec->override)
+ ec->placed = 1;
+ if (!ec->placed)
+ {
+ /* FIXME: special placement for dialogs etc. etc. etc goes
+ * here */
+ /* FIXME: what if parent is not on this desktop - or zone? */
+ if ((ec->parent) && (ec->parent->visible))
+ {
+ if (!E_INSIDE(ec->x, ec->y, ec->parent->x, ec->parent->y, ec->parent->w, ec->parent->h))
+ {
+ ec->x = ec->parent->x + ((ec->parent->w - ec->w) / 2);
+ ec->y = ec->parent->y + ((ec->parent->h - ec->h) / 2);
+ ec->changes.pos = 1;
+ }
+ ec->placed = 1;
+ }
+#if 0
+ else if ((ec->leader) && (ec->dialog))
+ {
+ /* TODO: Place in center of group */
+ }
+#endif
+ else if (ec->dialog)
+ {
+ ec->x = zx + ((zw - ec->w) / 2);
+ ec->y = zy + ((zh - ec->h) / 2);
+ ec->changes.pos = 1;
+ ec->placed = 1;
+ }
+ }
+
+ if (!ec->placed)
+ {
+ Eina_List *skiplist = NULL;
+ int new_x, new_y, t = 0;
+
+ 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 ((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;
+ }
+
+ /* Recreate state */
+ e_hints_window_init(ec);
+ if ((ec->e.state.centered) &&
+ ((!ec->remember) ||
+ ((ec->remember) && (!(ec->remember->apply & E_REMEMBER_APPLY_POS)))))
+ {
+ ec->x = zx + (zw - ec->w) / 2;
+ ec->y = zy + (zh - ec->h) / 2;
+ ec->changes.pos = 1;
+ ec->placed = 1;
+ }
+
+ /* if the explicit geometry request asks for the app to be
+ * in another zone - well move it there */
+ {
+ E_Zone *zone;
+
+ zone = e_comp_zone_xy_get(ec->comp, ec->x + (ec->w / 2), ec->y + (ec->h / 2));
+ if (!zone)
+ zone = e_comp_zone_xy_get(ec->comp, ec->x, ec->y);
+ if (!zone)
+ zone = e_comp_zone_xy_get(ec->comp, ec->x + ec->w - 1, ec->y);
+ if (!zone)
+ zone = e_comp_zone_xy_get(ec->comp, ec->x + ec->w - 1, ec->y + ec->h - 1);
+ if (!zone)
+ zone = e_comp_zone_xy_get(ec->comp, 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)) 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) */
+ //if (ec->shaded)
+ //ecore_x_window_raise(ec->win);
+ ec->changes.shading = 0;
+ send_event = 0;
+ rem_change = 1;
+ }
+ if (ec->changes.shaded) send_event = 0;
+ if ((ec->changes.shaded) && (ec->changes.pos) && (ec->changes.size))
+ {
+ //if (ec->shaded)
+ //ecore_x_window_lower(ec->win);
+ //else
+ //ecore_x_window_raise(ec->win);
+ ec->changes.shaded = 0;
+ rem_change = 1;
+ }
+ else if ((ec->changes.shaded) && (ec->changes.pos))
+ {
+ //if (ec->shaded)
+ //ecore_x_window_lower(ec->win);
+ //else
+ //ecore_x_window_raise(ec->win);
+ ec->changes.size = 1;
+ ec->changes.shaded = 0;
+ rem_change = 1;
+ }
+ else if ((ec->changes.shaded) && (ec->changes.size))
+ {
+ //if (ec->shaded)
+ //ecore_x_window_lower(ec->win);
+ //else
+ //ecore_x_window_raise(ec->win);
+ ec->changes.shaded = 0;
+ rem_change = 1;
+ }
+ else if (ec->changes.shaded)
+ {
+ //if (ec->shaded)
+ //ecore_x_window_lower(ec->win);
+ //else
+ //ecore_x_window_raise(ec->win);
+ ec->changes.shaded = 0;
+ rem_change = 1;
+ }
+
+ if (ec->changes.size)
+ {
+ ec->changes.size = 0;
+ if ((!ec->shaded) && (!ec->shading))
+ {
+ evas_object_resize(ec->frame, ec->w, ec->h);
+ if (ec->internal_ecore_evas)
+ ecore_evas_move_resize(ec->internal_ecore_evas, 0, 0, ec->client.w, ec->client.h);
+ }
+
+ rem_change = 1;
+ prop |= E_CLIENT_PROPERTY_SIZE;
+ }
+ if (ec->changes.pos)
+ {
+ ec->changes.pos = 0;
+ evas_object_move(ec->frame, ec->x, ec->y);
+ rem_change = 1;
+ prop |= E_CLIENT_PROPERTY_POS;
+ }
+
+ if (ec->changes.reset_gravity)
+ {
+ ec->changes.reset_gravity = 0;
+ rem_change = 1;
+ prop |= E_CLIENT_PROPERTY_GRAVITY;
+ }
+
+ if ((ec->changes.visible) && (ec->visible) && (ec->new_client))
+ {
+ int x, y;
+
+ ecore_evas_pointer_xy_get(ec->comp->ee, &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);
+ evas_object_focus_set(ec->frame, 1);
+ }
+ ec->changes.visible = 0;
+ rem_change = 1;
+ _e_client_event_simple(ec, E_EVENT_CLIENT_SHOW);
+ }
+ }
+ else if ((ec->changes.visible) && (ec->new_client))
+ {
+ ec->changes.visible = 0;
+ _e_client_event_simple(ec, E_EVENT_CLIENT_HIDE);
+ }
+
+ if (ec->changes.icon)
+ {
+ if (!ec->new_client)
+ E_FREE_FUNC(ec->desktop, efreet_desktop_free);
+ if (ec->remember && ec->remember->prop.desktop_file)
+ {
+ Efreet_Desktop *d;
+ const char *desktop = ec->remember->prop.desktop_file;
+
+ d = efreet_desktop_get(desktop);
+ if (!d)
+ d = efreet_util_desktop_name_find(desktop);
+ if (d)
+ {
+ efreet_desktop_free(ec->desktop);
+ ec->desktop = d;
+ }
+ }
+ if (!ec->desktop)
+ {
+ if (ec->internal && (ec->icccm.class && (!strncmp(ec->icccm.class, "e_fwin::", 8))))
+ ec->desktop = efreet_util_desktop_exec_find("enlightenment_filemanager");
+ }
+ if (!ec->desktop)
+ {
+ if ((ec->icccm.name) && (ec->icccm.class))
+ ec->desktop = efreet_util_desktop_wm_class_find(ec->icccm.name,
+ ec->icccm.class);
+ }
+ if (!ec->desktop)
+ {
+ /* libreoffice and maybe others match window class
+ with .desktop file name */
+ if (ec->icccm.class)
+ {
+ char buf[4096] = {0};
+ snprintf(buf, sizeof(buf), "%s.desktop", ec->icccm.class);
+ ec->desktop = efreet_util_desktop_file_id_find(buf);
+ if (!ec->desktop)
+ {
+ char *s;
+
+ strncpy(buf, ec->icccm.class, sizeof(buf));
+ s = buf;
+ eina_str_tolower(&s);
+ if (strcmp(s, ec->icccm.class))
+ ec->desktop = efreet_util_desktop_exec_find(s);
+ }
+ }
+ }
+ if (!ec->desktop)
+ {
+ ec->desktop = e_exec_startup_id_pid_find(ec->netwm.startup_id,
+ ec->netwm.pid);
+ if (ec->desktop) efreet_desktop_ref(ec->desktop);
+ }
+ if (!ec->desktop && ec->icccm.name)
+ {
+ /* this works for most cases as fallback. useful when app is
+ run from a shell */
+ ec->desktop = efreet_util_desktop_exec_find(ec->icccm.name);
+ }
+ if (!ec->desktop && ec->parent)
+ {
+ E_Client *ec2 = ec->parent;
+ if (ec2->desktop)
+ {
+ efreet_desktop_ref(ec2->desktop);
+ ec->desktop = ec2->desktop;
+ }
+ }
+
+ e_comp_object_frame_icon_update(ec->frame);
+ if ((ec->new_client || ec->re_manage) && ec->desktop && (!ec->exe_inst))
+ e_exec_phony(ec);
+ ec->changes.icon = 0;
+ prop |= E_CLIENT_PROPERTY_ICON;
+ }
+
+ ec->new_client = 0;
+ ec->comp->new_clients--;
+ 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_props || ec->changes.internal_state ||
+ ec->changes.need_maximize || ec->changes.need_unmaximize;
+ ec->changes.stack = 0;
+
+ if ((!ec->input_only) && ((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;
+ e_client_focus_set_with_pointer(ec);
+ }
+ 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);
+ }
+ }
+ }
+
+ 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 (rem_change)
+ e_remember_update(ec);
+
+ if (send_event && rem_change && prop)
+ {
+ _e_client_event_property(ec, prop);
+ }
+ _e_client_hook_call(E_CLIENT_HOOK_EVAL_END, ec);
+}
+
+
+////////////////////////////////////////////////
+EINTERN void
+e_client_idler_before(void)
+{
+ const Eina_List *l;
+ E_Comp *c;
+
+ if (!eina_hash_population(clients_hash)) return;
+
+ EINA_LIST_FOREACH(e_comp_list(), l, c)
+ {
+ Eina_List *ll;
+ E_Client *ec;
+
+ EINA_LIST_FOREACH(c->clients, ll, ec)
+ {
+ int urgent = ec->icccm.urgent;
+ Eina_Stringshare *title;
+ // pass 1 - eval0. fetch properties on new or on change and
+ // call hooks to decide what to do - maybe move/resize
+ if (!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_name_get(ec);
+ if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_FETCH, ec)) continue;
+ if (title != e_client_name_get(ec))
+ _e_client_event_property(ec, E_CLIENT_PROPERTY_TITLE);
+ /* 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) &&
+ (!(((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN))))
+ {
+ const char *bordername;
+ Eina_Stringshare *pborder;
+
+ if (ec->fullscreen || ec->borderless)
+ bordername = "borderless";
+ else if (ec->bordername)
+ bordername = ec->bordername;
+ else if ((ec->mwm.borderless) || (ec->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->icccm.urgent)
+ bordername = "urgent";
+ else if ((ec->icccm.transient_for != 0) ||
+ (ec->dialog))
+ 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";
+
+ if (e_util_strcmp(ec->border.name, bordername))
+ {
+ pborder = ec->border.name;
+ ec->border.name = eina_stringshare_add(bordername);
+ if (e_comp_object_frame_theme_set(ec->frame, bordername))
+ eina_stringshare_del(pborder);
+ else
+ {
+ eina_stringshare_del(ec->border.name);
+ ec->border.name = pborder;
+ }
+ }
+ ec->border.changed = 0;
+ }
+ if (urgent != ec->icccm.urgent)
+ {
+ _e_client_event_property(ec, E_CLIENT_PROPERTY_URGENCY);
+ if (ec->icccm.urgent && (!ec->focused))
+ e_comp_object_signal_emit(ec->frame, "e,state,urgent", "e");
+ else
+ e_comp_object_signal_emit(ec->frame, "e,state,not_urgent", "e");
+ }
+ _e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_FRAME_ASSIGN, ec);
+ }
+
+ // layout hook - this is where a hook gets to figure out what to
+ // do if anything.
+#warning FIXME: this should be...better :/
+ _e_client_hook_call(E_CLIENT_HOOK_CANVAS_LAYOUT, (void*)c);
+
+ E_CLIENT_FOREACH(c, ec)
+ {
+ // 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, ec->zone->w - 5, ec->zone->h - 5)) &&
+ (!E_INSIDE(ec->x, ec->y, 0 - ec->w + 5, 0 - ec->h + 5, ec->zone->w - 5, ec->zone->h - 5))
+ )
+ {
+ if (e_config->screen_limits != E_SCREEN_LIMITS_COMPLETELY)
+ _e_client_move_lost_window_to_center(ec);
+ }
+ }
+
+
+ // pass 3 - hide windows needing hide and eval (main eval)
+ E_CLIENT_FOREACH(c, ec)
+ {
+ if (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);
+
+ 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;
+ }
+ }
+ }
+}
+
+
+EINTERN Eina_Bool
+e_client_init(void)
+{
+ clients_hash = 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, EFREET_EVENT_DESKTOP_CACHE_UPDATE,
+ _e_client_cb_efreet_cache_update, NULL);
+ E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_ICON_CACHE_UPDATE,
+ _e_client_cb_efreet_cache_update, NULL);
+ E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_ICON_THEME,
+ _e_client_cb_config_icon_theme, 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_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_STICK = ecore_event_type_new();
+ E_EVENT_CLIENT_UNSTICK = 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();
+
+ return (!!clients_hash);
+}
+
+EINTERN void
+e_client_shutdown(void)
+{
+ E_FREE_FUNC(clients_hash, eina_hash_free);
+
+ E_FREE_LIST(handlers, ecore_event_handler_del);
+
+ e_int_client_menu_hooks_clear();
+ E_FREE_FUNC(warp_timer, ecore_timer_del);
+ warp_client = NULL;
+}
+
+EAPI E_Client *
+e_client_new(E_Comp *c, E_Pixmap *cp, int first_map, int internal)
+{
+ E_Client *ec;
+
+ if (eina_hash_find(clients_hash, &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));
+
+ ec->focus_policy_override = E_FOCUS_LAST;
+ ec->w = 1;
+ ec->h = 1;
+ ec->internal = internal;
+ ec->comp = c;
+
+ ec->pixmap = cp;
+ e_pixmap_client_set(cp, ec);
+ ec->resize_mode = E_POINTER_RESIZE_NONE;
+ ec->layer = E_LAYER_CLIENT_NORMAL;
+
+ /* printf("##- ON MAP CLIENT 0x%x SIZE %ix%i %i:%i\n",
+ * ec->win, ec->w, ec->h, att->x, att->y); */
+
+ /* 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)
+ {
+ // printf("##- FIRST MAP\n");
+ 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;
+ ec->comp->new_clients++;
+
+ if (!_e_client_hook_call(E_CLIENT_HOOK_NEW_CLIENT, ec)) return NULL;
+ e_client_desk_set(ec, e_desk_current_get(e_zone_current_get(c)));
+
+ 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_CHANGED(ec);
+
+ c->clients = eina_list_append(c->clients, ec);
+ eina_hash_direct_add(clients_hash, &ec->pixmap, ec);
+
+ _e_client_event_simple(ec, E_EVENT_CLIENT_ADD);
+ 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_PRIO);
+ else
+ evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NORMAL);
+ }
+ if (!e_client_util_ignored_get(ec))
+ {
+ if (starting)
+ focus_stack = eina_list_prepend(focus_stack, ec);
+ else
+ focus_stack = eina_list_append(focus_stack, ec);
+ }
+
+ return ec;
+}
+
+EAPI 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 (ec->e.state.profile.wait_for_done) return;
+ if (e_util_strcmp(ec->e.state.profile.name, desk->window_profile))
+ {
+ eina_stringshare_refplace(&ec->e.state.profile.set, desk->window_profile);
+ EC_CHANGED(ec);
+ return;
+ }
+ }
+ 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;
+ ec->desk = desk;
+ if (desk->visible || ec->sticky)
+ {
+ e_comp_object_effect_unclip(ec->frame);
+ e_comp_object_effect_set(ec->frame, NULL);
+ 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);
+ 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);
+ ev->ec = ec;
+ 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 (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_remember_update(ec);
+ _e_client_hook_call(E_CLIENT_HOOK_DESK_SET, ec);
+}
+
+EAPI Eina_Bool
+e_client_comp_grabbed_get(void)
+{
+ return comp_grabbed;
+}
+
+EAPI E_Client *
+e_client_action_get(void)
+{
+ return action_client;
+}
+
+EAPI E_Client *
+e_client_warping_get(void)
+{
+ return warp_client;
+}
+
+
+EAPI Eina_List *
+e_clients_immortal_list(const E_Comp *c)
+{
+ const Eina_List *l, *ll;
+ Eina_List *list = NULL;
+ E_Client *ec;
+
+ if (c)
+ {
+ EINA_LIST_FOREACH(c->clients, ll, ec)
+ {
+ if (ec->lock_life)
+ list = eina_list_append(list, ec);
+ }
+ }
+ else
+ {
+ EINA_LIST_FOREACH(e_comp_list(), l, c)
+ EINA_LIST_FOREACH(c->clients, ll, ec)
+ {
+ if (ec->lock_life)
+ list = eina_list_append(list, ec);
+ }
+ }
+ return list;
+}
+
+//////////////////////////////////////////////////////////
+
+EAPI 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;
+ if (!ec->iconic)
+ e_focus_event_mouse_in(ec);
+}
+
+EAPI 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 ((!ec->input_object) && E_INSIDE(x, y, ec->x, ec->y, ec->w, ec->h)) return;
+
+ ec->mouse.current.mx = x;
+ ec->mouse.current.my = y;
+ if (!ec->iconic)
+ e_focus_event_mouse_out(ec);
+}
+
+EAPI 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;
+ if (!ec->cur_mouse_action)
+ e_bindings_wheel_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(ec), ev);
+}
+
+EAPI 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) 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 (!ec->cur_mouse_action)
+ {
+ ec->cur_mouse_action =
+ e_bindings_mouse_down_event_handle(E_BINDING_CONTEXT_WINDOW,
+ E_OBJECT(ec), ev);
+ 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)
+ e_object_ref(E_OBJECT(ec->cur_mouse_action));
+ }
+ }
+ e_focus_event_mouse_down(ec);
+ 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;
+}
+
+EAPI 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 ((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 dont 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
+ {
+ if (!e_bindings_mouse_up_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(ec), ev))
+ 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;
+}
+
+EAPI void
+e_client_mouse_move(E_Client *ec, Evas_Point *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN(ec);
+ 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 ((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(ec->comp, 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_SCREEN_LIMITS_WITHIN)
+ _e_client_stay_within_canvas(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);
+ e_zone_flip_coords_handle(ec->zone, output->x, output->y);
+ }
+ else if (e_client_resizing_get(ec))
+ {
+ _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
+ {
+ int dx, dy;
+
+ dx = ec->drag.x - output->x;
+ dy = ec->drag.y - output->y;
+ if (((dx * dx) + (dy * dy)) >
+ (e_config->drag_resist * e_config->drag_resist))
+ {
+ /* start drag! */
+ if (ec->netwm.icons || ec->desktop || ec->internal_icon)
+ {
+ Evas_Object *o = NULL;
+ const char *drag_types[] = { "enlightenment/border" };
+
+ e_object_ref(E_OBJECT(ec));
+ client_drag = e_drag_new(ec->zone->comp,
+ output->x, output->y,
+ drag_types, 1, ec, -1,
+ NULL,
+ _e_client_cb_drag_finished);
+ e_drag_resize(client_drag, e_scale * 48, e_scale * 48);
+ o = e_client_icon_add(ec, client_drag->evas);
+ if (!o)
+ {
+ /* 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, ec->drag.x, ec->drag.y);
+ }
+ ec->drag.start = 0;
+ }
+ }
+ }
+}
+///////////////////////////////////////////////////////
+
+EAPI 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;
+}
+
+EAPI 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;
+
+ 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));
+}
+
+EAPI 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 (!zone) return;
+ if (ec->zone == zone) 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->zone != ec->zone)
+ e_client_desk_set(ec, e_desk_current_get(ec->zone));
+
+ ev = E_NEW(E_Event_Client_Zone_Set, 1);
+ ev->ec = ec;
+ 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_remember_update(ec);
+ e_client_res_change_geometry_save(ec);
+ e_client_res_change_geometry_restore(ec);
+ ec->pre_res_change.valid = 0;
+}
+
+EAPI void
+e_client_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+
+ if (ec->frame)
+ evas_object_geometry_get(ec->frame, x, y, w, h);
+ else
+ {
+ if (x) *x = ec->x;
+ if (y) *y = ec->y;
+ if (w) *w = ec->w;
+ if (h) *h = ec->h;
+ }
+}
+
+EAPI 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 (!e_object_is_del(E_OBJECT(ec2)))
+ return ec2;
+ }
+ if (ec->layer == E_LAYER_CLIENT_PRIO) 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_PRIO); x++)
+ {
+ if (!ec->comp->layers[x].clients) continue;
+ EINA_INLIST_FOREACH(ec->comp->layers[x].clients, ec2)
+ if (!e_object_is_del(E_OBJECT(ec2)))
+ return ec2;
+ }
+ return NULL;
+}
+
+EAPI E_Client *
+e_client_below_get(const E_Client *ec)
+{
+ unsigned int x;
+ E_Client *ec2;
+ Eina_Inlist *l;
+
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+
+ 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 (!e_object_is_del(E_OBJECT(ec2)))
+ return ec2;
+ }
+ }
+ if (ec->layer == E_LAYER_CLIENT_DESKTOP) return NULL;
+
+ /* go down 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_DESKTOP); x--)
+ {
+ if (!ec->comp->layers[x].clients) continue;
+ EINA_INLIST_REVERSE_FOREACH(ec->comp->layers[x].clients, ec2)
+ if (!e_object_is_del(E_OBJECT(ec2)))
+ return ec2;
+ }
+ return NULL;
+}
+
+EAPI E_Client *
+e_client_bottom_get(const E_Comp *c)
+{
+ unsigned int x;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+
+ for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); x++)
+ {
+ E_Client *ec2;
+
+ if (!c->layers[x].clients) continue;
+ EINA_INLIST_FOREACH(c->layers[x].clients, ec2)
+ if (!e_object_is_del(E_OBJECT(ec2)))
+ return ec2;
+ }
+ return NULL;
+}
+
+EAPI E_Client *
+e_client_top_get(const E_Comp *c)
+{
+ unsigned int x;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+
+ for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
+ {
+ E_Client *ec2;
+
+ if (!c->layers[x].clients) continue;
+ EINA_INLIST_REVERSE_FOREACH(c->layers[x].clients, ec2)
+ if (!e_object_is_del(E_OBJECT(ec2)))
+ return ec2;
+ }
+ return NULL;
+}
+
+EAPI unsigned int
+e_clients_count(E_Comp *c)
+{
+ if (!c) return eina_hash_population(clients_hash);
+ return eina_list_count(c->clients);
+}
+
+
+/**
+ * Set a callback which will be called just prior to updating the
+ * move coordinates for a border
+ */
+EAPI void
+e_client_move_intercept_cb_set(E_Client *ec, E_Client_Move_Intercept_Cb cb)
+{
+ ec->move_intercept_cb = cb;
+}
+
+///////////////////////////////////////
+
+EAPI E_Client_Hook *
+e_client_hook_add(E_Client_Hook_Point hookpoint, E_Client_Hook_Cb func, const void *data)
+{
+ E_Client_Hook *ch;
+
+ ch = E_NEW(E_Client_Hook, 1);
+ if (!ch) return NULL;
+ ch->hookpoint = hookpoint;
+ ch->func = func;
+ ch->data = (void*)data;
+ _e_client_hooks = eina_list_append(_e_client_hooks, ch);
+ return ch;
+}
+
+EAPI void
+e_client_hook_del(E_Client_Hook *ch)
+{
+ ch->delete_me = 1;
+ if (_e_client_hooks_walking == 0)
+ {
+ _e_client_hooks = eina_list_remove(_e_client_hooks, ch);
+ free(ch);
+ }
+ else
+ _e_client_hooks_delete++;
+}
+
+///////////////////////////////////////
+
+EAPI void
+e_client_focus_latest_set(E_Client *ec)
+{
+ focus_stack = eina_list_remove(focus_stack, ec);
+ focus_stack = eina_list_prepend(focus_stack, ec);
+}
+
+EAPI void
+e_client_raise_latest_set(E_Client *ec)
+{
+ raise_stack = eina_list_remove(raise_stack, ec);
+ raise_stack = eina_list_prepend(raise_stack, ec);
+}
+
+EAPI Eina_Bool
+e_client_focus_track_enabled(void)
+{
+ return !focus_track_frozen;
+}
+
+EAPI void
+e_client_focus_track_freeze(void)
+{
+ focus_track_frozen++;
+}
+
+EAPI void
+e_client_focus_track_thaw(void)
+{
+ focus_track_frozen--;
+}
+
+/*
+ * 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).
+ *
+ */
+EAPI void
+e_client_focus_set_with_pointer(E_Client *ec)
+{
+ /* 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 */
+ if (e_pixmap_is_x(ec->pixmap))
+ {
+ /* 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;
+ evas_object_focus_set(ec->frame, 1);
+
+ if (e_config->focus_policy == E_FOCUS_CLICK) return;
+ if (!ec->visible) return;
+
+ if (e_config->focus_policy == E_FOCUS_SLOPPY)
+ {
+ E_Client *pec;
+ pec = e_client_under_pointer_get(ec->desk, ec);
+ /* Do not slide pointer when disabled (probably breaks focus
+ * on sloppy/mouse focus but requested by users). */
+ if (e_config->pointer_slide && pec && (pec != ec))
+ e_client_pointer_warp_to_center(ec);
+ }
+ else
+ {
+ if (e_config->pointer_slide)
+ e_client_pointer_warp_to_center(ec);
+ }
+}
+
+EINTERN void
+e_client_focused_set(E_Client *ec)
+{
+ E_Client *ec2, *ec_unfocus = focused;
+ Eina_List *l, *ll;
+
+ if (ec == focused) return;
+ focused = ec;
+ if (ec)
+ {
+ ec->focused = 1;
+ if (!e_config->allow_above_fullscreen)
+ {
+ 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->want_focus = ec_unfocus->focused = 0;
+ if (!e_object_is_del(E_OBJECT(ec_unfocus)))
+ e_focus_event_focus_out(ec_unfocus);
+
+ E_FREE_FUNC(ec_unfocus->raise_timer, ecore_timer_del);
+
+ e_comp_object_signal_emit(ec_unfocus->frame, "e,state,unfocused", "e");
+
+ /* if there unfocus client is fullscreen and visible */
+ if ((!e_config->allow_above_fullscreen) &&
+ (ec_unfocus->fullscreen) &&
+ ((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);
+ }
+
+ /* only send event/hook 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_hook_call(E_CLIENT_HOOK_FOCUS_UNSET, ec_unfocus);
+ }
+ break;
+ }
+ if (!ec) 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->comp->man, ec);
+ _e_client_event_simple(ec, E_EVENT_CLIENT_FOCUS_IN);
+}
+
+EAPI void
+e_client_activate(E_Client *ec, Eina_Bool just_do_it)
+{
+ 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))
+ {
+ if (ec->iconic)
+ {
+ if (e_config->clientlist_warp_to_iconified_desktop == 1)
+ e_desk_show(ec->desk);
+
+ if (!ec->lock_user_iconify)
+ e_client_uniconify(ec);
+ }
+ if ((!ec->iconic) && (!ec->sticky))
+ e_desk_show(ec->desk);
+ if (!ec->lock_user_stacking)
+ evas_object_raise(ec->frame);
+ if (!ec->lock_focus_out)
+ {
+ /* XXX ooffice does send this request for
+ config dialogs when the main window gets focus.
+ causing the pointer to jump back and forth. */
+ if ((e_config->focus_policy != E_FOCUS_CLICK) && (!ec->new_client) &&
+ (!e_config->disable_all_pointer_warps) &&
+ (!e_util_strcmp(ec->icccm.name, "VCLSalFrame")))
+ ecore_evas_pointer_warp(ec->comp->ee,
+ ec->x + (ec->w / 2), ec->y + (ec->h / 2));
+ evas_object_focus_set(ec->frame, 1);
+ }
+ }
+}
+
+EAPI E_Client *
+e_client_focused_get(void)
+{
+ return focused;
+}
+
+EAPI Eina_List *
+e_client_focus_stack_get(void)
+{
+ return focus_stack;
+}
+
+EAPI Eina_List *
+e_client_raise_stack_get(void)
+{
+ return raise_stack;
+}
+
+EAPI Eina_List *
+e_client_lost_windows_get(E_Zone *zone)
+{
+ Eina_List *list = NULL;
+ const Eina_List *l, *ll;
+ E_Client *ec;
+ E_Comp *c;
+ 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_list(), l, c)
+ {
+ if (zone->comp != c) continue;
+ EINA_LIST_FOREACH(c->clients, ll, ec)
+ {
+ if (ec->zone != zone) 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;
+}
+
+///////////////////////////////////////
+
+EAPI 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;
+
+ 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;
+
+ if (e_config->border_shade_animate && (!ec->new_client))
+ {
+ ec->changes.shading = 1;
+ EC_CHANGED(ec);
+
+ evas_object_smart_callback_call(ec->frame, "shading", (uintptr_t*)dir);
+ }
+ else
+ evas_object_smart_callback_call(ec->frame, "shaded", (uintptr_t*)dir);
+
+ e_remember_update(ec);
+}
+
+EAPI 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;
+
+ if (e_config->border_shade_animate)
+ {
+ ec->changes.shading = 1;
+ EC_CHANGED(ec);
+
+ evas_object_smart_callback_call(ec->frame, "unshading", (uintptr_t*)dir);
+ }
+ else
+ evas_object_smart_callback_call(ec->frame, "unshaded", (uintptr_t*)dir);
+
+ e_remember_update(ec);
+}
+
+///////////////////////////////////////
+
+EAPI void
+e_client_maximize(E_Client *ec, E_Maximize max)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+
+ if (!(max & E_MAXIMIZE_DIRECTION)) max |= E_MAXIMIZE_BOTH;
+
+ if ((ec->shaded) || (ec->shading)) return;
+ /* 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->saved.w = ec->client.w;
+ }
+ if (!(ec->maximized & E_MAXIMIZE_VERTICAL))
+ {
+ /* Vertical hasn't been set */
+ ec->saved.y = ec->client.y;
+ ec->saved.h = ec->client.h;
+ }
+
+ ec->saved.zone = ec->zone->num;
+ e_hints_window_size_set(ec);
+
+ if (!starting)
+ evas_object_raise(ec->frame);
+
+ _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;
+
+ 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);
+ e_remember_update(ec);
+}
+
+EAPI void
+e_client_unmaximize(E_Client *ec, E_Maximize max)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+ 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;
+ /* 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)
+ {
+ evas_object_smart_callback_call(ec->frame, "unmaximize", NULL);
+ ec->maximized = E_MAXIMIZE_NONE;
+ e_client_util_move_resize_without_frame(ec,
+ ec->saved.x,
+ ec->saved.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;
+
+ w = ec->w;
+ h = ec->h;
+ x = ec->x;
+ y = ec->y;
+
+ if (((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_SMART) ||
+ ((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_EXPAND))
+ {
+ evas_object_smart_callback_call(ec->frame, "unfullscreen", NULL);
+ }
+ if (max & E_MAXIMIZE_VERTICAL)
+ {
+ /* Remove vertical */
+ h = ec->saved.h;
+ y = ec->saved.y + ec->zone->y;
+ ec->saved.h = ec->saved.y = 0;
+ ec->maximized &= ~E_MAXIMIZE_VERTICAL;
+ ec->maximized &= ~E_MAXIMIZE_LEFT;
+ ec->maximized &= ~E_MAXIMIZE_RIGHT;
+ }
+ if (max & E_MAXIMIZE_HORIZONTAL)
+ {
+ /* Remove horizontal */
+ w = ec->saved.w;
+ x = ec->saved.x + ec->zone->x;
+ ec->saved.w = ec->saved.x = 0;
+ ec->maximized &= ~E_MAXIMIZE_HORIZONTAL;
+ }
+
+ e_client_resize_limit(ec, &w, &h);
+
+ if (!(ec->maximized & E_MAXIMIZE_DIRECTION))
+ {
+ ec->maximized = E_MAXIMIZE_NONE;
+ evas_object_smart_callback_call(ec->frame, "unmaximize", NULL);
+ e_client_util_move_resize_without_frame(ec, x, y, w, h);
+ e_hints_window_size_unset(ec);
+ }
+ else
+ {
+ e_client_util_move_resize_without_frame(ec, x, y, w, h);
+ e_hints_window_size_set(ec);
+ }
+ }
+ e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL,
+ ec->maximized & E_MAXIMIZE_VERTICAL);
+ }
+ if (!e_client_util_ignored_get(ec))
+ {
+ ec->border.changed = 1;
+ EC_CHANGED(ec);
+ }
+ e_remember_update(ec);
+}
+
+EAPI 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->shaded) || (ec->shading) || ec->fullscreen) return;
+ if (ec->new_client)
+ {
+ ec->need_fullscreen = 1;
+ return;
+ }
+ 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->x - ec->zone->x;
+ ec->saved.y = ec->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;
+ if (!e_config->allow_above_fullscreen)
+ evas_object_layer_set(ec->frame, E_LAYER_CLIENT_FULLSCREEN);
+ else if (e_config->mode.presentation)
+ evas_object_layer_set(ec->frame, E_LAYER_CLIENT_TOP);
+
+ if ((eina_list_count(ec->comp->zones) > 1) ||
+ (policy == E_FULLSCREEN_RESIZE) || (!ecore_x_randr_query()))
+ {
+ 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);
+ }
+ ec->fullscreen = 1;
+
+ e_hints_window_fullscreen_set(ec, 1);
+ e_hints_window_size_unset(ec);
+ if (!e_client_util_ignored_get(ec))
+ {
+ ec->border.changed = 1;
+ EC_CHANGED(ec);
+ }
+ ec->fullscreen_policy = policy;
+ evas_object_smart_callback_call(ec->frame, "fullscreen", NULL);
+
+ _e_client_event_simple(ec, E_EVENT_CLIENT_FULLSCREEN);
+
+ e_remember_update(ec);
+}
+
+EAPI void
+e_client_unfullscreen(E_Client *ec)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+ 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);
+
+ 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);
+ if (!e_client_util_ignored_get(ec))
+ {
+ ec->border.changed = 1;
+ EC_CHANGED(ec);
+ }
+ ec->fullscreen_policy = 0;
+ evas_object_smart_callback_call(ec->frame, "unfullscreen", NULL);
+ _e_client_event_simple(ec, E_EVENT_CLIENT_UNFULLSCREEN);
+
+ e_remember_update(ec);
+ if (!ec->desk->fullscreen_clients)
+ e_comp_render_queue(ec->comp);
+}
+
+///////////////////////////////////////
+
+
+EAPI void
+e_client_iconify(E_Client *ec)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+ if (ec->shading || ec->iconic) return;
+ ec->iconic = 1;
+ ec->take_focus = 0;
+ if (ec->fullscreen)
+ ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
+ e_client_comp_hidden_set(ec, 1);
+ if (ec->new_client)
+ {
+ ec->visible = 0;
+ ec->changes.visible = 0;
+ EC_CHANGED(ec);
+ e_comp_object_signal_emit(ec->frame, "e,action,iconify", "e");
+ }
+ else
+ evas_object_hide(ec->frame);
+ e_hints_window_iconic_set(ec);
+
+ _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_remember_update(ec);
+}
+
+EAPI void
+e_client_uniconify(E_Client *ec)
+{
+ E_Desk *desk;
+
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+ if (ec->shading || (!ec->iconic)) return;
+ desk = e_desk_current_get(ec->desk->zone);
+ e_client_desk_set(ec, desk);
+ evas_object_raise(ec->frame);
+ evas_object_show(ec->frame);
+ e_client_comp_hidden_set(ec, 0);
+ ec->deskshow = ec->iconic = 0;
+ evas_object_focus_set(ec->frame, 1);
+
+ _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)
+ e_client_uniconify(child);
+ }
+ e_remember_update(ec);
+}
+
+///////////////////////////////////////
+
+EAPI void
+e_client_stick(E_Client *ec)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+ if (ec->sticky) return;
+ ec->sticky = 1;
+ e_hints_window_sticky_set(ec, 1);
+ evas_object_show(ec->frame);
+
+ 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_simple(ec, E_EVENT_CLIENT_STICK);
+ e_remember_update(ec);
+}
+
+EAPI void
+e_client_unstick(E_Client *ec)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+ /* Set the desk before we unstick the client */
+ if (!ec->sticky) return;
+ ec->sticky = 0;
+ e_hints_window_sticky_set(ec, 0);
+
+ 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_comp_object_signal_emit(ec->frame, "e,state,unsticky", "e");
+ _e_client_event_simple(ec, E_EVENT_CLIENT_UNSTICK);
+
+ e_client_desk_set(ec, e_desk_current_get(ec->zone));
+ e_remember_update(ec);
+}
+
+EAPI 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);
+}
+
+///////////////////////////////////////
+
+EAPI void
+e_client_comp_hidden_set(E_Client *ec, Eina_Bool hidden)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+
+ hidden = !!hidden;
+ if (ec->comp_hidden == hidden) return;
+ ec->comp_hidden = hidden;
+ evas_object_smart_callback_call(ec->frame, "comp_hidden", NULL);
+}
+
+///////////////////////////////////////
+
+EAPI void
+e_client_act_move_keyboard(E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN(ec);
+
+ if (!_e_client_move_begin(ec))
+ return;
+
+ if (!_e_client_action_input_win_new(ec))
+ {
+ _e_client_move_end(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;
+
+ 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);
+}
+
+EAPI void
+e_client_act_resize_keyboard(E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN(ec);
+
+ if (!e_client_resize_begin(ec))
+ return;
+
+ _e_client_action_init(ec);
+ _e_client_action_resize_timeout_add();
+
+ 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);
+}
+
+EAPI 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 (e_client_resizing_get(ec) || (ec->moving)) return;
+ if (!_e_client_move_begin(ec))
+ return;
+
+ if (!_e_client_action_input_win_new(ec))
+ {
+ _e_client_move_end(ec);
+ return;
+ }
+ _e_client_action_init(ec);
+ e_zone_edge_disable();
+ ec->moving = 1;
+ e_pointer_mode_push(ec, E_POINTER_MOVE);
+ if (ev)
+ {
+ char source[256];
+
+ snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button);
+ _e_client_moveinfo_gather(ec, source);
+ }
+}
+
+EAPI 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->moving) return;
+ e_zone_edge_enable();
+ _e_client_move_end(ec);
+ e_zone_flip_coords_handle(ec->zone, -1, -1);
+ _e_client_action_finish();
+}
+
+EAPI void
+e_client_act_resize_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+ if (ec->lock_user_size || ec->shaded || ec->shading) return;
+ if (e_client_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->mouse.current.mx > (ec->x + ec->w / 5)) &&
+ (ec->mouse.current.mx < (ec->x + ec->w * 4 / 5)))
+ {
+ if (ec->mouse.current.my < (ec->y + ec->h / 2))
+ {
+ ec->resize_mode = E_POINTER_RESIZE_T;
+ }
+ else
+ {
+ ec->resize_mode = E_POINTER_RESIZE_B;
+ }
+ }
+ else if (ec->mouse.current.mx < (ec->x + ec->w / 2))
+ {
+ if ((ec->mouse.current.my > (ec->y + ec->h / 5)) &&
+ (ec->mouse.current.my < (ec->y + ec->h * 4 / 5)))
+ {
+ ec->resize_mode = E_POINTER_RESIZE_L;
+ }
+ else if (ec->mouse.current.my < (ec->y + ec->h / 2))
+ {
+ ec->resize_mode = E_POINTER_RESIZE_TL;
+ }
+ else
+ {
+ ec->resize_mode = E_POINTER_RESIZE_BL;
+ }
+ }
+ else
+ {
+ if ((ec->mouse.current.my > (ec->y + ec->h / 5)) &&
+ (ec->mouse.current.my < (ec->y + ec->h * 4 / 5)))
+ {
+ ec->resize_mode = E_POINTER_RESIZE_R;
+ }
+ else if (ec->mouse.current.my < (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))
+ {
+ ec->resize_mode = E_POINTER_RESIZE_NONE;
+ return;
+ }
+ _e_client_action_init(ec);
+ e_pointer_mode_push(ec, ec->resize_mode);
+}
+
+EAPI 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 (e_client_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();
+}
+
+EAPI 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->border_menu) return;
+ if (ev)
+ e_int_client_menu_show(ec, ev->canvas.x, ev->canvas.y, key, ev->timestamp);
+ else
+ {
+ int x, y;
+
+ evas_pointer_canvas_xy_get(ec->comp->evas, &x, &y);
+ e_int_client_menu_show(ec, x, y, key, 0);
+ }
+}
+
+EAPI void
+e_client_act_close_begin(E_Client *ec)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+ 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);
+ }
+}
+
+EAPI void
+e_client_act_kill_begin(E_Client *ec)
+{
+ E_OBJECT_CHECK(ec);
+ E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+ 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);
+}
+
+////////////////////////////////////////////////
+
+
+EAPI Evas_Object *
+e_client_icon_add(E_Client *ec, Evas *evas)
+{
+ Evas_Object *o;
+
+ E_OBJECT_CHECK_RETURN(ec, NULL);
+ E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
+
+ o = NULL;
+ if (ec->internal)
+ {
+ if (!ec->internal_icon)
+ {
+ o = e_icon_add(evas);
+ e_util_icon_theme_set(o, "enlightenment");
+ }
+ else
+ {
+ if (!ec->internal_icon_key)
+ {
+ char *ext;
+
+ ext = strrchr(ec->internal_icon, '.');
+ if ((ext) && ((!strcmp(ext, ".edj"))))
+ {
+ o = edje_object_add(evas);
+ if (!edje_object_file_set(o, ec->internal_icon, "icon"))
+ e_util_icon_theme_set(o, "enlightenment");
+ }
+ else if (ext)
+ {
+ o = e_icon_add(evas);
+ e_icon_file_set(o, ec->internal_icon);
+ }
+ else
+ {
+ o = e_icon_add(evas);
+ if (!e_util_icon_theme_set(o, ec->internal_icon))
+ e_util_icon_theme_set(o, "enlightenment");
+ }
+ }
+ else
+ {
+ o = edje_object_add(evas);
+ edje_object_file_set(o, ec->internal_icon,
+ ec->internal_icon_key);
+ }
+ }
+ return o;
+ }
+ if ((e_config->use_app_icon) && (ec->icon_preference != E_ICON_PREF_USER))
+ {
+ if (ec->netwm.icons)
+ {
+ o = e_icon_add(evas);
+ e_icon_data_set(o, ec->netwm.icons[0].data,
+ ec->netwm.icons[0].width,
+ ec->netwm.icons[0].height);
+ e_icon_alpha_set(o, 1);
+ return o;
+ }
+ }
+ if (!o)
+ {
+ if ((ec->desktop) && (ec->icon_preference != E_ICON_PREF_NETWM))
+ {
+ o = e_icon_add(evas);
+ if (o)
+ {
+ e_icon_fdo_icon_set(o, ec->desktop->icon);
+ return o;
+ }
+ }
+ else if (ec->netwm.icons)
+ {
+ o = e_icon_add(evas);
+ e_icon_data_set(o, ec->netwm.icons[0].data,
+ ec->netwm.icons[0].width,
+ ec->netwm.icons[0].height);
+ e_icon_alpha_set(o, 1);
+ return o;
+ }
+ }
+
+ o = e_icon_add(evas);
+ e_util_icon_theme_set(o, "unknown");
+ return o;
+}
+
+////////////////////////////////////////////
+
+EAPI 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;
+ 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);
+}
+
+////////////////////////////////////////////
+
+EAPI 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);
+}
+
+EAPI 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);
+}
+
+EAPI Eina_Bool
+e_client_resize_begin(E_Client *ec)
+{
+ if (!ec->lock_user_stacking)
+ {
+ if (e_config->border_raise_on_mouse_action)
+ evas_object_raise(ec->frame);
+ }
+ if ((ec->shaded) || (ec->shading) ||
+ (ec->fullscreen) || (ec->lock_user_size))
+ return EINA_FALSE;
+
+ if (!_e_client_action_input_win_new(ec)) return EINA_FALSE;
+
+ ecresize = ec;
+ return _e_client_hook_call(E_CLIENT_HOOK_RESIZE_BEGIN, ec);
+}
+
+
+////////////////////////////////////////////
+
+EAPI 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);
+}
+
+////////////////////////////////////////////
+
+EAPI 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 (e_client_resizing_get(ec) || (ec->moving)) return;
+ if (!_e_client_move_begin(ec)) return;
+ ec->moving = 1;
+ e_pointer_mode_push(ec, E_POINTER_MOVE);
+ e_zone_edge_disable();
+ _e_client_moveinfo_gather(ec, sig);
+ if (ec->cur_mouse_action)
+ {
+ if ((!ec->cur_mouse_action->func.end_mouse) &&
+ (!ec->cur_mouse_action->func.end))
+ ec->cur_mouse_action = NULL;
+ else
+ e_object_unref(E_OBJECT(ec->cur_mouse_action));
+ }
+ ec->cur_mouse_action = e_action_find("window_move");
+ if (ec->cur_mouse_action)
+ e_object_ref(E_OBJECT(ec->cur_mouse_action));
+}
+
+EAPI 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->moving) return;
+ e_zone_edge_enable();
+ _e_client_move_end(ec);
+ e_zone_flip_coords_handle(ec->zone, -1, -1);
+}
+
+EAPI 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_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))
+ {
+ ec->resize_mode = E_POINTER_RESIZE_NONE;
+ return;
+ }
+ e_pointer_mode_push(ec, ec->resize_mode);
+ if (ec->cur_mouse_action)
+ {
+ if ((!ec->cur_mouse_action->func.end_mouse) &&
+ (!ec->cur_mouse_action->func.end))
+ ec->cur_mouse_action = NULL;
+ else
+ e_object_unref(E_OBJECT(ec->cur_mouse_action));
+ }
+ ec->cur_mouse_action = e_action_find("window_resize");
+ if (ec->cur_mouse_action)
+ e_object_ref(E_OBJECT(ec->cur_mouse_action));
+}
+
+EAPI 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_resizing_get(ec)) return;
+ _e_client_resize_handle(ec);
+ _e_client_resize_end(ec);
+ ec->changes.reset_gravity = 1;
+ EC_CHANGED(ec);
+}
+
+////////////////////////////////////////////
+
+EAPI 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 (*w > ec->icccm.max_w) *w = ec->icccm.max_w;
+ else if (*w < ec->icccm.min_w)
+ *w = ec->icccm.min_w;
+ if (*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);
+}
+
+////////////////////////////////////////////
+
+
+
+EAPI 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)
+ ecore_evas_pointer_xy_get(e_comp_get(desk)->ee, &x, &y);
+ else if (exclude)
+ ecore_evas_pointer_xy_get(exclude->comp->ee, &x, &y);
+ else
+ return NULL;
+
+ return _e_client_under_pointer_helper(desk, exclude, x, y);
+}
+
+////////////////////////////////////////////
+
+EAPI int
+e_client_pointer_warp_to_center_now(E_Client *ec)
+{
+ if (e_config->disable_all_pointer_warps) return 0;
+ if (warp_client == ec)
+ {
+ ecore_evas_pointer_warp(ec->comp->ee, warp_to_x, warp_to_y);
+ warp_to = 0;
+ }
+ else
+ {
+ if (e_client_pointer_warp_to_center(ec))
+ e_client_pointer_warp_to_center_now(ec);
+ }
+ return 1;
+}
+
+EAPI int
+e_client_pointer_warp_to_center(E_Client *ec)
+{
+ int x, y;
+ E_Client *cec = NULL;
+
+ if (e_config->disable_all_pointer_warps) return 0;
+ /* Only warp the pointer if it is not already in the area of
+ * the given border */
+ ecore_evas_pointer_xy_get(ec->comp->ee, &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;
+ ecore_evas_pointer_xy_get(warp_client->comp->ee, &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;
+}
+
+////////////////////////////////////////////
+
+EAPI 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;
+}
+
+////////////////////////////////////////////
+
+
+EAPI Eina_Stringshare *
+e_client_name_get(const E_Client *ec)
+{
+ E_OBJECT_CHECK_RETURN(ec, NULL);
+ E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
+ if (ec->netwm.name)
+ return ec->netwm.name;
+ else if (ec->icccm.title)
+ return ec->icccm.title;
+ return NULL;
+}
+
+EAPI Eina_Bool
+e_client_util_is_stacking(const E_Client *ec)
+{
+ return ec->comp->layers[e_comp_canvas_layer_map(ec->layer)].obj == ec->frame;
+}