compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
#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))
|
2013-12-29 14:04:26 -08:00
|
|
|
{
|
|
|
|
evas_object_focus_set(ec->parent->frame, 1);
|
|
|
|
if (e_config->raise_on_revert_focus)
|
|
|
|
evas_object_raise(ec->parent->frame);
|
|
|
|
}
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
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);
|
2013-12-29 14:04:26 -08:00
|
|
|
/* no autoraise/revert here because it's probably annoying */
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2014-01-15 08:00:45 -08:00
|
|
|
if ((!ec->iconic) && (!ec->override))
|
|
|
|
e_hints_window_hidden_set(ec);
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
|
|
|
|
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);
|
2014-01-15 13:59:43 -08:00
|
|
|
if (ec->moving || (ecmove == ec))
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
_e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec);
|
2014-01-15 19:52:14 -08:00
|
|
|
e_remember_update(ec);
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2014-01-15 13:59:43 -08:00
|
|
|
if (e_client_resizing_get(ec) || (ecresize == ec))
|
2013-10-14 10:52:49 -07:00
|
|
|
_e_client_hook_call(E_CLIENT_HOOK_RESIZE_UPDATE, ec);
|
2014-01-15 19:52:14 -08:00
|
|
|
e_remember_update(ec);
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2013-10-14 10:52:49 -07:00
|
|
|
if (ec->layer_block) return;
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
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->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 */
|
2014-01-15 08:00:45 -08:00
|
|
|
if (!ec->override)
|
|
|
|
e_hints_window_init(ec);
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
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)
|
|
|
|
{
|
2013-08-30 05:20:55 -07:00
|
|
|
if ((ec->icccm.name) || (ec->icccm.class))
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2013-08-30 08:17:34 -07:00
|
|
|
eina_hash_add(clients_hash, &ec->pixmap, ec);
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
|
|
|
|
_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;
|
2014-01-15 20:11:12 -08:00
|
|
|
int x, y, w, h;
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
const char *drag_types[] = { "enlightenment/border" };
|
|
|
|
|
|
|
|
e_object_ref(E_OBJECT(ec));
|
2014-01-15 20:11:12 -08:00
|
|
|
e_comp_object_frame_icon_geometry_get(ec->frame, &x, &y, &w, &h);
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
client_drag = e_drag_new(ec->zone->comp,
|
|
|
|
output->x, output->y,
|
|
|
|
drag_types, 1, ec, -1,
|
|
|
|
NULL,
|
|
|
|
_e_client_cb_drag_finished);
|
2014-01-15 20:11:12 -08:00
|
|
|
e_drag_resize(client_drag, w, h);
|
compositor rewrite / charlie-foxtrot situation
huge fustercluck commit because there wasn't really a way to separate out the changes. better to just rip it all out at once.
* compositor and window management completely rewritten. this was the goal for E19, but it pretty much required everything existing to be scrapped since it wasn't optimized, streamlined, or sensible. now instead of having the compositor strapped to the window manager like an outboard motor, it's housed more like an automobile engine.
** various comp structs have been merged into other places (eg. E_Comp_Zone is now just part of E_Zone where applicable), leading to a large deduplication of attributes
** awful E_Comp_Win is totally dead, having been replaced with e_comp_object smart objects which work just like normal canvas objects
** protocol-specific window management and compositor functionality is now kept exclusively in backend files
** e_pixmap api provides generic client finding and rendering api
** screen/xinerama screens are now provided directly by compositor on startup and re-set on change
** e_comp_render_update finally replaced with eina_tiler
** wayland compositor no longer creates X windows
** compositor e_layout removed entirely
* e_container is gone. this was made unnecessary in E18, but I kept it to avoid having too much code churn in one release. its sole purpose was to catch some events and handle window stacking, both of which are now just done by the compositor infra
* e_manager is just for screensaver and keybind stuff now, possibly remove later?
* e_border is gone along with a lot of its api. e_client has replaced it, and e_client has been rewritten completely; some parts may be similar, but the design now relies upon having a functional compositor
** window configuration/focus functions are all removed. all windows are now managed solely with evas_object_X functions on the "frame" member of a client, just as any other canvas object can be managed.
*** do NOT set interceptors on a client's comp_object. seriously.
* startup order rewritten: compositor now starts much earlier, other things just use attrs and members of the compositor
* ecore_x_pointer_xy_get usage replaced with ecore_evas_pointer_xy_get
* e_popup is totally gone, existing usage replaced by e_comp_object_util_add where applicable, otherwise just placed normally on the canvas
* deskmirror is (more) broken for now
* illume is totally fucked
* Ecore_X_Window replaced with Ecore_Window in most cases
* edge binding XWindows replaced with regular canvas objects
* some E_Win functionality has changed such that delete callbacks are now correctly called in ALL cases. various dialogs have been updated to not crash as a result
comp files and descriptions:
e_comp.c - overall compositor functions, rendering/update loop, shape cutting
e_comp_x.c - X window management and compositor functionality
e_comp_wl.c - Wayland surface management and compositor functionality
e_comp_canvas.c - general compositor canvas functions and utilities
e_comp_object.c - E_Client->frame member for managing clients as Evas_Objects, utility functions for adding objects to the compositor rendering systems
additional authors: ivan.briano@intel.com
feature: new compositor
removal: e_border, e_container, e_popup
2014-01-14 17:19:12 -08:00
|
|
|
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;
|
|
|
|
}
|