You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

5844 lines
174 KiB

#include "e.h"
static int _e_client_hooks_delete = 0;
static int _e_client_hooks_walking = 0;
E_API int E_EVENT_CLIENT_ADD = -1;
E_API int E_EVENT_CLIENT_REMOVE = -1;
E_API int E_EVENT_CLIENT_ZONE_SET = -1;
E_API int E_EVENT_CLIENT_DESK_SET = -1;
E_API int E_EVENT_CLIENT_RESIZE = -1;
E_API int E_EVENT_CLIENT_MOVE = -1;
E_API int E_EVENT_CLIENT_SHOW = -1;
E_API int E_EVENT_CLIENT_HIDE = -1;
E_API int E_EVENT_CLIENT_ICONIFY = -1;
E_API int E_EVENT_CLIENT_UNICONIFY = -1;
E_API int E_EVENT_CLIENT_STACK = -1;
E_API int E_EVENT_CLIENT_FOCUS_IN = -1;
E_API int E_EVENT_CLIENT_FOCUS_OUT = -1;
E_API int E_EVENT_CLIENT_PROPERTY = -1;
E_API int E_EVENT_CLIENT_FULLSCREEN = -1;
E_API int E_EVENT_CLIENT_UNFULLSCREEN = -1;
static Eina_Hash *clients_hash[2] = {NULL}; // pixmap->client
static unsigned int focus_track_frozen = 0;
static int warp_to = 0;
static int warp_to_x = 0;
static int warp_to_y = 0;
static int warp_x[2] = {0}; //{cur,prev}
static int warp_y[2] = {0}; //{cur,prev}
static Ecore_Timer *warp_timer = NULL;
static E_Client *focused = NULL;
static E_Client *warp_client = NULL;
static E_Client *ecmove = NULL;
static E_Client *ecresize = NULL;
static E_Client *action_client = NULL;
static E_Drag *client_drag = NULL;
static Eina_List *focus_stack = NULL;
static Eina_List *raise_stack = NULL;
static Eina_Bool comp_grabbed = EINA_FALSE;
static Evas_Object *action_rect;
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, 0, 0, 0};
static E_Client_Layout_Cb _e_client_layout_cb = NULL;
EINTERN void e_client_focused_set(E_Client *ec);
static Eina_Inlist *_e_client_hooks[E_CLIENT_HOOK_LAST] = {NULL};
///////////////////////////////////////////
static Eina_Bool
_e_client_cb_efreet_cache_update(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
{
const Eina_List *l;
E_Client *ec;
/* mark all clients for desktop/icon updates */
EINA_LIST_FOREACH(e_comp->clients, l, 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)
{
const Eina_List *l;
E_Client *ec;
/* mark all clients for desktop/icon updates */
EINA_LIST_FOREACH(e_comp->clients, l, 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)
{
const Eina_List *l;
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->clients, l, 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)
{
const Eina_List *l;
E_Client *ec;
EINA_LIST_FOREACH(e_comp->clients, l, ec)
{
if (e_object_is_del(E_OBJECT(ec))) continue;
ec->e.fetch.profile = 1;
EC_CHANGED(ec);
}
return ECORE_CALLBACK_RENEW;
}
static void
_e_client_cb_drag_finished(E_Drag *drag, int dropped EINA_UNUSED)
{
E_Client *ec;
ec = drag->data;
UNREFD(ec, 1);
e_object_unref(E_OBJECT(ec));
client_drag = NULL;
}
static void
_e_client_desk_window_profile_wait_desk_delfn(void *data, void *obj)
{
E_Client *ec = data;
E_Desk *desk = obj, *new_desk;
const char *p;
int i;
if (e_object_is_del(E_OBJECT(ec))) return;
ec->e.state.profile.wait_desk_delfn = NULL;
eina_stringshare_replace(&ec->e.state.profile.wait, NULL);
if (ec->e.state.profile.wait_desk)
e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk));
ec->e.state.profile.wait_desk = NULL;
ec->e.state.profile.wait_for_done = 0;
if (!ec->e.state.profile.use) return;
new_desk = e_comp_desk_window_profile_get(desk->window_profile);
if (new_desk)
e_client_desk_set(ec, new_desk);
else
{
for (i = 0; i < ec->e.state.profile.num; i++)
{
p = ec->e.state.profile.available_list[i];
new_desk = e_comp_desk_window_profile_get(p);
if (new_desk)
{
e_client_desk_set(ec, new_desk);
break;
}
}
}
}
////////////////////////////////////////////////
static Eina_Bool
_e_client_pointer_warp_to_center_timer(void *data EINA_UNUSED)
{
if (warp_to && warp_client)
{
int x, y;
double spd;
ecore_evas_pointer_xy_get(e_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(e_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_Inlist *l;
E_Client_Hook *ch;
unsigned int x;
for (x = 0; x < E_CLIENT_HOOK_LAST; x++)
EINA_INLIST_FOREACH_SAFE(_e_client_hooks[x], l, ch)
{
if (!ch->delete_me) continue;
_e_client_hooks[x] = eina_inlist_remove(_e_client_hooks[x], EINA_INLIST_GET(ch));
free(ch);
}
}
static Eina_Bool
_e_client_hook_call(E_Client_Hook_Point hookpoint, E_Client *ec)
{
E_Client_Hook *ch;
e_object_ref(E_OBJECT(ec));
_e_client_hooks_walking++;
EINA_INLIST_FOREACH(_e_client_hooks[hookpoint], ch)
{
if (ch->delete_me) continue;
ch->func(ch->data, ec);
if ((hookpoint != E_CLIENT_HOOK_DEL) &&
(hookpoint != E_CLIENT_HOOK_MOVE_END) &&
(hookpoint != E_CLIENT_HOOK_RESIZE_END) &&
(hookpoint != E_CLIENT_HOOK_FOCUS_UNSET) &&
e_object_is_del(E_OBJECT(ec)))
break;
}
_e_client_hooks_walking--;
if ((_e_client_hooks_walking == 0) && (_e_client_hooks_delete > 0))
_e_client_hooks_clean();
return !!e_object_unref(E_OBJECT(ec));
}
///////////////////////////////////////////
static void
_e_client_event_simple_free(void *d EINA_UNUSED, E_Event_Client *ev)
{
UNREFD(ev->ec, 3);
e_object_unref(E_OBJECT(ev->ec));
free(ev);
}
static void
_e_client_event_simple(E_Client *ec, int type)
{
E_Event_Client *ev;
ev = E_NEW(E_Event_Client, 1);
ev->ec = ec;
REFD(ec, 3);
e_object_ref(E_OBJECT(ec));
ecore_event_add(type, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
}
static void
_e_client_event_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;
REFD(ec, 33);
e_object_ref(E_OBJECT(ec));
ecore_event_add(E_EVENT_CLIENT_PROPERTY, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
}
static void
_e_client_event_desk_set_free(void *d EINA_UNUSED, E_Event_Client_Desk_Set *ev)
{
UNREFD(ev->ec, 4);
e_object_unref(E_OBJECT(ev->ec));
e_object_unref(E_OBJECT(ev->desk));
free(ev);
}
static void
_e_client_event_zone_set_free(void *d EINA_UNUSED, E_Event_Client_Zone_Set *ev)
{
UNREFD(ev->ec, 5);
e_object_unref(E_OBJECT(ev->ec));
e_object_unref(E_OBJECT(ev->zone));
free(ev);
}
////////////////////////////////////////////////
static int
_e_client_action_input_win_del(void)
{
if (!comp_grabbed) return 0;
comp_grabbed = 0;
E_FREE_FUNC(action_rect, evas_object_del);
e_comp_shape_queue();
e_comp_ungrab_input(1, 1);
return 1;
}
static void
_e_client_action_finish(void)
{
if (comp_grabbed)
_e_client_action_input_win_del();
if (action_handler_key && action_client)
evas_object_freeze_events_set(action_client->frame, 0);
E_FREE_FUNC(action_timer, ecore_timer_del);
E_FREE_FUNC(action_handler_key, ecore_event_handler_del);
E_FREE_FUNC(action_handler_mouse, ecore_event_handler_del);
if (action_client)
{
action_client->keyboard_resizing = 0;
if (action_client->internal_elm_win)
ecore_event_window_ignore_events(elm_win_window_id_get(action_client->internal_elm_win), 0);
}
action_client = NULL;
}
static void
_e_client_mouse_action_end(E_Client *ec)
{
if (!ec->cur_mouse_action) return;
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);
}
static void
_e_client_revert_focus(E_Client *ec)
{
E_Client *pec;
E_Desk *desk;
if (stopping) return;
if (!ec->focused) return;
if (!ec->zone) return;
desk = e_desk_current_get(ec->zone);
if (ec->desk == desk)
evas_object_focus_set(ec->frame, 0);
if (ec->stack.prev)
{
ec->stack.focus_skip = 1;
pec = e_client_stack_active_adjust(ec);
ec->stack.focus_skip = 0;
if ((pec != ec) && (!pec->iconic))
evas_object_focus_set(pec->frame, 1);
else
{
if ((e_object_is_del(E_OBJECT(ec))) || (ec->iconic))
{
Eina_Bool unlock = ec->lock_focus_out;
ec->lock_focus_out = 1;
pec = e_desk_last_focused_focus(desk);
ec->lock_focus_out = unlock;
}
}
}
else if ((ec->parent) &&
(ec->parent->desk == desk) && (ec->parent->modal == ec))
{
evas_object_focus_set(ec->parent->frame, 1);
if (e_config->raise_on_revert_focus)
evas_object_raise(ec->parent->frame);
}
else if (e_config->focus_revert_on_hide_or_close)
{
Eina_Bool unlock = ec->lock_focus_out;
ec->lock_focus_out = 1;
pec = 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);
/* no autoraise/revert here because it's probably annoying */
}
}
static void
_e_client_free(E_Client *ec)
{
if (ec->pixmap)
{
if (e_pixmap_free(ec->pixmap))
e_pixmap_client_set(ec->pixmap, NULL);
ec->pixmap = NULL;
}
if (ec->frame)
{
e_comp_object_redirected_set(ec->frame, 0);
e_comp_object_render_update_del(ec->frame);
}
E_OBJECT(ec)->references++;
if (ec->fullscreen)
{
ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
if (!ec->desk->fullscreen_clients)
e_comp_render_queue();
}
if (ec->new_client)
e_comp->new_clients--;
if (ec->e.state.profile.use)
{
e_client_desk_window_profile_wait_desk_set(ec, NULL);
if (ec->e.state.profile.available_list)
{
int i;
for (i = 0; i < ec->e.state.profile.num; i++)
eina_stringshare_replace(&ec->e.state.profile.available_list[i], NULL);
E_FREE(ec->e.state.profile.available_list);
}
ec->e.state.profile.num = 0;
eina_stringshare_replace(&ec->e.state.profile.set, NULL);
eina_stringshare_replace(&ec->e.state.profile.wait, NULL);
eina_stringshare_replace(&ec->e.state.profile.name, NULL);
ec->e.state.profile.wait_for_done = 0;
ec->e.state.profile.use = 0;
}
if (ec->e.state.video_parent && ec->e.state.video_parent_client)
{
ec->e.state.video_parent_client->e.state.video_child =
eina_list_remove(ec->e.state.video_parent_client->e.state.video_child, ec);
}
if (ec->e.state.video_child)
{
E_Client *tmp;
EINA_LIST_FREE(ec->e.state.video_child, tmp)
tmp->e.state.video_parent_client = NULL;
}
E_FREE_FUNC(ec->internal_elm_win, evas_object_del);
E_FREE_FUNC(ec->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);
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);
eina_stringshare_replace(&ec->uuid, NULL);
focus_stack = eina_list_remove(focus_stack, ec);
raise_stack = eina_list_remove(raise_stack, ec);
e_hints_client_list_set();
if (ec->e.state.profile.wait_desk)
{
e_object_delfn_del(E_OBJECT(ec->e.state.profile.wait_desk),
ec->e.state.profile.wait_desk_delfn);
ec->e.state.profile.wait_desk_delfn = NULL;
e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk));
}
if (ec->stack.prev) ec->stack.prev->stack.next = ec->stack.next;
if (ec->stack.next) ec->stack.next->stack.prev = ec->stack.prev;
ec->e.state.profile.wait_desk = NULL;
evas_object_del(ec->frame);
E_OBJECT(ec)->references--;
free(ec);
}
static void
_e_client_del(E_Client *ec)
{
E_Client *child;
E_Client_Volume_Sink *sink;
EINA_LIST_FREE(ec->sinks, sink)
e_client_volume_sink_remove(ec, sink);
for (child = ec->stack.next; child; child = child->stack.next)
e_client_act_close_begin(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))
{
if (e_exec_phony_del(ec->exe_inst))
ec->exe_inst = NULL;
}
else
{
if (!ec->exe_inst->deleted)
{
ec->exe_inst->clients = eina_list_remove(ec->exe_inst->clients, ec);
ec->exe_inst = NULL;
}
}
}
_e_client_mouse_action_end(ec);
if (action_client == ec) _e_client_action_finish();
e_pointer_type_pop(e_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);
if (ec->frame) evas_object_pass_events_set(ec->frame, 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_FREE_FUNC(ec->color_editor, evas_object_del);
e_int_client_menu_del(ec);
E_FREE_FUNC(ec->raise_timer, ecore_timer_del);
if (ec->internal_elm_win)
evas_object_hide(ec->internal_elm_win);
if (ec->focused)
_e_client_revert_focus(ec);
if (ec->frame) evas_object_focus_set(ec->frame, 0);
E_FREE_FUNC(ec->ping_poller, ecore_poller_del);
eina_hash_del_by_key(clients_hash[e_pixmap_type_get(ec->pixmap)], &ec->pixmap);
/* must be called before parent/child clear */
_e_client_hook_call(E_CLIENT_HOOK_DEL, ec);
E_FREE(ec->comp_data);
if ((!ec->new_client) && (!stopping))
_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;
e_comp->clients = eina_list_remove(e_comp->clients, ec);
if (ec->frame) e_comp_object_render_update_del(ec->frame);
}
///////////////////////////////////////////
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(void)
{
if (comp_grabbed)
{
CRI("DOUBLE COMP GRAB! ACK!!!!");
return 1;
}
comp_grabbed = e_comp_grab_input(1, 1);
if (!comp_grabbed) _e_client_action_input_win_del();
return comp_grabbed;
}
static void
_e_client_action_event_grabber_mouse_up(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Event_Mouse_Down *ev = event_info;
E_Binding_Event_Mouse_Button ev2;
if (!action_client) return;
e_bindings_evas_event_mouse_button_convert(ev, &ev2);
e_client_mouse_up(action_client, ev->button, &ev->output, &ev2);
if (!action_client) return;
if (action_client->moving)
e_client_act_move_end(action_client, NULL);
if (!action_client) return;
if (e_client_util_resizing_get(action_client))
e_client_act_resize_end(action_client, NULL);
}
static void
_e_client_action_event_grabber_mouse_move(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Event_Mouse_Move *ev = event_info;
if (action_client)
e_client_mouse_move(action_client, &ev->cur.output);
}
static void
_e_client_action_event_grabber_init(E_Client *ec)
{
action_rect = e_comp_canvas_event_grabber_add();
evas_object_event_callback_add(action_rect, EVAS_CALLBACK_MOUSE_UP, _e_client_action_event_grabber_mouse_up, NULL);
evas_object_event_callback_add(action_rect, EVAS_CALLBACK_MOUSE_MOVE, _e_client_action_event_grabber_mouse_move, NULL);
evas_object_smart_member_add(ec->frame, action_rect);
evas_object_resize(action_rect, e_comp->w, e_comp->h);
evas_object_layer_set(action_rect, EVAS_LAYER_MAX - 100);
evas_object_show(action_rect);
evas_object_event_grabber_freeze_when_visible_set(action_rect, 1);
e_comp_shape_queue();
}
static void
_e_client_action_init(E_Client *ec)
{
action_orig.x = ec->x;
action_orig.y = ec->y;
action_orig.w = ec->w;
action_orig.h = ec->h;
if (action_client)
{
action_client->keyboard_resizing = 0;
if (action_client->internal_elm_win)
ecore_event_window_ignore_events(elm_win_window_id_get(action_client->internal_elm_win), 0);
}
action_client = ec;
if (ec->internal_elm_win)
ecore_event_window_ignore_events(elm_win_window_id_get(ec->internal_elm_win), 1);
}
static void
_e_client_action_restore_orig(E_Client *ec)
{
if (action_client != ec)
return;
evas_object_geometry_set(ec->frame, action_orig.x, action_orig.y, action_orig.w, action_orig.h);
}
static int
_e_client_key_down_modifier_apply(int modifier, int value)
{
if (modifier & ECORE_EVENT_MODIFIER_CTRL) return value * 5;
else if (modifier & ECORE_EVENT_MODIFIER_ALT)
{
value /= 5;
if (value) return value;
else return 1;
}
return value;
}
static int
_e_client_move_begin(E_Client *ec)
{
if ((ec->fullscreen) || (ec->lock_user_location))
return 0;
/*
if (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()) return 0;
ec->moving = 1;
ecmove = ec;
if (!ec->lock_user_stacking)
{
if (e_config->border_raise_on_mouse_action)
evas_object_raise(ec->frame);
}
_e_client_hook_call(E_CLIENT_HOOK_MOVE_BEGIN, ec);
if (!ec->moving)
{
if (ecmove == ec) ecmove = NULL;
_e_client_action_input_win_del();
return 0;
}
E_FREE_FUNC(ec->raise_timer, ecore_timer_del);
_e_client_action_event_grabber_init(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();
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)
{
double timeout = e_config->border_keyboard.timeout;
E_FREE_FUNC(action_timer, ecore_timer_del);
if (!EINA_DBL_NONZERO(timeout)) timeout = 5.0;
action_timer = ecore_timer_loop_add(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, dx, dy;
if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
if (!action_client)
{
ERR("no action_client!");
goto stop;
}
x = action_client->x;
y = action_client->y;
dx = e_config->border_keyboard.move.dx;
dx = _e_client_key_down_modifier_apply(ev->modifiers, dx);
dy = e_config->border_keyboard.move.dy;
dy = _e_client_key_down_modifier_apply(ev->modifiers, dy);
switch (e_util_key_geometry_action_get(ev->key, &x, &y, dx, dy))
{
case E_UTIL_ACTION_DONE:
goto stop;
break;
case E_UTIL_ACTION_ABORT:
_e_client_action_restore_orig(action_client);
goto stop;
break;
case E_UTIL_ACTION_DO:
evas_object_move(action_client->frame, x, y);
_e_client_action_move_timeout_add();
break;
case E_UTIL_ACTION_NONE:
default:
break;
}
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;
if (e_comp->updating) return;
x = ec->x;
y = ec->y;
w = ec->w;
h = ec->h;
if ((ec->resize_mode == E_POINTER_RESIZE_TR) ||
(ec->resize_mode == E_POINTER_RESIZE_R) ||
(ec->resize_mode == E_POINTER_RESIZE_BR))
{
if ((ec->moveinfo.down.button >= 1) &&
(ec->moveinfo.down.button <= 3))
w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w +
(ec->mouse.current.mx - ec->moveinfo.down.mx);
else
w = ec->moveinfo.down.w + (ec->mouse.current.mx - ec->moveinfo.down.mx);
}
else if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
(ec->resize_mode == E_POINTER_RESIZE_L) ||
(ec->resize_mode == E_POINTER_RESIZE_BL))
{
if ((ec->moveinfo.down.button >= 1) &&
(ec->moveinfo.down.button <= 3))
w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w -
(ec->mouse.current.mx - ec->moveinfo.down.mx);
else
w = ec->moveinfo.down.w - (ec->mouse.current.mx - ec->moveinfo.down.mx);
}
if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
(ec->resize_mode == E_POINTER_RESIZE_T) ||
(ec->resize_mode == E_POINTER_RESIZE_TR))
{
if ((ec->moveinfo.down.button >= 1) &&
(ec->moveinfo.down.button <= 3))
h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h -
(ec->mouse.current.my - ec->moveinfo.down.my);
else
h = ec->moveinfo.down.h - (ec->mouse.current.my - ec->moveinfo.down.my);
}
else if ((ec->resize_mode == E_POINTER_RESIZE_BL) ||
(ec->resize_mode == E_POINTER_RESIZE_B) ||
(ec->resize_mode == E_POINTER_RESIZE_BR))
{
if ((ec->moveinfo.down.button >= 1) &&
(ec->moveinfo.down.button <= 3))
h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h +
(ec->mouse.current.my - ec->moveinfo.down.my);
else
h = ec->moveinfo.down.h + (ec->mouse.current.my - ec->moveinfo.down.my);
}
tw = ec->w;
th = ec->h;
if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
(ec->resize_mode == E_POINTER_RESIZE_L) ||
(ec->resize_mode == E_POINTER_RESIZE_BL))
x += (tw - w);
if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
(ec->resize_mode == E_POINTER_RESIZE_T) ||
(ec->resize_mode == E_POINTER_RESIZE_TR))
y += (th - h);
skiplist = eina_list_append(skiplist, ec);
e_resist_client_position(skiplist,
ec->x, ec->y, ec->w, ec->h,
x, y, w, h,
&new_x, &new_y, &new_w, &new_h);
eina_list_free(skiplist);
w = new_w;
h = new_h;
if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
{
if (ec->zone)
{
w = MIN(w, ec->zone->w);
h = MIN(h, ec->zone->h);
}
}
e_client_resize_limit(ec, &new_w, &new_h);
if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
(ec->resize_mode == E_POINTER_RESIZE_L) ||
(ec->resize_mode == E_POINTER_RESIZE_BL))
new_x += (w - new_w);
if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
(ec->resize_mode == E_POINTER_RESIZE_T) ||
(ec->resize_mode == E_POINTER_RESIZE_TR))
new_y += (h - new_h);
evas_object_geometry_set(ec->frame, new_x, new_y, new_w, new_h);
}
static int
_e_client_resize_end(E_Client *ec)
{
_e_client_action_input_win_del();
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_HORIZONTAL,
ec->maximized & E_MAXIMIZE_VERTICAL);
_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)
{
double timeout = e_config->border_keyboard.timeout;
E_FREE_FUNC(action_timer, ecore_timer_del);
if (!EINA_DBL_NONZERO(timeout)) timeout = 5.0;
action_timer = ecore_timer_loop_add(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;
switch (e_util_key_geometry_action_get(ev->key, &w, &h, dx, dy))
{
case E_UTIL_ACTION_DONE:
goto stop;
break;
case E_UTIL_ACTION_ABORT:
_e_client_action_restore_orig(action_client);
goto stop;
break;
case E_UTIL_ACTION_DO:
if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
{
if (action_client->zone)
{
w = MIN(w, action_client->zone->w);
h = MIN(h, action_client->zone->h);
}
}
e_client_resize_limit(action_client, &w, &h);
evas_object_resize(action_client->frame, w, h);
_e_client_action_resize_timeout_add();
break;
case E_UTIL_ACTION_NONE:
default:
break;
}
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;
E_CLIENT_REVERSE_FOREACH(cec)
{
/* If a border was specified which should be excluded from the list
* (because it will be closed shortly for example), skip */
if (e_client_util_ignored_get(cec) || (!e_client_util_desk_visible(cec, desk))) continue;
if (!evas_object_visible_get(cec->frame)) continue;
if ((exclude) && (cec == exclude)) continue;
if (!E_INSIDE(x, y, cec->x, cec->y, cec->w, cec->h))
continue;
/* If the layer is higher, the position of the window is higher
* (always on top vs always below) */
if (!ec || (cec->layer > ec->layer))
ec = cec;
}
return ec;
}
////////////////////////////////////////////////
static void
_e_client_zones_layout_calc(E_Client *ec, int *zx, int *zy, int *zw, int *zh)
{
int x, y, w, h;
E_Zone *zone_above, *zone_below, *zone_left, *zone_right;
if (!ec->zone) return;
x = ec->zone->x;
y = ec->zone->y;
w = ec->zone->w;
h = ec->zone->h;
if (eina_list_count(e_comp->zones) == 1)
{
if (zx) *zx = x;
if (zy) *zy = y;
if (zw) *zw = w;
if (zh) *zh = h;
return;
}
zone_left = e_comp_zone_xy_get((x - w + 5), y);
zone_right = e_comp_zone_xy_get((x + w + 5), y);
zone_above = e_comp_zone_xy_get(x, (y - h + 5));
zone_below = e_comp_zone_xy_get(x, (y + h + 5));
if (!(zone_above) && (y))
zone_above = e_comp_zone_xy_get(x, (h - 5));
if (!(zone_left) && (x))
zone_left = e_comp_zone_xy_get((x - 5), y);
if (zone_right)
w = zone_right->x + zone_right->w;
if (zone_left)
w = ec->zone->x + ec->zone->w;
if (zone_below)
h = zone_below->y + zone_below->h;
if (zone_above)
h = ec->zone->y + ec->zone->h;
if ((zone_left) && (zone_right))
w = ec->zone->w + zone_right->x;
if ((zone_above) && (zone_below))
h = ec->zone->h + zone_below->y;
if (x) x -= ec->zone->w;
if (y) y -= ec->zone->h;
if (zx) *zx = x > 0 ? x : 0;
if (zy) *zy = y > 0 ? y : 0;
if (zw) *zw = w;
if (zh) *zh = h;
}
static void
_e_client_stay_within_canvas(E_Client *ec, int x, int y, int *new_x, int *new_y)
{
int new_x_max, new_y_max;
int zw, zh;
Eina_Bool lw, lh;
if (!ec->zone)
{
if (new_x) *new_x = x;
if (new_y) *new_y = y;
return;
}
_e_client_zones_layout_calc(ec, NULL, NULL, &zw, &zh);
new_x_max = zw - ec->w;
new_y_max = zh - ec->h;
lw = ec->w > zw ? EINA_TRUE : EINA_FALSE;
lh = ec->h > zh ? EINA_TRUE : EINA_FALSE;
if (lw)
{
if (x <= new_x_max)
*new_x = new_x_max;
else if (x >= 0)
*new_x = 0;
}
else
{
if (x >= new_x_max)
*new_x = new_x_max;
else if (x <= 0)
*new_x = 0;
}
if (lh)
{
if (y <= new_y_max)
*new_y = new_y_max;
else if (y >= 0)
*new_y = 0;
}
else
{
if (y >= new_y_max)
*new_y = new_y_max;
else if (y <= 0)
*new_y = 0;
}
}
static void
_e_client_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 (ec->zone && E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h))
return;
/* find a new zone */
EINA_LIST_FOREACH(e_comp->zones, l, zone)
{
if (E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
zone->x, zone->y, zone->w, zone->h))
{
e_client_zone_set(ec, zone);
return;
}
}
}
////////////////////////////////////////////////
E_API Eina_List *
e_client_stack_list_prepare(E_Client *ec)
{
E_Client *ec2;
Eina_List *list = NULL;
for (ec2 = ec->stack.prev; ec2; ec2 = ec2->stack.prev)
{
ec2->stack.ignore++;
list = eina_list_prepend(list, ec2);
}
ec->stack.ignore++;
list = eina_list_append(list, ec);
for (ec2 = ec->stack.next; ec2; ec2 = ec2->stack.next)
{
ec2->stack.ignore++;
list = eina_list_append(list, ec2);
}
return list;
}
E_API void
e_client_stack_list_finish(Eina_List *list)
{
E_Client *ec;
EINA_LIST_FREE(list, ec) ec->stack.ignore--;
}
E_API E_Client *
e_client_stack_top_get(E_Client *ec)
{
E_Client *ec2;
for (ec2 = ec; ec2; ec2 = ec2->stack.next)
{
if (!ec2->stack.next) return ec2;
}
return ec;
}
E_API E_Client *
e_client_stack_bottom_get(E_Client *ec)
{
E_Client *ec2;
for (ec2 = ec; ec2; ec2 = ec2->stack.prev)
{
if (!ec2->stack.prev) return ec2;
}
return ec;
}
E_API E_Client *
e_client_stack_active_adjust(E_Client *ec)
{
E_Client *pec = ec;
if ((!ec->stack.prev) && (!ec->stack.next)) return ec;
ec = e_client_stack_top_get(ec);
for (; ec; ec = ec->stack.prev)
{
if (e_object_is_del(E_OBJECT(ec))) continue;
if (ec->stack.focus_skip) continue;
if (ec->iconic) continue;
if (ec->visible) break;
}
if (!ec) ec = pec;
return ec;
}
E_API Eina_Bool
e_client_stack_focused_get(E_Client *ec)
{
E_Client *ec2;
ec2 = e_client_stack_bottom_get(ec);
for (; ec2; ec2 = ec2->stack.next)
{
if (ec2->focused) return EINA_TRUE;
}
return EINA_FALSE;
}
E_API Eina_Bool
e_client_stack_iconified_get(E_Client *ec)
{
E_Client *ec2;
ec2 = e_client_stack_bottom_get(ec);
for (; ec2; ec2 = ec2->stack.next)
{
if (ec2->iconic) return EINA_TRUE;
}
return EINA_FALSE;
}
E_API Eina_Bool
e_client_stack_urgent_get(E_Client *ec)
{
E_Client *ec2;
ec2 = e_client_stack_bottom_get(ec);
for (; ec2; ec2 = ec2->stack.next)
{
if (ec2->urgent) return EINA_TRUE;
}
return EINA_FALSE;
}
////////////////////////////////////////////////
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
_e_client_mouse_action_end(ec);
if (action_client == ec) _e_client_action_finish();
if (!evas_object_pass_events_get(ec->frame))
e_pointer_type_pop(e_comp->pointer, ec, NULL);
if (!ec->hidden)
{
if (ec->focused)
_e_client_revert_focus(ec);
}
ec->want_focus = ec->take_focus = 0;
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;
Evas_Coord x, y;
ec->pre_res_change.valid = 0;
if (ec->internal_elm_win)
{
EC_CHANGED(ec);
ec->changes.pos = 1;
}
_e_client_event_simple(ec, E_EVENT_CLIENT_MOVE);
if (!ec->ignored) _e_client_zone_update(ec);
evas_object_geometry_get(ec->frame, &x, &y, NULL, NULL);
if (ec->stack.prev || ec->stack.next)
{
// do nothing - handled by idle enterer eval
}
else
{
if ((e_config->transient.move) && (ec->transients))
{
Eina_List *list = eina_list_clone(ec->transients);
E_Client *child;
EINA_LIST_FREE(list, child)
{
if (child->placed)
evas_object_move(child->frame,
child->x + x - ec->pre_cb.x,
child->y + y - ec->pre_cb.y);
}
}
}
if (ec->moving || (ecmove == ec))
_e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec);
e_remember_update(ec);
if (ec->fullscreen || (ec->maximized & E_MAXIMIZE_DIRECTION))
e_hints_window_size_set(ec);
ec->pre_cb.x = x; ec->pre_cb.y = y;
}
static void
_e_client_cb_evas_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
Evas_Coord x, y, w, h;
ec->pre_res_change.valid = 0;
_e_client_event_simple(ec, E_EVENT_CLIENT_RESIZE);
evas_object_geometry_get(ec->frame, &x, &y, &w, &h);
if (ec->stack.prev || ec->stack.next)
{
// do nothing - handled by idle enterer eval
}
else
{
if ((e_config->transient.resize) && (ec->transients))
{
Eina_List *list = eina_list_clone(ec->transients);
E_Client *child;
EINA_LIST_FREE(list, child)
{
Evas_Coord nx, ny, nw, nh;
if (!child->placed) continue;
if ((ec->pre_cb.w > 0) && (ec->pre_cb.h > 0))
{
nx = x + (((child->x - x) * w) / ec->pre_cb.w);
ny = y + (((child->y - y) * h) / ec->pre_cb.h);
nw = (child->w * w) / ec->pre_cb.w;
nh = (child->h * h) / ec->pre_cb.h;
nx += ((nw - child->w) / 2);
ny += ((nh - child->h) / 2);
evas_object_move(child->frame, nx, ny);
}
}
}
}
if (e_client_util_resizing_get(ec) || (ecresize == ec))
_e_client_hook_call(E_CLIENT_HOOK_RESIZE_UPDATE, ec);
e_remember_update(ec);
if (ec->fullscreen || (ec->maximized & E_MAXIMIZE_DIRECTION))
e_hints_window_size_set(ec);
ec->pre_cb.w = w; ec->pre_cb.h = h;
}
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_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 (ec->layer_block) return;
if (ec->stack.prev || ec->stack.next)
{
if (ec->stack.ignore == 0)
{
Eina_List *l, *list = e_client_stack_list_prepare(ec);
E_Client *child;
EINA_LIST_FOREACH(list, l, child)
{
if (child == ec) break;
evas_object_stack_below(child->frame, ec->frame);
}
EINA_LIST_REVERSE_FOREACH(list, l, child)
{
if (child == ec) break;
evas_object_stack_above(child->frame, ec->frame);
}
e_client_stack_list_finish(list);
}
}
else
{
if (e_config->transient.raise && ec->transients)
e_client_transients_restack(ec);
}
if (ec->unredirected_single) return;
e_remember_update(ec);
_e_client_event_simple(ec, E_EVENT_CLIENT_STACK);
}
////////////////////////////////////////////////
static void
_e_client_maximize_done(void *data, E_Efx_Map_Data *emd EINA_UNUSED, Evas_Object *obj)
{
E_Client *ec = data;
ec->maximize_override = 0;
ec->agent = NULL;
evas_object_del(obj);
}
static Eina_Bool
_e_client_maximize_run(E_Client *ec, int x, int y, int w, int h)
{
int pw, ph;
Eina_Bool disabled = EINA_FALSE;
if (e_pixmap_size_get(ec->pixmap, &pw, &ph))
{
e_comp_object_frame_wh_adjust(ec->frame, pw, ph, &pw, &ph);
disabled = (w == pw) && (h == ph);
}
if ((!disabled) && e_config->window_maximize_animate && (!ec->maximize_anims_disabled) &&
(!starting) && (!ec->changes.need_maximize))
{
evas_object_del(ec->agent);
ec->agent = e_comp_object_agent_add(ec->frame);
e_efx_resize(ec->agent, e_config->window_maximize_transition, E_EFX_POINT(x, y),
w, h, e_config->window_maximize_time, _e_client_maximize_done, ec);
return EINA_TRUE;
}
evas_object_geometry_set(ec->frame, x, y, w, h);
return EINA_FALSE;
}
////////////////////////////////////////////////
static void
_e_client_eval(E_Client *ec)
{
int rem_change = 0;
int send_event = 1;
unsigned int prop = 0;
int zx = 0, zy = 0, zw = 0, zh = 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)) && (ec->zone))
{
_e_client_event_simple(ec, E_EVENT_CLIENT_ADD);
e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
/* enforce wm size hints for initial sizing */
if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
{
ec->w = MIN(ec->w, ec->zone->w);
ec->h = MIN(ec->h, ec->zone->h);
}
e_client_resize_limit(ec, &ec->w, &ec->h);
if (ec->re_manage && e_comp_object_frame_exists(ec->frame))
{
int x = ec->x, y = ec->y;
if (ec->x) e_comp_object_frame_xy_adjust(ec->frame, ec->x, 0, &ec->x, NULL);
if (ec->y) e_comp_object_frame_xy_adjust(ec->frame, 0, ec->y, NULL, &ec->y);
if ((x != ec->x) || (y != ec->y)) ec->changes.pos = 1;
ec->placed = 1;
ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
}
if ((ec->stack.prev) && (!ec->dialog))
{
E_Client *ec2 = e_client_stack_bottom_get(ec);
ec->stack.ignore++;
evas_object_move(ec->frame, ec2->x, ec2->y);
evas_object_resize(ec->frame, ec2->w, ec2->h);
ec->stack.ignore--;
}
}
if (ec->new_client && (!ec->override))
e_hints_window_init(ec);
if ((!e_client_util_ignored_get(ec)) && ec->zone && ec->visible && (!ec->placed))
{
e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
if (ec->parent)
{
Eina_Bool centered = EINA_FALSE;
if (ec->parent->zone != e_zone_current_get())
{
e_client_zone_set(ec, ec->parent->zone);
e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
}
if (evas_object_visible_get(ec->parent->frame))
{
if ((!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh)) ||
(!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, ec->parent->x, ec->parent->y, ec->parent->w, ec->parent->h)))
{
int x, y;
e_comp_object_util_center_pos_get(ec->parent->frame, &x, &y);
if (E_CONTAINS(x, y, ec->w, ec->h, zx, zy, zw, zh))
{
ec->x = x, ec->y = y;
}
else
{
x = ec->parent->x;
y = ec->parent->y;
if (!E_CONTAINS(x, y, ec->w, ec->h, zx, zy, zw, zh))
{
e_comp_object_util_center_on(ec->frame,
ec->parent->frame);
centered = 1;
}
}
ec->changes.pos = 1;
}
}
else
{
e_comp_object_util_center_on(ec->frame,
ec->parent->frame);
centered = 1;
}
if (centered) //test for offscreen
{
if (!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh))
{
if (ec->x < zx)
ec->x = ec->parent->x;
if (ec->y < zy)
ec->y = ec->parent->y;
if (ec->x + ec->w > zx + zw)
ec->x = ec->parent->x + ec->parent->w - ec->w;
if (ec->y + ec->h > zy + zh)
ec->y = ec->parent->y + ec->parent->h - ec->h;
ec->changes.pos = 1;
}
}
ec->placed = 1;
ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
}
#if 0
else if ((ec->leader) && (ec->dialog))
{
/* TODO: Place in center of group */
}
#endif
else if (ec->dialog)
{
E_Client *trans_ec = NULL;
if (ec->icccm.transient_for)
trans_ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ec->icccm.transient_for);
if (trans_ec)
{
// if transient for a window and not placed, center on
// transient parent if found
ec->x = trans_ec->x + ((trans_ec->w - ec->w) / 2);
ec->y = trans_ec->y + ((trans_ec->h - ec->h) / 2);
}
else
{
ec->x = zx + ((zw - ec->w) / 2);
ec->y = zy + ((zh - ec->h) / 2);
}
ec->changes.pos = 1;
ec->placed = 1;
ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
}
if (!ec->placed)
{
Eina_List *skiplist = NULL;
int new_x, new_y, t = 0;
E_Client *trans_ec = NULL;
if (zw > ec->w)
new_x = zx + (rand() % (zw - ec->w));
else
new_x = zx;
if (zh > ec->h)
new_y = zy + (rand() % (zh - ec->h));
else
new_y = zy;
e_comp_object_frame_geometry_get(ec->frame, NULL, NULL, &t, NULL);
if (ec->icccm.transient_for)
trans_ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ec->icccm.transient_for);
if (trans_ec)
{
// if transient for a window and not placed, center on
// transient parent if found
new_x = trans_ec->x + ((trans_ec->w - ec->w) / 2);
new_y = trans_ec->y + ((trans_ec->h - ec->h) / 2);
}
else if ((e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART) || (e_config->window_placement_policy == E_WINDOW_PLACEMENT_ANTIGADGET))
{
skiplist = eina_list_append(skiplist, ec);
if (ec->transients)
skiplist = eina_list_merge(skiplist, eina_list_clone(ec->transients));
if (ec->desk)
e_place_desk_region_smart(ec->desk, skiplist,
ec->x, ec->y, ec->w, ec->h,
&new_x, &new_y);
else
e_place_zone_region_smart(ec->zone, skiplist,
ec->x, ec->y, ec->w, ec->h,
&new_x, &new_y);
eina_list_free(skiplist);
}
else if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL)
{
e_place_zone_manual(ec->zone, ec->w, t, &new_x, &new_y);
}
else
{
e_place_zone_cursor(ec->zone, ec->x, ec->y, ec->w, ec->h,
t, &new_x, &new_y);
}
ec->x = new_x;
ec->y = new_y;
ec->changes.pos = 1;
ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
}
else if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh))
{
/* If an ec is placed out of bound, fix it! */
ec->x = zx + ((zw - ec->w) / 2);
ec->y = zy + ((zh - ec->h) / 2);
ec->changes.pos = 1;
}
/* Recreate state */
if ((ec->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;
}
/* if the explicit geometry request asks for the app to be
* in another zone - well move it there */
{
E_Zone *zone = NULL;
int x, y;
x = MAX(ec->x, 0);
y = MAX(ec->y, 0);
if ((!ec->re_manage) && ((ec->x != x) || (ec->y != y)))
zone = e_comp_zone_xy_get(x, y);
if (!zone)
{
zone = e_comp_zone_xy_get(ec->x + (ec->w / 2), ec->y + (ec->h / 2));
if (zone)
{
E_Zone *z2 = e_comp_zone_xy_get(ec->x, ec->y);
if (z2 && (z2 != zone))
{
size_t psz = 0;
E_Zone *zf = z2;
Eina_List *l;
EINA_LIST_FOREACH(e_comp->zones, l, z2)
{
int w, h;
x = ec->x, y = ec->y, w = ec->w, h = ec->h;
E_RECTS_CLIP_TO_RECT(x, y, w, h, z2->x, z2->y, z2->w, z2->h);
if (w * h == z2->w * z2->h)
{
/* client fully covering zone */
zf = z2;
break;
}
if ((unsigned)(w * h) > psz)
{
psz = w * h;
zf = z2;
}
}
zone = zf;
}
}
}
if (!zone)
zone = e_comp_zone_xy_get(ec->x, ec->y);
if (!zone)
zone = e_comp_zone_xy_get(ec->x + ec->w - 1, ec->y);
if (!zone)
zone = e_comp_zone_xy_get(ec->x + ec->w - 1, ec->y + ec->h - 1);
if (!zone)
zone = e_comp_zone_xy_get(ec->x, ec->y + ec->h - 1);
if ((zone) && (zone != ec->zone))
e_client_zone_set(ec, zone);
}
}
if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT, ec)) 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);
rem_change = 1;
prop |= E_CLIENT_PROPERTY_SIZE;
}
if (ec->changes.pos)
{
Eina_Bool placed = ec->placed;
ec->changes.pos = 0;
evas_object_move(ec->frame, ec->x, ec->y);
if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL)
ec->placed = placed;
rem_change = 1;
prop |= E_CLIENT_PROPERTY_POS;
}
if (ec->changes.need_rescale)
{
e_client_rescale(ec);
ec->changes.need_rescale = 0;
}
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) && (!ec->iconic))
{
int x, y;
ecore_evas_pointer_xy_get(e_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->next_mouse_action_ignore)
ec->cur_mouse_action = NULL;
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 (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);
}
if (evas_object_visible_get(ec->frame))
ec->changes.visible = 0;
}
else if ((ec->changes.visible) && (ec->new_client))
{
ec->changes.visible = 0;
if (!ec->iconic)
_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->steam.steam_game_id)
{
Efreet_Desktop *d;
Eina_List *desks = efreet_util_desktop_name_glob_list("*");
EINA_LIST_FREE(desks, d)
{
if (!d->exec) continue;
if (!strncmp(d->exec, "steam ", 6))
{
const char *st = strstr(d->exec, "steam://rungameid/");
if (st)
{
st += strlen("steam://rungameid/");
unsigned int id = atoi(st);
if (id == ec->steam.steam_game_id)
ec->desktop = d;
}
}
}
}
}
if (!ec->desktop)
{
E_Exec_Instance *inst;
inst = e_exec_startup_id_pid_instance_find(ec->netwm.startup_id,
ec->netwm.pid);
if (inst && inst->clients)
{
E_Client *ec2 = eina_list_data_get(inst->clients);
if (ec2->netwm.pid == ec->netwm.pid)
ec->desktop = inst->desktop;
}
else if (inst)
ec->desktop = inst->desktop;
if (ec->desktop) efreet_desktop_ref(ec->desktop);
}
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 && ec->icccm.command.argv && (ec->icccm.command.argc > 0))
{