enlightenment/src/bin/e_comp_x.c

4902 lines
164 KiB
C

#include "e.h"
#include <Ecore_X.h>
#define GRAV_SET(ec, grav) \
ecore_x_window_gravity_set(e_client_util_pwin_get(ec), grav); \
if (ec->comp_data->lock_win) ecore_x_window_gravity_set(ec->comp_data->lock_win, grav); \
ecore_x_window_gravity_set(e_client_util_win_get(ec), grav);
#define E_COMP_X_PIXMAP_CHECK if (e_pixmap_type_get(ec->pixmap) != E_PIXMAP_TYPE_X) return
/* maybe make configurable?
* not sure why anyone would want to change it...
*/
#define MOVE_COUNTER_LIMIT 50
EINTERN void _e_main_cb_x_fatal(void *data EINA_UNUSED);
typedef struct _Frame_Extents Frame_Extents;
struct _Frame_Extents
{
int l, r, t, b;
};
struct _E_Comp_Data
{
Eina_Bool restack : 1;
};
static unsigned int focus_time = 0;
static Eina_List *handlers = NULL;
static Eina_Hash *clients_win_hash = NULL;
static Eina_Hash *damages_hash = NULL;
static Eina_Hash *frame_extents = NULL;
static Eina_Hash *alarm_hash = NULL;
static Ecore_Idle_Enterer *_e_comp_x_post_client_idler = NULL;
static Eina_List *post_clients = NULL;
static int _e_comp_x_mapping_change_disabled = 0;
static Ecore_X_Randr_Screen_Size screen_size = { -1, -1 };
static int screen_size_index = -1;
static Ecore_Timer *screensaver_idle_timer = NULL;
static Eina_Bool screensaver_dimmed = EINA_FALSE;
static inline Ecore_X_Window
_e_comp_x_client_window_get(const E_Client *ec)
{
if (ec->comp_data->reparented)
return e_client_util_pwin_get(ec);
return e_client_util_win_get(ec);
}
static void
_e_comp_x_client_damage_add(E_Client *ec)
{
Ecore_X_Window win;
if (ec->comp_data->damage) return;
win = _e_comp_x_client_window_get(ec);
ec->comp_data->damage = ecore_x_damage_new(win, ECORE_X_DAMAGE_REPORT_DELTA_RECTANGLES);
eina_hash_add(damages_hash, &ec->comp_data->damage, ec);
}
static void
_e_comp_x_focus_check(E_Comp *comp)
{
E_Client *focused;
if (stopping) return;
focused = e_client_focused_get();
/* if there is no new focused or it is a non-X client,
* focus comp canvas on focus-out */
if ((!focused) || (e_pixmap_type_get(focused->pixmap) != E_PIXMAP_TYPE_X))
e_grabinput_focus(comp->ee_win, E_FOCUS_METHOD_PASSIVE);
}
static void
_e_comp_x_client_frame_update(E_Client *ec, int l, int r, int t, int b)
{
ecore_x_netwm_frame_size_set(e_client_util_win_get(ec), l, r, t, b);
ecore_x_e_frame_size_set(e_client_util_win_get(ec), l, r, t, b);
ec->comp_data->frame_update = 0;
}
static void
_e_comp_x_client_event_free(void *d EINA_UNUSED, void *e)
{
E_Event_Client *ev = e;
e_object_unref(E_OBJECT(ev->ec));
free(ev);
}
static void
_e_comp_x_print_win(Ecore_X_Window win)
{
int x, y, w, h;
Eina_Bool vis;
ecore_x_window_geometry_get(win, &x, &y, &w, &h);
vis = ecore_x_window_visible_get(win);
fprintf(stderr, "%s 0x%x: %d,%d @ %dx%d\n", vis ? "VIS" : "HID", win, x, y, w, h);
}
static void
_e_comp_x_focus_setup(E_Client *ec)
{
if (ec->comp_data->button_grabbed) return;
if (!((e_client_focus_policy_click(ec)) ||
(e_config->always_click_to_raise) ||
(e_config->always_click_to_focus))) return;
ecore_x_window_button_grab(e_client_util_pwin_get(ec), 1,
ECORE_X_EVENT_MASK_MOUSE_DOWN |
ECORE_X_EVENT_MASK_MOUSE_UP |
ECORE_X_EVENT_MASK_MOUSE_MOVE, 0, 1);
ecore_x_window_button_grab(e_client_util_pwin_get(ec), 2,
ECORE_X_EVENT_MASK_MOUSE_DOWN |
ECORE_X_EVENT_MASK_MOUSE_UP |
ECORE_X_EVENT_MASK_MOUSE_MOVE, 0, 1);
ecore_x_window_button_grab(e_client_util_pwin_get(ec), 3,
ECORE_X_EVENT_MASK_MOUSE_DOWN |
ECORE_X_EVENT_MASK_MOUSE_UP |
ECORE_X_EVENT_MASK_MOUSE_MOVE, 0, 1);
ec->comp_data->button_grabbed = 1;
}
static void
_e_comp_x_focus_setdown(E_Client *ec)
{
Ecore_X_Window win = e_client_util_pwin_get(ec);
if (!ec->comp_data->button_grabbed) return;
e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, win);
e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, win);
ecore_x_window_button_ungrab(win, 1, 0, 1);
ecore_x_window_button_ungrab(win, 2, 0, 1);
ecore_x_window_button_ungrab(win, 3, 0, 1);
e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, win);
e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, win);
ec->comp_data->button_grabbed = 0;
}
static Eina_Bool
_e_comp_x_client_new_helper(E_Client *ec)
{
Ecore_X_Window win = e_client_util_win_get(ec);
int at_num = 0, i;
Ecore_X_Atom *atoms;
if (!ecore_x_window_attributes_get(win, &ec->comp_data->initial_attributes))
{
//CRI("OUCH! FIX THIS!");
e_object_del(E_OBJECT(ec));
return EINA_FALSE;
}
if (ec->re_manage && (!ec->comp_data->initial_attributes.visible))
{
/* ain't gonna be no hidden clients on my watch! */
e_object_del(E_OBJECT(ec));
return EINA_FALSE;
}
ec->depth = ec->comp_data->initial_attributes.depth;
ec->override = ec->comp_data->initial_attributes.override;
ec->input_only = ec->comp_data->initial_attributes.input_only;
ec->border_size = ec->comp_data->initial_attributes.border;
ec->icccm.accepts_focus = (!ec->override) && (!ec->input_only);
//INF("NEW CLIENT: %d,%d -> %d,%d", ec->x, ec->y, ec->comp_data->initial_attributes.x, ec->comp_data->initial_attributes.y);
ec->x = ec->client.x = ec->comp_data->initial_attributes.x;
ec->y = ec->client.y = ec->comp_data->initial_attributes.y;
if (ec->override && ((ec->x == -77) && (ec->y == -777)))
{
/* this is the ecore-x private window :/ */
e_comp_ignore_win_add(E_PIXMAP_TYPE_X, win);
e_object_del(E_OBJECT(ec));
return EINA_FALSE;
}
if ((!e_client_util_ignored_get(ec)) && (!ec->internal) && (!ec->internal_ecore_evas))
{
ec->comp_data->need_reparent = 1;
EC_CHANGED(ec);
ec->take_focus = 1;
}
ec->w = ec->client.w = ec->comp_data->initial_attributes.w;
ec->h = ec->client.h = ec->comp_data->initial_attributes.h;
ec->changes.size = 1;
e_pixmap_visual_cmap_set(ec->pixmap, ec->comp_data->initial_attributes.visual, ec->comp_data->initial_attributes.colormap);
if (ec->override && (!(ec->comp_data->initial_attributes.event_mask.mine & ECORE_X_EVENT_MASK_WINDOW_PROPERTY)))
ecore_x_event_mask_set(win, ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
atoms = ecore_x_window_prop_list(win, &at_num);
ec->icccm.fetch.command = 1;
if (atoms)
{
Eina_Bool video_parent = EINA_FALSE;
Eina_Bool video_position = EINA_FALSE;
/* icccm */
for (i = 0; i < at_num; i++)
{
if (atoms[i] == ECORE_X_ATOM_WM_NAME)
ec->icccm.fetch.title = 1;
else if (atoms[i] == ECORE_X_ATOM_WM_CLASS)
ec->icccm.fetch.name_class = 1;
else if (atoms[i] == ECORE_X_ATOM_WM_ICON_NAME)
ec->icccm.fetch.icon_name = 1;
else if (atoms[i] == ECORE_X_ATOM_WM_CLIENT_MACHINE)
ec->icccm.fetch.machine = 1;
else if (atoms[i] == ECORE_X_ATOM_WM_HINTS)
ec->icccm.fetch.hints = 1;
else if (atoms[i] == ECORE_X_ATOM_WM_NORMAL_HINTS)
ec->icccm.fetch.size_pos_hints = 1;
else if (atoms[i] == ECORE_X_ATOM_WM_PROTOCOLS)
ec->icccm.fetch.protocol = 1;
else if (atoms[i] == ECORE_X_ATOM_MOTIF_WM_HINTS)
ec->mwm.fetch.hints = 1;
else if (atoms[i] == ECORE_X_ATOM_WM_TRANSIENT_FOR)
{
ec->icccm.fetch.transient_for = 1;
ec->netwm.fetch.type = 1;
}
else if (atoms[i] == ECORE_X_ATOM_WM_CLIENT_LEADER)
ec->icccm.fetch.client_leader = 1;
else if (atoms[i] == ECORE_X_ATOM_WM_WINDOW_ROLE)
ec->icccm.fetch.window_role = 1;
else if (atoms[i] == ECORE_X_ATOM_WM_STATE)
ec->icccm.fetch.state = 1;
}
/* netwm, loop again, netwm will ignore some icccm, so we
* have to be sure that netwm is checked after */
for (i = 0; i < at_num; i++)
{
if (atoms[i] == ECORE_X_ATOM_NET_WM_NAME)
{
/* Ignore icccm */
ec->icccm.fetch.title = 0;
ec->netwm.fetch.name = 1;
}
else if (atoms[i] == ECORE_X_ATOM_NET_WM_ICON_NAME)
{
/* Ignore icccm */
ec->icccm.fetch.icon_name = 0;
ec->netwm.fetch.icon_name = 1;
}
else if (atoms[i] == ECORE_X_ATOM_NET_WM_ICON)
{
ec->netwm.fetch.icon = 1;
}
else if (atoms[i] == ECORE_X_ATOM_NET_WM_USER_TIME)
{
ec->netwm.fetch.user_time = 1;
}
else if (atoms[i] == ECORE_X_ATOM_NET_WM_STRUT)
{
DBG("ECORE_X_ATOM_NET_WM_STRUT");
ec->netwm.fetch.strut = 1;
}
else if (atoms[i] == ECORE_X_ATOM_NET_WM_STRUT_PARTIAL)
{
DBG("ECORE_X_ATOM_NET_WM_STRUT_PARTIAL");
ec->netwm.fetch.strut = 1;
}
else if (atoms[i] == ECORE_X_ATOM_NET_WM_WINDOW_TYPE)
{
/* Ignore mwm
ec->mwm.fetch.hints = 0;
*/
ec->netwm.fetch.type = 1;
}
else if (atoms[i] == ECORE_X_ATOM_NET_WM_STATE)
{
ec->netwm.fetch.state = 1;
}
else if (atoms[i] == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
ec->netwm.fetch.opacity = 1;
}
/* other misc atoms */
for (i = 0; i < at_num; i++)
{
/* loop to check for own atoms */
if (atoms[i] == E_ATOM_WINDOW_STATE)
{
ec->e.fetch.state = 1;
}
/* loop to check for qtopia atoms */
if (atoms[i] == ATM__QTOPIA_SOFT_MENU)
ec->qtopia.fetch.soft_menu = 1;
else if (atoms[i] == ATM__QTOPIA_SOFT_MENUS)
ec->qtopia.fetch.soft_menus = 1;
/* loop to check for vkbd atoms */
else if (atoms[i] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE)
ec->vkbd.fetch.state = 1;
else if (atoms[i] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD)
ec->vkbd.fetch.vkbd = 1;
/* loop to check for illume atoms */
else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_CONFORMANT)
ec->comp_data->illume.conformant.fetch.conformant = 1;
else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE)
ec->comp_data->illume.quickpanel.fetch.state = 1;
else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL)
ec->comp_data->illume.quickpanel.fetch.quickpanel = 1;
else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR)
ec->comp_data->illume.quickpanel.fetch.priority.major = 1;
else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR)
ec->comp_data->illume.quickpanel.fetch.priority.minor = 1;
else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE)
ec->comp_data->illume.quickpanel.fetch.zone = 1;
else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED)
ec->comp_data->illume.drag.fetch.locked = 1;
else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_DRAG)
ec->comp_data->illume.drag.fetch.drag = 1;
else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE)
ec->comp_data->illume.win_state.fetch.state = 1;
else if (atoms[i] == ECORE_X_ATOM_E_VIDEO_PARENT)
video_parent = EINA_TRUE;
else if (atoms[i] == ECORE_X_ATOM_E_VIDEO_POSITION)
video_position = EINA_TRUE;
/* loop to check for window profile list atom */
else if (atoms[i] == ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED)
ec->e.fetch.profile = 1;
}
if (video_position && video_parent)
{
ec->e.state.video = 1;
ec->e.fetch.video_parent = 1;
ec->e.fetch.video_position = 1;
fprintf(stderr, "We found a video window \\o/ %x\n", win);
}
free(atoms);
}
return EINA_TRUE;
}
static E_Client *
_e_comp_x_client_find_by_damage(Ecore_X_Damage damage)
{
return eina_hash_find(damages_hash, &damage);
}
static E_Client *
_e_comp_x_client_find_by_window(Ecore_X_Window win)
{
E_Client *ec;
ec = eina_hash_find(clients_win_hash, &win);
if (ec && e_object_is_del(E_OBJECT(ec))) ec = NULL;
return ec;
}
/*
static E_Client *
_e_comp_x_client_find_all_by_window(Ecore_X_Window win)
{
return eina_hash_find(clients_win_hash, &win);
}
*/
static void
_e_comp_x_add_fail_job(void *d EINA_UNUSED)
{
e_util_dialog_internal
(_("Compositor Warning"),
_("Your display driver does not support OpenGL, GLSL<br>"
"shaders or no OpenGL engines were compiled or installed<br>"
"for Evas or Ecore-Evas. Falling back to software engine.<br>"
"<br>"
"You will need an OpenGL 2.0 (or OpenGL ES 2.0) capable<br>"
"GPU to use OpenGL with compositing."));
}
static void
_pri_adj(int pid, int set, int adj, Eina_Bool use_adj, Eina_Bool adj_children, Eina_Bool do_children)
{
int newpri = set;
if (use_adj) newpri = getpriority(PRIO_PROCESS, pid) + adj;
setpriority(PRIO_PROCESS, pid, newpri);
// shouldnt need to do this as default ionice class is "none" (0), and
// this inherits io priority FROM nice level
// ioprio_set(IOPRIO_WHO_PROCESS, pid,
// IOPRIO_PRIO_VALUE(2, 5));
if (do_children)
{
Eina_List *files;
char *file, buf[PATH_MAX];
FILE *f;
int pid2, ppid;
// yes - this is /proc specific... so this may not work on some
// os's - works on linux. too bad for others.
files = ecore_file_ls("/proc");
EINA_LIST_FREE(files, file)
{
if (isdigit(file[0]))
{
snprintf(buf, sizeof(buf), "/proc/%s/stat", file);
f = fopen(buf, "r");
if (f)
{
pid2 = -1;
ppid = -1;
if (fscanf(f, "%i %*s %*s %i %*s", &pid2, &ppid) == 2)
{
fclose(f);
if (ppid == pid)
{
if (adj_children)
_pri_adj(pid2, set, adj, EINA_TRUE,
adj_children, do_children);
else
_pri_adj(pid2, set, adj, use_adj,
adj_children, do_children);
}
}
else fclose(f);
}
}
free(file);
}
}
}
static E_Client *
_e_comp_x_client_find_by_alarm(Ecore_X_Sync_Alarm al)
{
return eina_hash_find(alarm_hash, &al);
}
static void
_e_comp_x_client_move_resize_send(E_Client *ec)
{
if (ec->internal_ecore_evas)
ecore_evas_managed_move(ec->internal_ecore_evas, ec->client.x - ec->x, ec->client.y - ec->y);
ecore_x_icccm_move_resize_send(e_client_util_win_get(ec), ec->client.x, ec->client.y, ec->client.w, ec->client.h);
}
static Eina_Bool
_e_comp_x_post_client_idler_cb(void *d EINA_UNUSED)
{
E_Client *ec;
const Eina_List *l;
E_Comp *c;
//INF("POST IDLER");
EINA_LIST_FREE(post_clients, ec)
{
Ecore_X_Window win, twin;
if (e_object_is_del(E_OBJECT(ec)) || (!ec->comp_data)) continue;
win = _e_comp_x_client_window_get(ec);
if (ec->post_move)
{
E_Client *tmp;
EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
{
twin = _e_comp_x_client_window_get(tmp);
ecore_x_window_move(twin,
ec->client.x +
tmp->e.state.video_position.x,
ec->client.y +
tmp->e.state.video_position.y);
}
}
if (ec->e.state.video)
{
E_Client *parent;
parent = ec->e.state.video_parent_client;
twin = _e_comp_x_client_window_get(parent);
ecore_x_window_move(twin,
parent->client.x +
ec->e.state.video_position.x,
parent->client.y +
ec->e.state.video_position.y);
}
else if (ec->shading)
{
// do nothing
}
else if ((ec->post_move) && (ec->post_resize))
{
//INF("X MVRSZ");
ecore_x_window_move_resize(win,
ec->client.x,
ec->client.y,
ec->client.w,
ec->client.h);
if (ec->comp_data->reparented)
ecore_x_window_resize(e_client_util_win_get(ec),
ec->client.w,
ec->client.h);
}
else if (ec->post_move)
{
//INF("X MV");
ecore_x_window_move(win, ec->client.x, ec->client.y);
}
else if (ec->post_resize)
{
//INF("X RSZ: %dx%d (REAL: %dx%d)", ec->client.w, ec->client.h, ec->w, ec->h);
ecore_x_window_resize(win,
ec->client.w, ec->client.h);
if (ec->comp_data->reparented)
ecore_x_window_resize(e_client_util_win_get(ec),
ec->client.w, ec->client.h);
}
if ((!ec->shading) && (!ec->shaded))
{
if (ec->post_resize)
{
if (ec->netwm.sync.request)
{
//INF("NETWM SYNC: %p", ec);
ec->netwm.sync.wait++;
ecore_x_netwm_sync_request_send(e_client_util_win_get(ec),
ec->netwm.sync.serial++);
}
}
if (ec->post_move || ec->post_resize)
_e_comp_x_client_move_resize_send(ec);
}
if (ec->e.state.video)
{
fprintf(stderr, "VIDEO %p: [%i, %i] [%i, %i]\n",
ec,
ec->e.state.video_parent_client->client.x +
ec->e.state.video_position.x,
ec->e.state.video_parent_client->client.y +
ec->e.state.video_position.y,
ec->w, ec->h);
}
if (ec->netwm.opacity_changed)
{
unsigned int opacity;
int op;
evas_object_color_get(ec->frame, NULL, NULL, NULL, &op);
ec->netwm.opacity = op;
opacity = (op << 24);
ecore_x_window_prop_card32_set(e_client_util_win_get(ec), ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, &opacity, 1);
/* flag gets unset in property cb to avoid fetching opacity after we just set it */
}
ec->post_move = 0;
ec->post_resize = 0;
}
EINA_LIST_FOREACH(e_comp_list(), l, c)
if (c->comp_data->restack && (!c->new_clients))
{
e_hints_client_stacking_set();
c->comp_data->restack = 0;
}
_e_comp_x_post_client_idler = NULL;
return EINA_FALSE;
}
static void
_e_comp_x_post_client_idler_add(E_Client *ec)
{
if (!_e_comp_x_post_client_idler)
_e_comp_x_post_client_idler = ecore_idle_enterer_add(_e_comp_x_post_client_idler_cb, NULL);
if (!ec) CRI("ACK!");
//INF("POST IDLE: %p", ec);
if (!eina_list_data_find(post_clients, ec))
post_clients = eina_list_append(post_clients, ec);
}
static void
_e_comp_x_client_stack(E_Client *ec)
{
E_Client *ec2;
Ecore_X_Window_Stack_Mode mode = ECORE_X_WINDOW_STACK_BELOW;
Ecore_X_Window win = 0;
Eina_List *l;
if (ec->override && (!ec->internal)) return; //can't restack these
ecore_x_window_shadow_tree_flush();
/* try stacking below */
ec2 = e_client_above_get(ec);
if (ec2)
{
if (ec2->layer == ec->layer)
win = _e_comp_x_client_window_get(ec2);
}
/* try stacking above */
if (!win)
{
ec2 = e_client_below_get(ec);
if (ec2 && (ec2->layer == ec->layer))
{
win = _e_comp_x_client_window_get(ec2);
mode = ECORE_X_WINDOW_STACK_ABOVE;
}
}
/* just layer stack */
if (!win)
{
win = ec->comp->layers[e_comp_canvas_layer_map(ec->layer)].win;
mode = ECORE_X_WINDOW_STACK_BELOW;
}
ecore_x_window_configure(_e_comp_x_client_window_get(ec),
ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
0, 0, 0, 0, 0, win, mode);
_e_comp_x_post_client_idler_add(ec);
ec->comp->comp_data->restack = 1;
EINA_LIST_FOREACH(ec->e.state.video_child, l, ec2)
evas_object_stack_below(ec2->frame, ec->frame);
}
static E_Client *
_e_comp_x_client_new(E_Comp *c, Ecore_X_Window win, Eina_Bool first)
{
E_Pixmap *cp;
E_Client *ec;
cp = e_pixmap_new(E_PIXMAP_TYPE_X, win);
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);
ec = e_client_new(c, cp, first, 0);
return ec;
}
static void
_e_comp_x_client_pri_raise(E_Client *ec)
{
if (ec->netwm.pid <= 0) return;
if (ec->netwm.pid == getpid()) return;
_pri_adj(ec->netwm.pid,
e_config->priority - 1, -1, EINA_FALSE,
// EINA_TRUE, EINA_TRUE);
EINA_TRUE, EINA_FALSE);
// printf("WIN: pid %i, title %s (HI!!!!!!!!!!!!!!!!!!)\n",
// ec->netwm.pid, e_client_name_get(ec));
}
static void
_e_comp_x_client_pri_norm(E_Client *ec)
{
if (ec->netwm.pid <= 0) return;
if (ec->netwm.pid == getpid()) return;
_pri_adj(ec->netwm.pid,
e_config->priority, 1, EINA_FALSE,
// EINA_TRUE, EINA_TRUE);
EINA_TRUE, EINA_FALSE);
// printf("WIN: pid %i, title %s (NORMAL)\n",
// ec->netwm.pid, e_client_name_get(ec));
}
static void
_e_comp_x_client_shape_input_rectangle_set(E_Client *ec)
{
Ecore_X_Window win = e_client_util_pwin_get(ec);
if (!ec->comp_data->reparented) return;
if (ec->shaped_input)
ecore_x_composite_window_events_disable(win);
else
{
if (ec->visible && (!ec->comp_hidden))
ecore_x_composite_window_events_enable(win);
else
ecore_x_composite_window_events_disable(win);
}
}
static void
_e_comp_x_evas_color_set_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
int a;
evas_object_color_get(obj, NULL, NULL, NULL, &a);
if (a == ec->netwm.opacity) return;
ec->netwm.opacity_changed = 1;
_e_comp_x_post_client_idler_add(ec);
}
static void
_e_comp_x_evas_ping_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
ecore_x_netwm_ping_send(e_client_util_win_get(ec));
}
static void
_e_comp_x_evas_kill_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
ecore_x_kill(e_client_util_win_get(ec));
}
static void
_e_comp_x_evas_delete_request_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
if (ec->netwm.ping)
e_client_ping(ec);
ecore_x_window_delete_request_send(e_client_util_win_get(ec));
}
static void
_e_comp_x_evas_comp_hidden_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *tmp, *ec = data;
Eina_List *l;
Ecore_X_Window win;
if (ec->comp_data->need_reparent) return;
win = _e_comp_x_client_window_get(ec);
EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
{
Ecore_X_Window cwin;
cwin = _e_comp_x_client_window_get(tmp);
if (ec->comp_hidden)
ecore_x_window_hide(cwin);
else
ecore_x_window_show(cwin);
}
if (ec->comp_hidden)
ecore_x_composite_window_events_disable(win);
else
ecore_x_composite_window_events_enable(win);
ecore_x_window_ignore_set(win, ec->comp_hidden);
}
static void
_e_comp_x_evas_shade_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
Eina_List *l;
E_Client *tmp;
EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
ecore_x_window_hide(e_client_util_pwin_get(tmp));
ecore_x_window_shadow_tree_flush();
}
static void
_e_comp_x_evas_frame_recalc_cb(void *data, Evas_Object *obj, void *event_info)
{
E_Client *ec = data;
E_Comp_Object_Frame *fr = event_info;
if (evas_object_visible_get(obj))
_e_comp_x_client_frame_update(ec, fr->l, fr->r, fr->t, fr->b);
else
ec->comp_data->frame_update = 1;
}
static void
_e_comp_x_evas_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
if (ec->comp_data->moving)
{
if (ec->comp_data->move_counter++ < MOVE_COUNTER_LIMIT) return;
ec->comp_data->move_counter = 0;
}
ecore_x_window_shadow_tree_flush();
ec->post_move = 1;
_e_comp_x_post_client_idler_add(ec);
}
static void
_e_comp_x_evas_resize_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
if (ec->shading || ec->shaded) return;
if (!e_pixmap_size_changed(ec->pixmap, ec->client.w, ec->client.h)) return;
ecore_x_window_shadow_tree_flush();
if (ec->e.state.video)
{
if (ec->e.state.video_position.updated)
{
ecore_x_window_move(e_client_util_pwin_get(ec),
ec->e.state.video_parent_client->client.x +
ec->e.state.video_position.x,
ec->e.state.video_parent_client->client.y +
ec->e.state.video_position.y);
ec->e.state.video_position.updated = 0;
}
}
else if (ec->changes.pos)
{
E_Client *tmp;
Eina_List *l;
EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
ecore_x_window_move(e_client_util_pwin_get(tmp),
ec->client.x + tmp->e.state.video_position.x,
ec->client.y + tmp->e.state.video_position.y);
}
ec->post_resize = 1;
e_pixmap_dirty(ec->pixmap);
e_comp_object_render_update_del(ec->frame);
_e_comp_x_post_client_idler_add(ec);
}
static void
_e_comp_x_evas_hide_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data, *tmp;
unsigned int visible = 0;
Eina_List *l;
if (!ec->comp_data) return; // already deleted, happens with internal wins
ecore_x_window_shadow_tree_flush();
if (!ec->iconic)
{
ecore_x_window_prop_card32_set(e_client_util_win_get(ec), E_ATOM_MAPPED, &visible, 1);
e_hints_window_hidden_set(ec);
}
EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
evas_object_hide(tmp->frame);
if (e_comp_config_get()->send_flush)
ecore_x_e_comp_flush_send(e_client_util_pwin_get(ec));
if (e_comp_config_get()->send_dump)
ecore_x_e_comp_dump_send(e_client_util_pwin_get(ec));
}
static void
_e_comp_x_evas_show_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data, *tmp;
unsigned int visible = 1;
Ecore_X_Window win;
Eina_List *l;
if (!ec->comp_data) return;
win = e_client_util_win_get(ec);
ecore_x_window_shadow_tree_flush();
if (!ec->comp_data->need_reparent)
ecore_x_window_show(win);
e_hints_window_visible_set(ec);
ecore_x_window_prop_card32_set(win, E_ATOM_MAPPED, &visible, 1);
ecore_x_window_prop_card32_set(win, E_ATOM_MANAGED, &visible, 1);
if (ec->comp_data->frame_update)
{
int ll, r, t, b;
e_comp_object_frame_geometry_get(obj, &ll, &r, &t, &b);
_e_comp_x_client_frame_update(ec, ll, r, t, b);
}
EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
{
evas_object_show(tmp->frame);
ecore_x_window_show(e_client_util_pwin_get(tmp));
}
}
static void
_e_comp_x_evas_stack_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
if (evas_object_data_get(obj, "client_restack"))
_e_comp_x_client_stack(data);
}
static void
_e_comp_x_evas_unfullscreen_zoom_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
if ((screen_size.width != -1) && (screen_size.height != -1))
{
ecore_x_randr_screen_primary_output_size_set(ec->comp->man->root,
screen_size_index);
screen_size.width = -1;
screen_size.height = -1;
}
}
static void
_e_comp_x_evas_fullscreen_zoom_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Client *ec = data;
Ecore_X_Randr_Screen_Size_MM *sizes;
int num_sizes, i, best_size_index = 0;
ecore_x_randr_screen_primary_output_current_size_get(ec->comp->man->root,
&screen_size.width,
&screen_size.height,
NULL, NULL, NULL);
sizes = ecore_x_randr_screen_primary_output_sizes_get(ec->comp->man->root,
&num_sizes);
if (sizes)
{
Ecore_X_Randr_Screen_Size best_size = { -1, -1 };
int best_dist = INT_MAX, dist;
for (i = 0; i < num_sizes; i++)
{
if ((sizes[i].width > ec->w) && (sizes[i].height > ec->h))
{
dist = (sizes[i].width * sizes[i].height) - (ec->w * ec->h);
if (dist < best_dist)
{
best_size.width = sizes[i].width;
best_size.height = sizes[i].height;
best_dist = dist;
best_size_index = i;
}
}
}
if (((best_size.width != -1) && (best_size.height != -1)) &&
((best_size.width != screen_size.width) ||
(best_size.height != screen_size.height)))
{
if (ecore_x_randr_screen_primary_output_size_set(ec->comp->man->root,
best_size_index))
screen_size_index = best_size_index;
evas_object_geometry_set(ec->frame, 0, 0, best_size.width, best_size.height);
}
else
{
screen_size.width = -1;
screen_size.height = -1;
evas_object_geometry_set(ec->frame, 0, 0, ec->zone->w, ec->zone->h);
}
free(sizes);
}
else
evas_object_geometry_set(ec->frame, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h);
}
static Eina_Bool
_e_comp_x_destroy(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Destroy *ev)
{
E_Client *ec;
//INF("X DESTROY: %u", ev->win);
e_comp_ignore_win_del(E_PIXMAP_TYPE_X, ev->win);
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
if (ec->comp_data)
{
if (ec->comp_data->reparented)
e_client_comp_hidden_set(ec, 1);
evas_object_pass_events_set(ec->frame, 1);
evas_object_hide(ec->frame);
ec->comp_data->deleted = 1;
e_object_del(E_OBJECT(ec));
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_resize_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Resize_Request *ev)
{
E_Client *ec;
int w, h;
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec)
{
if (!e_comp_find_by_window(ev->win)) ecore_x_window_resize(ev->win, ev->w, ev->h);
return ECORE_CALLBACK_PASS_ON;
}
w = ev->w, h = ev->h;
if (ec->zone && (e_config->geometry_auto_resize_limit == 1))
{
int zx, zy, zw, zh;
e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
if (w > zw)
w = zw;
if (h > zh)
h = zh;
}
if ((w != ec->w) || (h != ec->h))
evas_object_resize(ec->frame, w, h);
return ECORE_CALLBACK_RENEW;
}
static void
_e_comp_x_client_evas_init(E_Client *ec)
{
ec->comp_data->evas_init = 1;
evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESTACK, _e_comp_x_evas_stack_cb, ec);
evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW, _e_comp_x_evas_show_cb, ec);
evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE, _e_comp_x_evas_hide_cb, ec);
if (!ec->override)
{
evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE, _e_comp_x_evas_move_cb, ec);
evas_object_smart_callback_add(ec->frame, "client_resize", _e_comp_x_evas_resize_cb, ec);
}
evas_object_smart_callback_add(ec->frame, "frame_recalc_done", _e_comp_x_evas_frame_recalc_cb, ec);
evas_object_smart_callback_add(ec->frame, "shade_done", _e_comp_x_evas_shade_cb, ec);
evas_object_smart_callback_add(ec->frame, "comp_hidden", _e_comp_x_evas_comp_hidden_cb, ec);
evas_object_smart_callback_add(ec->frame, "delete_request", _e_comp_x_evas_delete_request_cb, ec);
evas_object_smart_callback_add(ec->frame, "kill_request", _e_comp_x_evas_kill_cb, ec);
evas_object_smart_callback_add(ec->frame, "ping", _e_comp_x_evas_ping_cb, ec);
evas_object_smart_callback_add(ec->frame, "color_set", _e_comp_x_evas_color_set_cb, ec);
evas_object_smart_callback_add(ec->frame, "fullscreen_zoom", _e_comp_x_evas_fullscreen_zoom_cb, ec);
evas_object_smart_callback_add(ec->frame, "unfullscreen_zoom", _e_comp_x_evas_unfullscreen_zoom_cb, ec);
/* force apply this since we haven't set up our smart cb previously */
_e_comp_x_evas_comp_hidden_cb(ec, NULL, NULL);
}
static Eina_Bool
_e_comp_x_show_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Show_Request *ev)
{
E_Client *ec;
E_Comp *c;
//INF("X SHOW REQ: %u", ev->win);
ec = _e_comp_x_client_find_by_window(ev->win);
c = e_comp_find_by_window(ev->parent);
if (e_comp_ignore_win_find(ev->win) ||
(ec && (ec->ignored || ec->override)) ||
(!c) || (ev->parent != c->man->root))
{
ecore_x_window_show(ev->win);
return ECORE_CALLBACK_RENEW;
}
if (!ec)
ec = _e_comp_x_client_new(c, ev->win, 0);
if (!ec)
{
ecore_x_window_show(ev->win);
return ECORE_CALLBACK_RENEW;
}
if ((!ec->comp_data->reparented) && (!e_client_util_ignored_get(ec)))
{
if (!ec->override)
ec->comp_data->need_reparent = 1;
ec->visible = 1;
EC_CHANGED(ec);
return ECORE_CALLBACK_RENEW;
}
if (ec->iconic)
{
if (!ec->lock_client_iconify)
e_client_uniconify(ec);
}
else
{
/* FIXME: make client "urgent" for a bit - it wants attention */
/* e_client_show(ec); */
if (!ec->lock_client_stacking)
evas_object_raise(ec->frame);
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_show(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Show *ev)
{
E_Client *ec;
E_Comp *c;
//INF("X SHOW: %u", ev->win);
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec)
{
if (e_comp_ignore_win_find(ev->win)) return ECORE_CALLBACK_RENEW;
c = e_comp_find_by_window(ev->event_win);
if (!c) return ECORE_CALLBACK_RENEW;
if (ev->event_win != c->man->root) return ECORE_CALLBACK_RENEW;
if ((c->win == ev->win) || (c->ee_win == ev->win) ||
(c->man->root == ev->win) || (c->cm_selection == ev->win)) return ECORE_CALLBACK_RENEW;
/* some window which we haven't made a client for yet but need to */
ec = _e_comp_x_client_new(c, ev->win, 0);
if (!ec) return ECORE_CALLBACK_RENEW;
}
else if (e_object_is_del(E_OBJECT(ec)) || ec->already_unparented)
return ECORE_CALLBACK_RENEW;
if ((!ec->override) && (!ec->re_manage) && (!ec->comp_data->first_map) &&
(!ec->comp_data->reparented) && (!ec->comp_data->need_reparent))
{
/* this is most likely an internal window */
ec->comp_data->need_reparent = 1;
ec->visible = 1;
if (ec->internal_ecore_evas)
ec->take_focus = 1;
EC_CHANGED(ec);
}
else if (ec->override)
{
ec->changes.visible = ec->visible = 1;
EC_CHANGED(ec);
if (!ec->comp_data->first_map)
_e_comp_x_client_evas_init(ec);
}
if (!ec->input_only)
_e_comp_x_client_damage_add(ec);
if (!ec->comp_data->need_reparent)
{
e_pixmap_usable_set(ec->pixmap, 1);
if (ec->hidden || ec->iconic)
{
evas_object_hide(ec->frame);
e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
}
else
evas_object_show(ec->frame);
ec->comp_data->first_map = 1;
if (ec->internal_ecore_evas)
{
_e_comp_x_post_client_idler_add(ec);
ec->post_move = 1;
ec->post_resize = 1;
ec->comp->comp_data->restack = 1;
}
}
if (ec->internal || (!ec->override))
_e_comp_x_client_stack(ec);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_hide(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Hide *ev)
{
E_Client *ec;
Eina_Bool hid = EINA_FALSE;
//INF("X HIDE: %u", ev->win);
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_PASS_ON;
if (!ec->visible)
{
//INF("IGNORED");
return ECORE_CALLBACK_PASS_ON;
}
if (ev->win != ev->event_win)
{
if ((!ec->override) && (!ev->send_event)) return ECORE_CALLBACK_PASS_ON;
}
if (ec->ignore_first_unmap > 0)
{
ec->ignore_first_unmap--;
return ECORE_CALLBACK_PASS_ON;
}
/* Don't delete hidden or iconified windows */
if ((ec->iconic) || (ec->await_hide_event > 0))
{
if (ec->await_hide_event > 0)
{
ec->await_hide_event--;
}
else
{
/* Only hide the border if it is visible */
hid = EINA_TRUE;
evas_object_hide(ec->frame);
}
}
else
{
hid = EINA_TRUE;
evas_object_hide(ec->frame);
if (!ec->internal)
e_object_del(E_OBJECT(ec));
}
if (hid)
_e_comp_x_focus_check(ec->comp);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_reparent(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Reparent *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->win);
if ((!ec) || (ev->win == e_client_util_pwin_get(ec))) return ECORE_CALLBACK_PASS_ON;
DBG("== repar [%u] to [%u]", ev->win, ev->parent);
if (ev->parent != e_client_util_pwin_get(ec))
{
e_pixmap_parent_window_set(ec->pixmap, ev->parent);
if (!e_object_is_del(E_OBJECT(ec)))
e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_configure(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Configure *ev)
{
E_Client *ec;
E_Comp *c;
Eina_Bool move, resize;
c = e_comp_find_by_window(ev->win);
if (c)
{
e_manager_resize(c->man, ev->w, ev->h);
return ECORE_CALLBACK_RENEW;
}
ec = _e_comp_x_client_find_by_window(ev->win);
if ((!ec) || (!ec->override)) return ECORE_CALLBACK_PASS_ON;
//INF("configure %p: %d,%d %dx%d", ec, ev->x, ev->y, ev->w, ev->h);
if (ev->abovewin == 0)
{
if (e_client_below_get(ec))
evas_object_lower(ec->frame);
}
else
{
E_Client *ec2 = _e_comp_x_client_find_by_window(ev->abovewin);
if (ec2)
{
/* client(ec) wants to be above a layer client(ec2) */
if (e_client_util_is_stacking(ec2)) //is it a stacking placeholder window?
{
E_Client *ec3;
ec3 = e_client_above_get(ec2);
/* stack under next client(ec3) */
if (ec3)
{
evas_object_layer_set(ec->frame, ec3->layer);
if (!e_client_util_is_stacking(ec3))
evas_object_stack_below(ec->frame, ec3->frame);
}
else //force override to obey our stacking
evas_object_layer_set(ec->frame, ec2->layer);
}
else
{
evas_object_layer_set(ec->frame, ec2->layer);
evas_object_stack_above(ec->frame, ec2->frame);
}
}
}
move = (ec->client.x != ev->x) || (ec->client.y != ev->y);
resize = (ec->client.w != ev->w) || (ec->client.h != ev->h);
EINA_RECTANGLE_SET(&ec->client, ev->x, ev->y, ev->w, ev->h);
if (move)
evas_object_move(ec->frame, ev->x, ev->y);
if (resize)
{
e_pixmap_dirty(ec->pixmap);
evas_object_resize(ec->frame, ev->w, ev->h);
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_configure_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Configure_Request *ev)
{
E_Client *ec;
Eina_Bool move = EINA_FALSE, resize = EINA_FALSE;
int ox, oy, ow, oh;
int x, y, w, h;
if (e_comp_find_by_window(ev->win)) return ECORE_CALLBACK_RENEW;
ec = _e_comp_x_client_find_by_window(ev->win);
/* pass through requests for windows we haven't/won't reparent yet */
if (ec && (!ec->comp_data->need_reparent) && (!ec->comp_data->reparented))
{
ec->comp_data->initial_attributes.x = ev->x;
ec->comp_data->initial_attributes.y = ev->y;
ec->w = ec->client.w = ec->comp_data->initial_attributes.w = ev->w;
ec->h = ec->client.h = ec->comp_data->initial_attributes.h = ev->h;
ec->border_size = ev->border;
ec->changes.size = 1;
ec = NULL;
}
if (!ec)
{
ecore_x_window_configure(ev->win, ev->value_mask,
ev->x, ev->y, ev->w, ev->h, ev->border,
ev->abovewin, ev->detail);
return ECORE_CALLBACK_PASS_ON;
}
x = ox = ec->x;
y = oy = ec->y;
w = ow = ec->client.w;
h = oh = ec->client.h;
if ((ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X) ||
(ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y))
{
int zx, zy, zw, zh, t, l;
e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
e_comp_object_frame_geometry_get(ec->frame, &l, NULL, &t, NULL);
if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X)
{
if (e_config->screen_limits == E_SCREEN_LIMITS_WITHIN)
x = E_CLAMP(ev->x, zx, zx + zw - ec->w);
else
x = ev->x;
}
if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y)
{
if (e_config->screen_limits == E_SCREEN_LIMITS_WITHIN)
y = E_CLAMP(ev->y, zy, zy + zh - ec->h);
else
y = ev->y;
}
}
if ((ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W) ||
(ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H))
{
if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W)
w = ev->w;
if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H)
h = ev->h;
}
e_comp_object_frame_wh_adjust(ec->frame, w, h, &w, &h);
move = (x != ec->x) || (y != ec->y);
resize = (w != ec->w) || (h != ec->h);
if (move && (!ec->lock_client_location))
{
if ((ec->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE)
{
ec->saved.x = x;
ec->saved.y = y;
}
else
{
if (ec->zone)
{
/* client is completely outside the zone, policy does not allow */
if (((!E_INTERSECTS(x, y, ec->w, ec->h, ec->zone->x, ec->zone->y, ec->zone->w - 5, ec->zone->h - 5)) &&
(e_config->screen_limits != E_SCREEN_LIMITS_COMPLETELY)) ||
/* client is partly outside the zone, policy does not allow */
(((!E_INSIDE(x, y, ec->zone->x, ec->zone->y, ec->zone->w - 5, ec->zone->h - 5)) &&
(!E_INSIDE(x + ec->w, y, ec->zone->x, ec->zone->y, ec->zone->w - 5, ec->zone->h - 5)) &&
(!E_INSIDE(x, y + ec->h, ec->zone->x, ec->zone->y, ec->zone->w - 5, ec->zone->h - 5)) &&
(!E_INSIDE(x + ec->w, y + ec->h, ec->zone->x, ec->zone->y, ec->zone->w - 5, ec->zone->h - 5))) &&
(e_config->screen_limits == E_SCREEN_LIMITS_WITHIN))
)
e_comp_object_util_center(ec->frame);
else
evas_object_move(ec->frame, x, y);
}
else
{
evas_object_move(ec->frame, x, y);
}
}
}
if (resize && (!ec->lock_client_size))
{
if ((ec->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE)
{
ec->saved.w = w;
ec->saved.h = h;
}
else
{
evas_object_resize(ec->frame, w, h);
}
}
if (!ec->lock_client_stacking)
{
if ((ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE) &&
(ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING))
{
E_Client *oec;
if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE)
{
oec = _e_comp_x_client_find_by_window(ev->abovewin);
if (oec)
{
evas_object_stack_above(ec->frame, oec->frame);
}
else
{
ecore_x_window_configure(e_client_util_pwin_get(ec),
ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
0, 0, 0, 0, 0,
ev->abovewin, ECORE_X_WINDOW_STACK_ABOVE);
}
}
else if (ev->detail == ECORE_X_WINDOW_STACK_BELOW)
{
oec = _e_comp_x_client_find_by_window(ev->abovewin);
if (oec)
{
evas_object_stack_below(ec->frame, oec->frame);
}
else
{
ecore_x_window_configure(e_client_util_pwin_get(ec),
ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
0, 0, 0, 0, 0,
ev->abovewin, ECORE_X_WINDOW_STACK_BELOW);
}
}
else if (ev->detail == ECORE_X_WINDOW_STACK_TOP_IF)
{
/* FIXME: do */
}
else if (ev->detail == ECORE_X_WINDOW_STACK_BOTTOM_IF)
{
/* FIXME: do */
}
else if (ev->detail == ECORE_X_WINDOW_STACK_OPPOSITE)
{
/* FIXME: do */
}
}
else if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE)
{
if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE)
{
evas_object_raise(ec->frame);
}
else if (ev->detail == ECORE_X_WINDOW_STACK_BELOW)
{
evas_object_lower(ec->frame);
}
else if (ev->detail == ECORE_X_WINDOW_STACK_TOP_IF)
{
/* FIXME: do */
}
else if (ev->detail == ECORE_X_WINDOW_STACK_BOTTOM_IF)
{
/* FIXME: do */
}
else if (ev->detail == ECORE_X_WINDOW_STACK_OPPOSITE)
{
/* FIXME: do */
}
}
}
/* FIXME: need to send synthetic stacking event too as well as move/resize */
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_stack_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Stack_Request *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->win);
if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE)
evas_object_raise(ec->frame);
else if (ev->detail == ECORE_X_WINDOW_STACK_BELOW)
evas_object_lower(ec->frame);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_stack(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Stack *ev)
{
E_Client *ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_PASS_ON;
if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE) evas_object_raise(ec->frame);
else evas_object_lower(ec->frame);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_property(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Property *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
if (ev->atom == ECORE_X_ATOM_WM_NAME)
{
if ((!ec->netwm.name) &&
(!ec->netwm.fetch.name))
{
ec->icccm.fetch.title = 1;
EC_CHANGED(ec);
}
}
else if (ev->atom == ECORE_X_ATOM_NET_WM_NAME)
{
ec->netwm.fetch.name = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_WM_CLASS)
{
ec->icccm.fetch.name_class = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_WM_ICON_NAME)
{
if ((!ec->netwm.icon_name) &&
(!ec->netwm.fetch.icon_name))
{
ec->icccm.fetch.icon_name = 1;
EC_CHANGED(ec);
}
}
else if (ev->atom == ECORE_X_ATOM_NET_WM_ICON_NAME)
{
ec->netwm.fetch.icon_name = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_WM_CLIENT_MACHINE)
{
ec->icccm.fetch.machine = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_WM_PROTOCOLS)
{
ec->icccm.fetch.protocol = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_WM_HINTS)
{
ec->icccm.fetch.hints = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_WM_NORMAL_HINTS)
{
if (ec->comp_data->internal_props_set)
ec->comp_data->internal_props_set--;
else
{
ec->icccm.fetch.size_pos_hints = 1;
EC_CHANGED(ec);
}
}
else if (ev->atom == ECORE_X_ATOM_MOTIF_WM_HINTS)
{
/*
if ((ec->netwm.type == E_WINDOW_TYPE_UNKNOWN) &&
(!ec->netwm.fetch.type))
{
*/
ec->mwm.fetch.hints = 1;
EC_CHANGED(ec);
/*
}
*/
}
else if (ev->atom == ECORE_X_ATOM_WM_TRANSIENT_FOR)
{
ec->icccm.fetch.transient_for = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_WM_CLIENT_LEADER)
{
ec->icccm.fetch.client_leader = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_WM_WINDOW_ROLE)
{
ec->icccm.fetch.window_role = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_NET_WM_ICON)
{
ec->netwm.fetch.icon = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ATM__QTOPIA_SOFT_MENU)
{
ec->qtopia.fetch.soft_menu = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ATM__QTOPIA_SOFT_MENUS)
{
ec->qtopia.fetch.soft_menus = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE)
{
ec->vkbd.fetch.state = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD)
{
ec->vkbd.fetch.vkbd = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_ILLUME_CONFORMANT)
{
ec->comp_data->illume.conformant.fetch.conformant = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE)
{
ec->comp_data->illume.quickpanel.fetch.state = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL)
{
ec->comp_data->illume.quickpanel.fetch.quickpanel = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR)
{
ec->comp_data->illume.quickpanel.fetch.priority.major = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR)
{
ec->comp_data->illume.quickpanel.fetch.priority.minor = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE)
{
ec->comp_data->illume.quickpanel.fetch.zone = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED)
{
ec->comp_data->illume.drag.fetch.locked = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_ILLUME_DRAG)
{
ec->comp_data->illume.drag.fetch.drag = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE)
{
ec->comp_data->illume.win_state.fetch.state = 1;
EC_CHANGED(ec);
}
/*
else if (ev->atom == ECORE_X_ATOM_NET_WM_USER_TIME)
{
ec->netwm.fetch.user_time = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_NET_WM_STRUT)
{
ec->netwm.fetch.strut = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_NET_WM_STRUT_PARTIAL)
{
ec->netwm.fetch.strut = 1;
EC_CHANGED(ec);
}
*/
else if (ev->atom == ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER)
{
//printf("ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER\n");
}
else if (ev->atom == ECORE_X_ATOM_E_VIDEO_POSITION)
{
ec->e.fetch.video_position = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_VIDEO_PARENT)
{
ec->e.fetch.video_parent = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_NET_WM_STATE)
{
ec->netwm.fetch.state = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
{
if (ec->netwm.opacity_changed)
ec->netwm.opacity_changed = 0;
else
{
ec->netwm.fetch.opacity = 1;
EC_CHANGED(ec);
}
}
else if (ev->atom == ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED)
{
ec->e.fetch.profile = 1;
EC_CHANGED(ec);
}
else if (ev->atom == ECORE_X_ATOM_E_WINDOW_PROFILE_AVAILABLE_LIST)
{
ec->e.fetch.profile = 1;
EC_CHANGED(ec);
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_message(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Client_Message *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
if (ev->message_type == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
{
ec->netwm.fetch.opacity = 1;
EC_CHANGED(ec);
}
else if (ev->message_type == ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE)
{
if (ec->e.state.profile.use)
{
char *profile;
profile = ecore_x_atom_name_get(ev->data.l[1]);
ecore_x_e_window_profile_change_request_send(e_client_util_pwin_get(ec), profile);
ec->e.state.profile.wait_for_done = 1;
free(profile);
}
}
else if (ev->message_type == ECORE_X_ATOM_NET_ACTIVE_WINDOW)
{
#if 0 /* notes */
if (e->data.l[0] == 0 /* 0 == old, 1 == client, 2 == pager */)
{
}
timestamp = e->data.l[1];
requestor_id e->data.l[2];
#endif
switch (e_config->window_activehint_policy)
{
case 0: break;
case 1:
e_comp_object_signal_emit(ec->frame, "e,state,urgent", "e");
ec->icccm.urgent = 1;
EC_CHANGED(ec);
break;
default:
if (e_client_action_get())
{
/* be helpful and ignore activates during window actions, but still set urgent */
e_comp_object_signal_emit(ec->frame, "e,state,urgent", "e");
ec->icccm.urgent = 1;
EC_CHANGED(ec);
break;
}
if ((!starting) && (!ec->focused))
e_client_activate(ec, EINA_TRUE);
else
evas_object_raise(ec->frame);
}
}
else if (ev->message_type == ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE_DONE)
{
if ((ec->e.state.profile.use) &&
(ec->e.state.profile.wait_for_done))
{
E_Desk *desk = NULL;
char *profile;
profile = ecore_x_atom_name_get(ev->data.l[1]);
if (profile)
eina_stringshare_replace(&ec->e.state.profile.name, profile);
ec->e.state.profile.wait_for_done = 0;
if (ec->desk && e_util_strcmp(ec->desk->window_profile, profile))
{
desk = e_comp_desk_window_profile_get(ec->comp, profile);
if (desk)
e_client_desk_set(ec, desk);
}
free(profile);
}
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_state_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_State_Request *ev)
{
int i;
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
for (i = 0; i < 2; i++)
e_hints_window_state_update(ec, ev->state[i], ev->action);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_mapping_change(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Mapping_Change *ev EINA_UNUSED)
{
const Eina_List *l, *ll;
E_Client *ec;
E_Comp *c;
if (_e_comp_x_mapping_change_disabled) return ECORE_CALLBACK_RENEW;
e_managers_keys_ungrab();
EINA_LIST_FOREACH(e_comp_list(), l, c)
EINA_LIST_FOREACH(c->clients, ll, ec)
{
Ecore_X_Window win;
if (e_pixmap_type_get(ec->pixmap) != E_PIXMAP_TYPE_X) continue;
win = e_client_util_pwin_get(ec);
if ((!ec->comp_data->first_map) || (!ec->comp_data->reparented)) continue;
_e_comp_x_focus_setdown(ec);
e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, win);
e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, win);
e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, win);
e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, win);
_e_comp_x_focus_setup(ec);
}
e_managers_keys_grab();
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Mouse_In *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
if (ec->comp_data->deleted) return ECORE_CALLBACK_RENEW;
if (ec->input_object) return ECORE_CALLBACK_RENEW;
e_client_mouse_in(ec, e_comp_canvas_x_root_adjust(ec->comp, ev->root.x), e_comp_canvas_x_root_adjust(ec->comp, ev->root.y));
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Mouse_In *ev)
{
E_Client *ec;
if ((ev->mode == ECORE_X_EVENT_MODE_UNGRAB) &&
(ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR))
return ECORE_CALLBACK_PASS_ON;
if (ev->mode == ECORE_X_EVENT_MODE_GRAB)
return ECORE_CALLBACK_PASS_ON;
if ((ev->mode == ECORE_X_EVENT_MODE_NORMAL) &&
(ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR))
return ECORE_CALLBACK_PASS_ON;
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
if (ec->comp_data->deleted) return ECORE_CALLBACK_RENEW;
if (ec->input_object) return ECORE_CALLBACK_RENEW;
e_client_mouse_out(ec, e_comp_canvas_x_root_adjust(ec->comp, ev->root.x), e_comp_canvas_x_root_adjust(ec->comp, ev->root.y));
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_mouse_wheel(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Wheel *ev)
{
E_Client *ec;
E_Binding_Event_Wheel ev2;
//if (action_input_win)
//ec = action_border;
//else
{
ec = _e_comp_x_client_find_by_window(ev->window);
if (!ec) return ECORE_CALLBACK_RENEW;
}
if (ec->comp_data->deleted) return ECORE_CALLBACK_RENEW;
e_bindings_ecore_event_mouse_wheel_convert(ev, &ev2);
e_client_mouse_wheel(ec, (Evas_Point*)&ev->root, &ev2);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_mouse_up(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev)
{
E_Client *ec;
E_Binding_Event_Mouse_Button ev2;
//if (action_input_win)
//ec = action_border;
//else
{
ec = _e_comp_x_client_find_by_window(ev->window);
if (!ec)
{
if (e_client_comp_grabbed_get())
ec = e_client_action_get();
if (!ec) return ECORE_CALLBACK_RENEW;
}
}
if (ec->comp_data->deleted) return ECORE_CALLBACK_RENEW;
e_bindings_ecore_event_mouse_button_convert(ev, &ev2);
e_client_mouse_up(ec, ev->buttons, (Evas_Point*)&ev->root, &ev2);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_mouse_down(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev)
{
E_Client *ec;
E_Binding_Event_Mouse_Button ev2;
if (e_client_action_get()) return ECORE_CALLBACK_RENEW; //block extra mouse buttons during action
//if (action_input_win)
//ec = action_border;
//else
{
ec = _e_comp_x_client_find_by_window(ev->window);
if (!ec) return ECORE_CALLBACK_RENEW;
}
if (ec->comp_data->deleted) return ECORE_CALLBACK_RENEW;
e_bindings_ecore_event_mouse_button_convert(ev, &ev2);
e_client_mouse_down(ec, ev->buttons, (Evas_Point*)&ev->root, &ev2);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_mouse_move(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev)
{
E_Client *ec;
ec = e_client_action_get();
if (!ec) return ECORE_CALLBACK_RENEW;
E_COMP_X_PIXMAP_CHECK ECORE_CALLBACK_RENEW;
if (ec->comp_data->deleted) return ECORE_CALLBACK_RENEW;
if (e_client_resizing_get(ec) &&
ec->netwm.sync.request &&
ec->comp_data->alarm
)
{
if ((ecore_loop_time_get() - ec->netwm.sync.send_time) > 0.5)
{
if (ec->pending_resize)
{
ec->changes.pos = 1;
ec->changes.size = 1;
EC_CHANGED(ec);
_e_comp_x_client_move_resize_send(ec);
}
E_FREE_LIST(ec->pending_resize, free);
ec->netwm.sync.wait = 0;
/* sync.wait is incremented when resize_handle sends
* sync-request and decremented by sync-alarm cb. so
* we resize here either on initial resize, timeout or
* when no new resize-request was added by sync-alarm cb.
*/
}
}
e_client_mouse_move(ec, (Evas_Point*)&ev->root);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_focus_out(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Focus_Out *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
_e_comp_x_client_pri_norm(ec);
if (ev->mode == ECORE_X_EVENT_MODE_NORMAL)
{
if (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
return ECORE_CALLBACK_PASS_ON;
else if (ev->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR)
return ECORE_CALLBACK_PASS_ON;
else if (ev->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL)
return ECORE_CALLBACK_PASS_ON;
}
else if (ev->mode == ECORE_X_EVENT_MODE_GRAB)
{
if (ev->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR)
return ECORE_CALLBACK_PASS_ON;
else if (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
return ECORE_CALLBACK_PASS_ON;
else if (ev->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL)
return ECORE_CALLBACK_PASS_ON;
else if (ev->detail == ECORE_X_EVENT_DETAIL_ANCESTOR)
return ECORE_CALLBACK_PASS_ON;
else if (ev->detail == ECORE_X_EVENT_DETAIL_VIRTUAL)
return ECORE_CALLBACK_PASS_ON;
}
else if (ev->mode == ECORE_X_EVENT_MODE_UNGRAB)
{
/* for firefox/thunderbird (xul) menu walking */
/* NB: why did i disable this before? */
if (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
return ECORE_CALLBACK_PASS_ON;
else if (ev->detail == ECORE_X_EVENT_DETAIL_POINTER)
return ECORE_CALLBACK_PASS_ON;
}
else if (ev->mode == ECORE_X_EVENT_MODE_WHILE_GRABBED)
{
if (ev->detail == ECORE_X_EVENT_DETAIL_ANCESTOR)
return ECORE_CALLBACK_PASS_ON;
else if (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
return ECORE_CALLBACK_PASS_ON;
}
evas_object_focus_set(ec->frame, 0);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_client_property(void *d EINA_UNUSED, int t EINA_UNUSED, E_Event_Client_Property *ev)
{
if ((ev->property & E_CLIENT_PROPERTY_ICON) && ev->ec->desktop)
ecore_x_window_prop_string_set(e_client_util_win_get(ev->ec), E_ATOM_DESKTOP_FILE,
ev->ec->desktop->orig_path);
return ECORE_CALLBACK_RENEW;
}
static void
_e_comp_x_client_zone_geometry_set(E_Client *ec)
{
unsigned int zgeom[4];
zgeom[0] = ec->zone->x;
zgeom[1] = ec->zone->y;
zgeom[2] = ec->zone->w;
zgeom[3] = ec->zone->h;
ecore_x_window_prop_card32_set(e_client_util_win_get(ec), E_ATOM_ZONE_GEOMETRY, zgeom, 4);
}
static Eina_Bool
_e_comp_x_client_zone_set(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Client *ev)
{
E_Client *ec = ev->ec;
if (e_object_is_del(E_OBJECT(ec))) return ECORE_CALLBACK_RENEW;
E_COMP_X_PIXMAP_CHECK ECORE_CALLBACK_RENEW;
ecore_x_window_prop_card32_set(e_client_util_win_get(ev->ec), E_ATOM_ZONE, &ev->ec->zone->num, 1);
_e_comp_x_client_zone_geometry_set(ev->ec);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_sync_alarm(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Sync_Alarm *ev)
{
unsigned int serial;
E_Client *ec;
Eina_Bool resize = EINA_FALSE;
ec = _e_comp_x_client_find_by_alarm(ev->alarm);
if (!ec) return ECORE_CALLBACK_RENEW;
if (ec->netwm.sync.wait)
ec->netwm.sync.wait--;
if (ecore_x_sync_counter_query(ec->comp_data->sync_counter, &serial))
{
E_Client_Pending_Resize *pnd = NULL;
/* skip pending for which we didn't get a reply */
while (ec->pending_resize)
{
pnd = ec->pending_resize->data;
ec->pending_resize = eina_list_remove(ec->pending_resize, pnd);
if (serial == pnd->serial)
break;
E_FREE(pnd);
}
if (pnd)
{
resize = ((ec->w != pnd->w) || (ec->h != pnd->h));
ec->w = pnd->w;
ec->h = pnd->h;
E_FREE(pnd);
}
}
if (resize)
{
ec->changes.size = 1;
EC_CHANGED(ec);
}
ecore_x_pointer_xy_get(ec->comp->man->root,
&ec->mouse.current.mx,
&ec->mouse.current.my);
ec->netwm.sync.send_time = ecore_loop_time_get();
if (resize)
e_client_mouse_move(ec, &(Evas_Point){ec->mouse.current.mx, ec->mouse.current.my});
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_desktop_change(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Desktop_Change *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->win);
if (ec)
{
if (ev->desk == 0xffffffff)
e_client_stick(ec);
else if ((int)ev->desk < (ec->zone->desk_x_count * ec->zone->desk_y_count))
{
E_Desk *desk;
desk = e_desk_at_pos_get(ec->zone, ev->desk);
if (desk)
e_client_desk_set(ec, desk);
}
}
else
ecore_x_netwm_desktop_set(ev->win, ev->desk);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_move_resize_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Move_Resize_Request *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
if ((ec->shaded) || (ec->shading) ||
(ec->fullscreen) || (ec->moving) ||
(ec->resize_mode != E_POINTER_RESIZE_NONE))
return ECORE_CALLBACK_PASS_ON;
if ((ev->button >= 1) && (ev->button <= 3))
{
ec->mouse.last_down[ev->button - 1].mx = ev->x;
ec->mouse.last_down[ev->button - 1].my = ev->y;
ec->mouse.last_down[ev->button - 1].x = ec->x;
ec->mouse.last_down[ev->button - 1].y = ec->y;
ec->mouse.last_down[ev->button - 1].w = ec->w;
ec->mouse.last_down[ev->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 = ev->x;
ec->mouse.current.my = ev->y;
ec->moveinfo.down.button = ev->button;
ec->moveinfo.down.mx = ev->x;
ec->moveinfo.down.my = ev->y;
if (!ec->lock_user_stacking)
evas_object_raise(ec->frame);
if (ev->direction == E_POINTER_MOVE)
{
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)
{
e_object_ref(E_OBJECT(ec->cur_mouse_action));
ec->cur_mouse_action->func.go(E_OBJECT(ec), NULL);
}
}
return ECORE_CALLBACK_PASS_ON;
}
ec->cur_mouse_action = e_action_find("window_resize");
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) return ECORE_CALLBACK_RENEW;
e_object_ref(E_OBJECT(ec->cur_mouse_action));
ec->cur_mouse_action->func.go(E_OBJECT(ec), NULL);
switch (ev->direction)
{
case E_POINTER_RESIZE_TL:
ec->resize_mode = E_POINTER_RESIZE_TL;
GRAV_SET(ec, ECORE_X_GRAVITY_SE);
break;
case E_POINTER_RESIZE_T:
ec->resize_mode = E_POINTER_RESIZE_T;
GRAV_SET(ec, ECORE_X_GRAVITY_S);
break;
case E_POINTER_RESIZE_TR:
ec->resize_mode = E_POINTER_RESIZE_TR;
GRAV_SET(ec, ECORE_X_GRAVITY_SW);
break;
case E_POINTER_RESIZE_R:
ec->resize_mode = E_POINTER_RESIZE_R;
GRAV_SET(ec, ECORE_X_GRAVITY_W);
break;
case E_POINTER_RESIZE_BR:
ec->resize_mode = E_POINTER_RESIZE_BR;
GRAV_SET(ec, ECORE_X_GRAVITY_NW);
break;
case E_POINTER_RESIZE_B:
ec->resize_mode = E_POINTER_RESIZE_B;
GRAV_SET(ec, ECORE_X_GRAVITY_N);
break;
case E_POINTER_RESIZE_BL:
ec->resize_mode = E_POINTER_RESIZE_BL;
GRAV_SET(ec, ECORE_X_GRAVITY_NE);
break;
case E_POINTER_RESIZE_L:
ec->resize_mode = E_POINTER_RESIZE_L;
GRAV_SET(ec, ECORE_X_GRAVITY_E);
break;
default:
return ECORE_CALLBACK_PASS_ON;
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Focus_In *ev)
{
E_Client *ec, *focused;
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
/* block refocus attempts on iconic clients
* these result from iconifying a client during a grab */
if (ec->iconic) return ECORE_CALLBACK_RENEW;
/* block spurious focus events
* not sure if correct, but seems necessary to use pointer focus...
*/
focused = e_client_focused_get();
if (focused && (ec != focused)) return ECORE_CALLBACK_RENEW;
_e_comp_x_client_pri_raise(ec);
if (ev->mode == ECORE_X_EVENT_MODE_GRAB)
{
if (ev->detail == ECORE_X_EVENT_DETAIL_POINTER) return ECORE_CALLBACK_PASS_ON;
}
else if (ev->mode == ECORE_X_EVENT_MODE_UNGRAB)
{
/* this seems to break winlist...
if (ev->detail == ECORE_X_EVENT_DETAIL_POINTER)
*/
/* we're getting a non-linear focus re-set on a visible
* window on current desk when no other client is focused;
* this is probably when we're trying to reapply focus after
* unfocusing some comp canvas widget
*/
if ((ev->detail != ECORE_X_EVENT_DETAIL_NON_LINEAR) ||
focused ||
(!e_client_util_desk_visible(ec, e_desk_current_get(ec->zone))))
return ECORE_CALLBACK_PASS_ON;
}
/* ignore focus in from !take_focus windows, we just gave it em */
/* if (!ec->icccm.take_focus)
* return ECORE_CALLBACK_PASS_ON; */
/* should be equal, maybe some clients dont reply with the proper timestamp ? */
if (ev->time >= focus_time)
evas_object_focus_set(ec->frame, 1);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_shape(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Shape *ev)
{
E_Client *ec;
//const char *txt[] =
//{
//[ECORE_X_SHAPE_BOUNDING] = "BOUNDING",
//[ECORE_X_SHAPE_INPUT] = "INPUT",
//[ECORE_X_SHAPE_CLIP] = "CLIP",
//};
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
//INF("%p(%s): %d,%d %dx%d || %d", ec, txt[ev->type], ev->x, ev->y, ev->w, ev->h, ev->shaped);
if (ev->win == e_client_util_win_get(ec))
{
if (ev->type == ECORE_X_SHAPE_INPUT)
{
ec->changes.shape_input = 1;
ec->need_shape_merge = 1;
}
else
ec->changes.shape = 1;
}
else if (ec->shaped) //shape change on parent window only valid if window is known to be shaped
ec->need_shape_export = 1;
EC_CHANGED(ec);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_damage(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Damage *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_damage(ev->damage);
if (!ec) return ECORE_CALLBACK_PASS_ON;
if (ec->comp_data->damage)
{
Ecore_X_Region parts;
parts = ecore_x_region_new(NULL, 0);
ecore_x_damage_subtract(ec->comp_data->damage, 0, parts);
ecore_x_region_free(parts);
}
//WRN("DAMAGE %p: %dx%d", ec, ev->area.width, ev->area.height);
if (ec->comp->nocomp)
e_pixmap_dirty(ec->pixmap);
else
e_comp_object_damage(ec->frame, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_damage_win(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Damage *ev)
{
E_Comp *c;
c = e_comp_find_by_window(ev->win);
if (c) e_comp_render_queue(c);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_grab_replay(void *data EINA_UNUSED, int type, void *event)
{
Ecore_Event_Mouse_Button *ev = event;
E_Binding_Event_Mouse_Button ev2;
E_Client *ec;
if (type != ECORE_EVENT_MOUSE_BUTTON_DOWN) return ECORE_CALLBACK_DONE;
if ((!e_config->pass_click_on) &&
(!e_config->always_click_to_raise) && // this works even if not on click-to-focus
(!e_config->always_click_to_focus) // this works even if not on click-to-focus
)
return ECORE_CALLBACK_DONE;
ec = _e_comp_x_client_find_by_window(ev->event_window);
if (!ec) return ECORE_CALLBACK_DONE;
if (ec->cur_mouse_action) return ECORE_CALLBACK_DONE;
e_bindings_ecore_event_mouse_button_convert(ev, &ev2);
return !e_bindings_mouse_button_find(E_BINDING_CONTEXT_WINDOW,
&ev2, NULL);
}
static void
_e_comp_x_hook_client_eval_end(void *d EINA_UNUSED, E_Client *ec)
{
E_COMP_X_PIXMAP_CHECK;
if (ec->comp->comp_data->restack && (!ec->comp->new_clients))
{
e_hints_client_stacking_set();
ec->comp->comp_data->restack = 0;
}
}
static void
_e_comp_x_hook_client_post_new_client(void *d EINA_UNUSED, E_Client *ec)
{
E_COMP_X_PIXMAP_CHECK;
if (ec->changes.reset_gravity)
{
GRAV_SET(ec, ECORE_X_GRAVITY_NW);
}
if (ec->need_shape_merge)
{
_e_comp_x_client_shape_input_rectangle_set(ec);
if (!ec->shaped)
ecore_x_window_shape_mask_set(e_client_util_pwin_get(ec), 0);
ec->need_shape_merge = 0;
}
if (ec->changes.internal_state)
{
Ecore_X_Atom state[1];
int num = 0;
E_Win *win = ecore_evas_data_get(ec->internal_ecore_evas, "E_Win");
if (win->state.centered)
state[num++] = E_ATOM_WINDOW_STATE_CENTERED;
if (num)
ecore_x_window_prop_card32_set(win->evas_win, E_ATOM_WINDOW_STATE, state, num);
else
ecore_x_window_prop_property_del(win->evas_win, E_ATOM_WINDOW_STATE);
}
if (ec->changes.internal_props)
{
E_Win *win = ecore_evas_data_get(ec->internal_ecore_evas, "E_Win");
ecore_x_icccm_size_pos_hints_set(win->evas_win,
win->placed, ECORE_X_GRAVITY_NW,
win->min_w, win->min_h,
win->max_w, win->max_h,
win->base_w, win->base_h,
win->step_x, win->step_y,
win->min_aspect, win->max_aspect);
ec->changes.internal_props = 0;
ec->comp_data->internal_props_set++;
}
if (ec->need_shape_export)
{
Ecore_X_Rectangle *rects, *orects;
int num;
rects = ecore_x_window_shape_rectangles_get(e_client_util_win_get(ec), &num);
if (rects)
{
int changed = 1;
if (((unsigned int)num == ec->shape_rects_num) && (ec->shape_rects))
{
int i;
orects = (Ecore_X_Rectangle*)ec->shape_rects;
changed = 0;
for (i = 0; i < num; i++)
{
E_RECTS_CLIP_TO_RECT(rects[i].x, rects[i].y,
rects[i].width, rects[i].height, 0, 0, ec->client.w, ec->client.h);
if ((orects[i].x != rects[i].x) ||
(orects[i].y != rects[i].y) ||
(orects[i].width != rects[i].width) ||
(orects[i].height != rects[i].height))
{
changed = 1;
break;
}
}
}
if (changed)
{
E_FREE(ec->shape_rects);
ec->shape_rects = (Eina_Rectangle*)rects;
ec->shape_rects_num = num;
ec->shape_changed = 1;
}
else
free(rects);
}
else
{
E_FREE(ec->shape_rects);
ec->shape_rects_num = 0;
}
ec->need_shape_export = 0;
}
}
static void
_e_comp_x_hook_client_pre_frame_assign(void *d EINA_UNUSED, E_Client *ec)
{
Ecore_X_Window win, pwin;
E_COMP_X_PIXMAP_CHECK;
win = e_client_util_win_get(ec);
if (!ec->comp_data->need_reparent) return;
/* match ec parent argbness */
if (ec->argb)
pwin = ecore_x_window_manager_argb_new(ec->comp->man->root, ec->client.x, ec->client.y, ec->client.w, ec->client.h);
else
{
pwin = ecore_x_window_override_new(ec->comp->man->root, ec->client.x, ec->client.y, ec->client.w, ec->client.h);
ecore_x_window_shape_events_select(pwin, !ec->internal); //let's just agree never to do this with our own windows...
}
if (ec->client.w && ec->client.h)
/* force a resize here (no-op most of the time)
* prevents mismatch between remembered window size and current size
*/
ecore_x_window_resize(win, ec->client.w, ec->client.h);
ecore_x_window_container_manage(pwin);
if (!ec->internal) ecore_x_window_client_manage(win);
ecore_x_window_configure(pwin,
ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
0, 0, 0, 0, 0,
win, ECORE_X_WINDOW_STACK_ABOVE);
ecore_x_event_mask_set(pwin, ECORE_X_EVENT_MASK_MOUSE_IN | ECORE_X_EVENT_MASK_MOUSE_OUT);
ecore_x_window_border_width_set(win, 0);
ec->border_size = 0;
if (ec->e.state.video)
{
ecore_x_window_lower(pwin);
ecore_x_composite_window_events_disable(pwin);
ecore_x_window_ignore_set(pwin, EINA_TRUE);
}
if (!ec->internal)
ecore_x_window_save_set_add(win);
ecore_x_window_reparent(win, pwin, 0, 0);
{
unsigned int managed = 1;
ecore_x_window_prop_card32_set(win, E_ATOM_MANAGED, &managed, 1);
}
e_pixmap_parent_window_set(ec->pixmap, pwin);
ec->border.changed = 1;
if (!ec->shaped)
ecore_x_window_shape_mask_set(pwin, 0);
if (ec->shaped_input)
ecore_x_window_shape_input_rectangles_set(pwin, (Ecore_X_Rectangle*)ec->shape_input_rects, ec->shape_input_rects_num);
ec->changes.shape = 1;
ec->changes.shape_input = 1;
if (ec->internal_ecore_evas)
{
ecore_x_window_gravity_set(win, ECORE_X_GRAVITY_NW);
ec->changes.reset_gravity = 1;
}
EC_CHANGED(ec);
eina_hash_add(clients_win_hash, &pwin, ec);
if (ec->visible)
{
if (ec->comp_data->set_win_type && ec->internal_ecore_evas)
{
E_Win *ewin = ecore_evas_data_get(ec->internal_ecore_evas, "E_Win");
if (ewin)
{
if (ec->dialog)
ecore_x_netwm_window_type_set(win, ECORE_X_WINDOW_TYPE_DIALOG);
else
ecore_x_netwm_window_type_set(win, ECORE_X_WINDOW_TYPE_NORMAL);
}
ec->comp_data->set_win_type = 0;
}
}
if (ec->re_manage || ec->visible)
{
ecore_x_window_show(win);
ecore_x_window_show(pwin);
}
_e_comp_x_focus_setup(ec);
e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, pwin);
e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, pwin);
_e_comp_x_client_evas_init(ec);
if (ec->netwm.ping && (!ec->ping_poller))
e_client_ping(ec);
if (ec->visible) evas_object_show(ec->frame);
ec->comp_data->need_reparent = 0;
ec->redirected = 1;
if (ec->comp_data->change_icon)
{
ec->changes.icon = 1;
EC_CHANGED(ec);
}
ec->comp_data->change_icon = 0;
ec->comp_data->reparented = 1;
_e_comp_x_evas_comp_hidden_cb(ec, NULL, NULL);
}
static void
_e_comp_x_hook_client_fetch(void *d EINA_UNUSED, E_Client *ec)
{
Ecore_X_Window win, pwin;
int rem_change = 0;
Eina_Bool need_desk_set = EINA_FALSE;
E_COMP_X_PIXMAP_CHECK;
win = e_client_util_win_get(ec);
pwin = e_client_util_pwin_get(ec);
if (ec->changes.visible)
_e_comp_x_client_shape_input_rectangle_set(ec);
/* fetch any info queued to be fetched */
if (ec->changes.prop || ec->netwm.fetch.state)
{
e_hints_window_state_get(ec);
ec->netwm.fetch.state = 0;
rem_change = 1;
}
if (ec->icccm.fetch.client_leader)
{
/* TODO: What do to if the client leader isn't mapped yet? */
E_Client *ec_leader = NULL;
ec->icccm.client_leader = ecore_x_icccm_client_leader_get(win);
if (ec->icccm.client_leader)
ec_leader = _e_comp_x_client_find_by_window(ec->icccm.client_leader);
if (ec->leader)
{
if (ec->leader != ec_leader)
{
ec->leader->group = eina_list_remove(ec->leader->group, ec);
if (ec->leader->modal == ec) ec->leader->modal = NULL;
ec->leader = NULL;
}
else
ec_leader = NULL;
}
/* If this client is the leader of the group, don't register itself */
if ((ec_leader) && (ec_leader != ec))
{
ec_leader->group = eina_list_append(ec_leader->group, ec);
ec->leader = ec_leader;
/* Only set the window modal to the leader it there is no parent */
if ((ec->netwm.state.modal) &&
((!ec->parent) || (ec->parent->modal != ec)))
{
ec->leader->modal = ec;
if (ec->leader->focused)
evas_object_focus_set(ec->frame, 1);
else
{
Eina_List *l;
E_Client *child;
EINA_LIST_FOREACH(ec->leader->group, l, child)
{
if ((child != ec) && (child->focused))
evas_object_focus_set(ec->frame, 1);
}
}
}
}
ec->icccm.fetch.client_leader = 0;
rem_change = 1;
}
if (ec->icccm.fetch.title)
{
char *title = ecore_x_icccm_title_get(win);
eina_stringshare_replace(&ec->icccm.title, title);
free(title);
e_comp_object_frame_title_set(ec->frame, ec->icccm.title);
ec->icccm.fetch.title = 0;
rem_change = 1;
}
if (ec->netwm.fetch.name)
{
char *name;
ecore_x_netwm_name_get(win, &name);
eina_stringshare_replace(&ec->netwm.name, name);
free(name);
ec->hacks.iconic_shading =
((ec->netwm.icon_name == ec->netwm.name) &&
(!e_util_strcmp(ec->netwm.name, "QEMU")));
e_comp_object_frame_title_set(ec->frame, ec->netwm.name);
ec->netwm.fetch.name = 0;
rem_change = 1;
}
if (ec->icccm.fetch.name_class)
{
const char *pname, *pclass;
char *nname, *nclass;
ecore_x_icccm_name_class_get(win, &nname, &nclass);
pname = ec->icccm.name;
pclass = ec->icccm.class;
ec->icccm.name = eina_stringshare_add(nname);
ec->icccm.class = eina_stringshare_add(nclass);
ec->hacks.mapping_change =
((!e_util_strcasecmp(ec->icccm.class, "vmplayer")) ||
(!e_util_strcasecmp(ec->icccm.class, "vmware")));
if (ec->hacks.mapping_change)
_e_comp_x_mapping_change_disabled++;
_e_comp_x_mapping_change_disabled = MIN(_e_comp_x_mapping_change_disabled, 0);
free(nname);
free(nclass);
if (!((ec->icccm.name == pname) &&
(ec->icccm.class == pclass)))
{
if (ec->icccm.name && (!e_util_strcmp(ec->icccm.class, "e_layer_win")))
{
/* this is a stacking window or someone trying to crash us */
E_Layer layer;
errno = 0;
layer = strtol(ec->icccm.name, NULL, 10);
if ((!errno) && (!ec->comp->layers[e_comp_canvas_layer_map(layer)].obj))
{
ec->lock_client_stacking = 1;
ec->internal = 1;
ec->comp->layers[e_comp_canvas_layer_map(layer)].obj = ec->frame;
evas_object_layer_set(ec->frame, layer);
}
}
ec->changes.icon = 1;
rem_change = 1;
}
eina_stringshare_del(pname);
eina_stringshare_del(pclass);
ec->icccm.fetch.name_class = 0;
}
if (ec->changes.prop || ec->icccm.fetch.state)
{
ec->icccm.state = ecore_x_icccm_state_get(win);
ec->icccm.fetch.state = 0;
rem_change = 1;
}
if (ec->changes.prop || ec->e.fetch.state)
{
e_hints_window_e_state_get(ec);
ec->e.fetch.state = 0;
rem_change = 1;
}
if (ec->e.fetch.profile)
{
const char **list = NULL;
int n, i, res;
unsigned int use;
if (ec->e.state.profile.name)
{
eina_stringshare_del(ec->e.state.profile.name);
ec->e.state.profile.name = NULL;
}
if (ec->e.state.profile.available_list)
{
for (i = 0; i < ec->e.state.profile.num; i++)
{
if (ec->e.state.profile.available_list[i])
{
eina_stringshare_del(ec->e.state.profile.available_list[i]);
ec->e.state.profile.available_list[i] = NULL;
}
}
E_FREE(ec->e.state.profile.available_list);
ec->e.state.profile.available_list = NULL;
}
ec->e.state.profile.num = 0;
res = ecore_x_window_prop_card32_get(win,
ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED,
&use,
1);
if ((res == 1) && (use == 1))
{
Ecore_X_Atom val;
res = ecore_x_window_prop_atom_get(win,
ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE,
&val, 1);
if (res == 1)
{
char *name = ecore_x_atom_name_get(val);
if (name)
{
ec->e.state.profile.name = eina_stringshare_add(name);
free(name);
}
}
if (ecore_x_e_window_available_profiles_get(win, &list, &n))
{
ec->e.state.profile.available_list = E_NEW(const char *, n);
for (i = 0; i < n; i++)
ec->e.state.profile.available_list[i] = eina_stringshare_add(list[i]);
ec->e.state.profile.num = n;
}
need_desk_set = EINA_TRUE;
ec->e.state.profile.use = 1;
free(list);
}
ec->e.fetch.profile = 0;
}
if (ec->e.state.profile.set)
{
ecore_x_e_window_profile_change_request_send(e_client_util_pwin_get(ec),
ec->e.state.profile.set);
ec->e.state.profile.wait_for_done = 1;
eina_stringshare_replace(&ec->e.state.profile.set, NULL);
}
if (ec->changes.prop || ec->netwm.fetch.type)
{
e_hints_window_type_get(ec);
if (((!ec->lock_border) || (!ec->border.name)) && ec->comp_data->reparented)
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
if ((ec->netwm.type == E_WINDOW_TYPE_DOCK) || ec->tooltip)
{
if (!ec->netwm.state.skip_pager)
{
ec->netwm.state.skip_pager = 1;
ec->netwm.update.state = 1;
}
if (!ec->netwm.state.skip_taskbar)
{
ec->netwm.state.skip_taskbar = 1;
ec->netwm.update.state = 1;
}
}
else if (ec->netwm.type == E_WINDOW_TYPE_DESKTOP)
{
ec->focus_policy_override = E_FOCUS_CLICK;
_e_comp_x_focus_setup(ec);
if (!ec->netwm.state.skip_pager)
{
ec->netwm.state.skip_pager = 1;
ec->netwm.update.state = 1;
}
if (!ec->netwm.state.skip_taskbar)
{
ec->netwm.state.skip_taskbar = 1;
ec->netwm.update.state = 1;
}
if (!e_client_util_ignored_get(ec))
ec->border.changed = ec->borderless = 1;
}
if (ec->tooltip)
{
ec->icccm.accepts_focus = 0;
eina_stringshare_replace(&ec->bordername, "borderless");
}
else if (ec->internal)
{
if (ec->dialog)
ecore_x_icccm_transient_for_set(win, ec->comp->man->root);
else
ecore_x_icccm_transient_for_unset(win);
}
{
E_Event_Client_Property *ev;
ev = E_NEW(E_Event_Client_Property, 1);
ev->ec = ec;
e_object_ref(E_OBJECT(ec));
ev->property = E_CLIENT_PROPERTY_NETWM_STATE;
ecore_event_add(E_EVENT_CLIENT_PROPERTY, ev, _e_comp_x_client_event_free, NULL);
}
ec->netwm.fetch.type = 0;
}
if (ec->icccm.fetch.machine)
{
char *machine = ecore_x_icccm_client_machine_get(win);
if ((!machine) && (ec->icccm.client_leader))
machine = ecore_x_icccm_client_machine_get(ec->icccm.client_leader);
eina_stringshare_replace(&ec->icccm.machine, machine);
free(machine);
ec->icccm.fetch.machine = 0;
rem_change = 1;
}
if (ec->icccm.fetch.command)
{
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]);
free(ec->icccm.command.argv);
}
ec->icccm.command.argc = 0;
ec->icccm.command.argv = NULL;
ecore_x_icccm_command_get(win,
&(ec->icccm.command.argc),
&(ec->icccm.command.argv));
if ((ec->icccm.client_leader) &&
(!ec->icccm.command.argv))
ecore_x_icccm_command_get(ec->icccm.client_leader,
&(ec->icccm.command.argc),
&(ec->icccm.command.argv));
ec->icccm.fetch.command = 0;
rem_change = 1;
}
if (ec->changes.prop || ec->icccm.fetch.hints)
{
Eina_Bool accepts_focus, is_urgent;
accepts_focus = EINA_TRUE;
is_urgent = EINA_FALSE;
ec->icccm.initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
if (ecore_x_icccm_hints_get(win,
&accepts_focus,
&ec->icccm.initial_state,
&ec->icccm.icon_pixmap,
&ec->icccm.icon_mask,
(Ecore_X_Window*)&ec->icccm.icon_window,
(Ecore_X_Window*)&ec->icccm.window_group,
&is_urgent))
{
ec->icccm.accepts_focus = accepts_focus;
ec->icccm.urgent = is_urgent;
/* If this is a new window, set the state as requested. */
if ((ec->new_client) &&
(ec->icccm.initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC))
e_client_iconify(ec);
}
ec->icccm.fetch.hints = 0;
rem_change = 1;
}
if (ec->changes.prop || ec->icccm.fetch.size_pos_hints)
{
Eina_Bool request_pos;
request_pos = EINA_FALSE;
if (ecore_x_icccm_size_pos_hints_get(win,
&request_pos,
&ec->icccm.gravity,
&ec->icccm.min_w,
&ec->icccm.min_h,
&ec->icccm.max_w,
&ec->icccm.max_h,
&ec->icccm.base_w,
&ec->icccm.base_h,
&ec->icccm.step_w,
&ec->icccm.step_h,
&ec->icccm.min_aspect,
&ec->icccm.max_aspect))
{
ec->icccm.request_pos = request_pos;
if (request_pos && (!ec->placed) && (!ec->re_manage))
{
Ecore_X_Window_Attributes *att;
int bw;
int l, r, t, b;
int zx = 0, zy = 0, zw = 0, zh = 0;
if (ec->zone)
e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
e_comp_object_frame_geometry_get(ec->frame, &l, &r, &t, &b);
att = &ec->comp_data->initial_attributes;
bw = att->border * 2;
switch (ec->icccm.gravity)
{
case ECORE_X_GRAVITY_N:
ec->x = (att->x - (bw / 2)) - (l / 2);
ec->y = att->y;
break;
case ECORE_X_GRAVITY_NE:
ec->x = (att->x - (bw)) - (l);
ec->y = att->y;
break;
case ECORE_X_GRAVITY_E:
ec->x = (att->x - (bw)) - (l);
ec->y = (att->y - (bw / 2)) - (t / 2);
break;
case ECORE_X_GRAVITY_SE:
ec->x = (att->x - (bw)) - (l);
ec->y = (att->y - (bw)) - (t);
break;
case ECORE_X_GRAVITY_S:
ec->x = (att->x - (bw / 2)) - (l / 2);
ec->y = (att->y - (bw)) - (t);
break;
case ECORE_X_GRAVITY_SW:
ec->x = att->x;
ec->y = (att->y - (bw)) - (t);
break;
case ECORE_X_GRAVITY_W:
ec->x = att->x;
ec->y = (att->y - (bw)) - (t);
break;
case ECORE_X_GRAVITY_CENTER:
ec->x = (att->x - (bw / 2)) - (l / 2);
ec->y = (att->y - (bw / 2)) - (t / 2);
break;
case ECORE_X_GRAVITY_NW:
default:
ec->x = att->x;
ec->y = att->y;
}
/*
* This ensures that windows that like to open with a x/y
* position smaller than returned by e_zone_useful_geometry_get()
* are moved to useful positions.
*/
// ->
if (e_config->geometry_auto_move)
{
if (ec->x < zx)
ec->x = zx;
if (ec->y < zy)
ec->y = zy;
/* ensure we account for windows which already have client_inset;
* fixes lots of wine placement issues
*/
if (ec->x - l >= zx)
ec->x -= l;
if (ec->y - t >= zy)
ec->y -= t;
if (ec->x + ec->w > zx + zw)
ec->x = zx + zw - ec->w;
if (ec->y + ec->h > zy + zh)
ec->y = zy + zh - ec->h;
// <--
if (ec->zone && e_comp_zone_xy_get(ec->comp, ec->x, ec->y))
{
if (!E_INSIDE(ec->x, ec->y, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h))
{
ec->x = E_CLAMP(ec->x, ec->zone->x, ec->zone->x + ec->zone->w);
ec->y = E_CLAMP(ec->y, ec->zone->y, ec->zone->y + ec->zone->h);
}
/* some application failing to correctly center a window */
if (eina_list_count(ec->comp->zones) > 1)
{
if (((abs((ec->comp->man->w / 2) - ec->x) < 3) || //ec->x is center of manager
((abs((ec->comp->man->w / 2) - ec->x - ec->w) < 3) || //ec->x - ec->w is center of manager
(abs((ec->comp->man->w / 2) - ec->x - (ec->w / 2)) < 3))) || //ec->x - ec->w/2 is center of manager
((abs((ec->comp->man->h / 2) - ec->y) < 3) || //ec->y is center of manager
((abs((ec->comp->man->h / 2) - ec->y - ec->h) < 3) || //ec->y - ec->h is center of manager
(abs((ec->comp->man->h / 2) - ec->y - (ec->h / 2)) < 3))) //ec->y - ec->h/2 is center of manager
)
e_comp_object_util_center(ec->frame);
}
ec->changes.pos = 1;
ec->placed = 1;
}
}
else
{
ec->changes.pos = 1;
ec->placed = 1;
}
}
}
else
{
}
if (ec->icccm.min_w > 32767) ec->icccm.min_w = 32767;
if (ec->icccm.min_h > 32767) ec->icccm.min_h = 32767;
if (ec->icccm.max_w > 32767) ec->icccm.max_w = 32767;
if (ec->icccm.max_h > 32767) ec->icccm.max_h = 32767;
if (ec->icccm.base_w > 32767) ec->icccm.base_w = 32767;
if (ec->icccm.base_h > 32767) ec->icccm.base_h = 32767;
// if (ec->icccm.step_w < 1) ec->icccm.step_w = 1;
// if (ec->icccm.step_h < 1) ec->icccm.step_h = 1;
// if doing a resize, fix it up
if (e_client_resizing_get(ec))
{
int x, y, w, h, new_w, new_h;
x = ec->x;
y = ec->y;
w = ec->w;
h = ec->h;
new_w = w;
new_h = 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))
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))
y += (h - new_h);
evas_object_geometry_set(ec->frame, x, y, new_w, new_h);
}
ec->icccm.fetch.size_pos_hints = 0;
rem_change = 1;
}
if (ec->icccm.fetch.protocol)
{
int i, num;
Ecore_X_WM_Protocol *proto;
proto = ecore_x_window_prop_protocol_list_get(win, &num);
if (proto)
{
for (i = 0; i < num; i++)
{
if (proto[i] == ECORE_X_WM_PROTOCOL_DELETE_REQUEST)
ec->icccm.delete_request = 1;
else if (proto[i] == ECORE_X_WM_PROTOCOL_TAKE_FOCUS)
ec->icccm.take_focus = 1;
else if (proto[i] == ECORE_X_NET_WM_PROTOCOL_PING)
ec->netwm.ping = 1;
else if (proto[i] == ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST)
{
ec->netwm.sync.request = 1;
if (!ecore_x_netwm_sync_counter_get(win,
&ec->comp_data->sync_counter))
ec->netwm.sync.request = 0;
}
}
free(proto);
}
if (ec->netwm.ping && ec->comp_data->evas_init)
e_client_ping(ec);
else
E_FREE_FUNC(ec->ping_poller, ecore_poller_del);
ec->icccm.fetch.protocol = 0;
}
if (ec->icccm.fetch.transient_for)
{
/* TODO: What do to if the transient for isn't mapped yet? */
E_Client *ec_parent = NULL;
ec->icccm.transient_for = ecore_x_icccm_transient_for_get(win);
if (ec->icccm.transient_for)
ec_parent = _e_comp_x_client_find_by_window(ec->icccm.transient_for);
/* If we already have a parent, remove it */
if (ec->parent)
{
if (ec_parent != ec->parent)
{
ec->parent->transients = eina_list_remove(ec->parent->transients, ec);
if (ec->parent->modal == ec) ec->parent->modal = NULL;
ec->parent = NULL;
}
else
ec_parent = NULL;
}
if ((ec_parent) && (ec_parent != ec) &&
(eina_list_data_find(ec->transients, ec_parent) != ec_parent))
{
ec_parent->transients = eina_list_append(ec_parent->transients, ec);
ec->parent = ec_parent;
}
if (ec->parent)
{
evas_object_layer_set(ec->frame, ec->parent->layer);
if (ec->netwm.state.modal)
{
ec->parent->modal = ec;
ec->parent->lock_close = 1;
if (!ec->parent->comp_data->lock_win)
{
eina_hash_add(clients_win_hash, &ec->parent->comp_data->lock_win, ec->parent);
ec->parent->comp_data->lock_win = ecore_x_window_input_new(e_client_util_pwin_get(ec->parent), 0, 0, ec->parent->w, ec->parent->h);
e_comp_ignore_win_add(E_PIXMAP_TYPE_X, ec->parent->comp_data->lock_win);
ecore_x_window_show(ec->parent->comp_data->lock_win);
ecore_x_icccm_name_class_set(ec->parent->comp_data->lock_win, "comp_data->lock_win", "comp_data->lock_win");
}
}
if (e_config->focus_setting == E_FOCUS_NEW_DIALOG ||
(ec->parent->focused && (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))
ec->take_focus = 1;
}
ec->icccm.fetch.transient_for = 0;
rem_change = 1;
}
if (ec->icccm.fetch.window_role)
{
char *role = ecore_x_icccm_window_role_get(win);
eina_stringshare_replace(&ec->icccm.window_role, role);
free(role);
ec->icccm.fetch.window_role = 0;
rem_change = 1;
}
if (ec->icccm.fetch.icon_name)
{
char *icon_name = ecore_x_icccm_icon_name_get(win);
eina_stringshare_replace(&ec->icccm.icon_name, icon_name);
free(icon_name);
ec->hacks.iconic_shading =
((ec->netwm.icon_name == ec->netwm.name) &&
(!e_util_strcmp(ec->netwm.icon_name, "QEMU")));
ec->icccm.fetch.icon_name = 0;
rem_change = 1;
}
if (ec->netwm.fetch.icon_name)
{
char *icon_name;
ecore_x_netwm_icon_name_get(win, &icon_name);
eina_stringshare_replace(&ec->netwm.icon_name, icon_name);
free(icon_name);
ec->netwm.fetch.icon_name = 0;
rem_change = 1;
}
if (ec->netwm.fetch.opacity)
{
unsigned int val;
if (ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, &val, 1) > 0)
{
val = (val >> 24);
if (ec->netwm.opacity != val)
{
ec->netwm.opacity = val;
rem_change = 1;
}
}
}
if (ec->netwm.fetch.icon)
{
int i;
if (ec->netwm.icons)
{
for (i = 0; i < ec->netwm.num_icons; i++)
{
free(ec->netwm.icons[i].data);
ec->netwm.icons[i].data = NULL;
}
free(ec->netwm.icons);
}
ec->netwm.icons = NULL;
ec->netwm.num_icons = 0;
if (ecore_x_netwm_icons_get(win,
&ec->netwm.icons,
&ec->netwm.num_icons))
{
// unless the rest of e uses border icons OTHER than icon #0
// then free the rest that we don't need anymore.
for (i = 1; i < ec->netwm.num_icons; i++)
{
free(ec->netwm.icons[i].data);
ec->netwm.icons[i].data = NULL;
}
ec->netwm.num_icons = 1;
ec->changes.icon = 1;
}
ec->netwm.fetch.icon = 0;
}
if (ec->netwm.fetch.user_time)
{
ecore_x_netwm_user_time_get(win, &ec->netwm.user_time);
ec->netwm.fetch.user_time = 0;
}
if (ec->netwm.fetch.strut)
{
if (!ecore_x_netwm_strut_partial_get(win,
&ec->netwm.strut.left,
&ec->netwm.strut.right,
&ec->netwm.strut.top,
&ec->netwm.strut.bottom,
&ec->netwm.strut.left_start_y,
&ec->netwm.strut.left_end_y,
&ec->netwm.strut.right_start_y,
&ec->netwm.strut.right_end_y,
&ec->netwm.strut.top_start_x,
&ec->netwm.strut.top_end_x,
&ec->netwm.strut.bottom_start_x,
&ec->netwm.strut.bottom_end_x))
{
ecore_x_netwm_strut_get(win,
&ec->netwm.strut.left, &ec->netwm.strut.right,
&ec->netwm.strut.top, &ec->netwm.strut.bottom);
ec->netwm.strut.left_start_y = 0;
ec->netwm.strut.left_end_y = 0;
ec->netwm.strut.right_start_y = 0;
ec->netwm.strut.right_end_y = 0;
ec->netwm.strut.top_start_x = 0;
ec->netwm.strut.top_end_x = 0;
ec->netwm.strut.bottom_start_x = 0;
ec->netwm.strut.bottom_end_x = 0;
}
ec->netwm.fetch.strut = 0;
}
if (ec->qtopia.fetch.soft_menu)
{
e_hints_window_qtopia_soft_menu_get(ec);
ec->qtopia.fetch.soft_menu = 0;
rem_change = 1;
}
if (ec->qtopia.fetch.soft_menus)
{
e_hints_window_qtopia_soft_menus_get(ec);
ec->qtopia.fetch.soft_menus = 0;
rem_change = 1;
}
if (ec->vkbd.fetch.state)
{
e_hints_window_virtual_keyboard_state_get(ec);
ec->vkbd.fetch.state = 0;
rem_change = 1;
}
if (ec->vkbd.fetch.vkbd)
{
e_hints_window_virtual_keyboard_get(ec);
ec->vkbd.fetch.vkbd = 0;
rem_change = 1;
}
if (ec->comp_data->illume.conformant.fetch.conformant)
{
ec->comp_data->illume.conformant.conformant =
ecore_x_e_illume_conformant_get(win);
ec->comp_data->illume.conformant.fetch.conformant = 0;
}
if (ec->comp_data->illume.quickpanel.fetch.state)
{
ec->comp_data->illume.quickpanel.state =
ecore_x_e_illume_quickpanel_state_get(win);
ec->comp_data->illume.quickpanel.fetch.state = 0;
}
if (ec->comp_data->illume.quickpanel.fetch.quickpanel)
{
ec->comp_data->illume.quickpanel.quickpanel =
ecore_x_e_illume_quickpanel_get(win);
ec->comp_data->illume.quickpanel.fetch.quickpanel = 0;
}
if (ec->comp_data->illume.quickpanel.fetch.priority.major)
{
ec->comp_data->illume.quickpanel.priority.major =
ecore_x_e_illume_quickpanel_priority_major_get(win);
ec->comp_data->illume.quickpanel.fetch.priority.major = 0;
}
if (ec->comp_data->illume.quickpanel.fetch.priority.minor)
{
ec->comp_data->illume.quickpanel.priority.minor =
ecore_x_e_illume_quickpanel_priority_minor_get(win);
ec->comp_data->illume.quickpanel.fetch.priority.minor = 0;
}
if (ec->comp_data->illume.quickpanel.fetch.zone)
{
ec->comp_data->illume.quickpanel.zone =
ecore_x_e_illume_quickpanel_zone_get(win);
ec->comp_data->illume.quickpanel.fetch.zone = 0;
}
if (ec->comp_data->illume.drag.fetch.drag)
{
ec->comp_data->illume.drag.drag =
ecore_x_e_illume_drag_get(win);
ec->comp_data->illume.drag.fetch.drag = 0;
}
if (ec->comp_data->illume.drag.fetch.locked)
{
ec->comp_data->illume.drag.locked =
ecore_x_e_illume_drag_locked_get(win);
ec->comp_data->illume.drag.fetch.locked = 0;
}
if (ec->comp_data->illume.win_state.fetch.state)
{
ec->comp_data->illume.win_state.state =
ecore_x_e_illume_window_state_get(win);
ec->comp_data->illume.win_state.fetch.state = 0;
}
if (ec->changes.shape)
{
Ecore_X_Rectangle *rects;
int num;
Eina_Bool pshaped = ec->shaped;
ec->changes.shape = 0;
rects = ecore_x_window_shape_rectangles_get(win, &num);
if (rects)
{
int cw = 0, ch = 0;
/* This doesn't fix the race, but makes it smaller. we detect
* this and if cw and ch != client w/h then mark this as needing
* a shape change again to fixup next event loop.
*/
ecore_x_window_size_get(win, &cw, &ch);
/* normalize for client window dead zone */
if (ec->border_size && (num == 1))
{
rects[0].x += ec->border_size;
rects[0].y += ec->border_size;
rects[0].width -= ec->border_size;
rects[0].height -= ec->border_size;
}
if ((cw != ec->client.w) || (ch != ec->client.h))
{
ec->changes.shape = 1;
EC_CHANGED(ec);
}
if ((num == 1) &&
(rects[0].x == 0) &&
(rects[0].y == 0) &&
((int)rects[0].width == cw) &&
((int)rects[0].height == ch))
{
if (ec->shaped)
{
ec->shaped = 0;
if (ec->comp_data->reparented && (!ec->bordername))
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
}
}
else
{
if (ec->comp_data->reparented)
{
ecore_x_window_shape_rectangles_set(pwin, rects, num);
if ((!ec->shaped) && (!ec->bordername))
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
}
ec->shaped = 1;
ec->changes.shape_input = 0;
E_FREE(ec->shape_input_rects);
ec->shape_input_rects_num = 0;
}
free(rects);
}
else
{
// FIXME: no rects i think can mean... totally empty window
if (ec->shaped && ec->comp_data->reparented && (!ec->bordername))
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
ec->shaped = 0;
}
if (ec->shaped != pshaped)
{
_e_comp_x_client_shape_input_rectangle_set(ec);
if ((!ec->shaped) && ec->comp_data->reparented)
ecore_x_window_shape_mask_set(pwin, 0);
}
ec->need_shape_merge = 1;
}
if (ec->changes.shape_input)
{
Ecore_X_Rectangle *rects;
Eina_Bool pshaped = ec->shaped_input, changed = EINA_FALSE;
int num;
ec->changes.shape_input = 0;
rects = ecore_x_window_shape_input_rectangles_get(win, &num);
if (rects)
{
int cw = 0, ch = 0;
/* This doesn't fix the race, but makes it smaller. we detect
* this and if cw and ch != client w/h then mark this as needing
* a shape change again to fixup next event loop.
*/
ecore_x_window_size_get(win, &cw, &ch);
/* normalize for client window dead zone */
if (ec->border_size && (num == 1))
{
rects[0].x += ec->border_size;
rects[0].y += ec->border_size;
rects[0].width -= ec->border_size;
rects[0].height -= ec->border_size;
}
if ((cw != ec->client.w) || (ch != ec->client.h))
ec->changes.shape_input = 1;
if (num == 1)
E_RECTS_CLIP_TO_RECT(rects[0].x, rects[0].y, rects[0].width, rects[0].height, 0, 0, cw, ch);
if ((num == 1) &&
(rects[0].x == 0) &&
(rects[0].y == 0) &&
((int)rects[0].width == cw) &&
((int)rects[0].height == ch))
{
if (ec->shaped_input)
{
ec->shaped_input = 0;
if (ec->comp_data->reparented && (!ec->bordername))
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
}
free(rects);
}
else
{
if (!ec->shaped_input)
{
ec->shaped_input = 1;
if (ec->comp_data->reparented && (!ec->bordername))
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
}
if (ec->comp_data->reparented)
ecore_x_window_shape_input_rectangles_set(pwin, rects, num);
changed = EINA_TRUE;
free(ec->shape_input_rects);
ec->shape_input_rects = (Eina_Rectangle*)rects;
ec->shape_input_rects_num = num;
}
}
else
{
ec->shaped_input = 1;
if (ec->comp_data->reparented && (!ec->bordername))
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
}
if (changed || (pshaped != ec->shaped_input))
ec->need_shape_merge = 1;
}
if (ec->changes.prop || ec->mwm.fetch.hints)
{
int pb;
ec->mwm.exists =
ecore_x_mwm_hints_get(win,
&ec->mwm.func,
&ec->mwm.decor,
&ec->mwm.input);
pb = ec->mwm.borderless;
ec->mwm.borderless = 0;
if (ec->mwm.exists)
{
if ((!(ec->mwm.decor & ECORE_X_MWM_HINT_DECOR_ALL)) &&
(!(ec->mwm.decor & ECORE_X_MWM_HINT_DECOR_TITLE)) &&
(!(ec->mwm.decor & ECORE_X_MWM_HINT_DECOR_BORDER)))
ec->mwm.borderless = 1;
}
if (ec->mwm.borderless != pb)
{
if (ec->comp_data->reparented && ((!ec->lock_border) || (!ec->border.name)))
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
}
ec->mwm.fetch.hints = 0;
rem_change = 1;
}
if (ec->e.fetch.video_parent)
{
/* unlinking child/parent */
if (ec->e.state.video_parent_client != NULL)
{
ec->e.state.video_parent_client->e.state.video_child =
eina_list_remove(ec->e.state.video_parent_client->e.state.video_child, ec);
}
ecore_x_window_prop_card32_get(win,
ECORE_X_ATOM_E_VIDEO_PARENT,
(Ecore_X_Window*)&ec->e.state.video_parent, 1);
/* linking child/parent */
if (ec->e.state.video_parent != 0)
{
E_Client *tmp;
tmp = _e_comp_x_client_find_by_window(ec->e.state.video_parent);
if (tmp)
{
/* fprintf(stderr, "child added to parent \\o/\n"); */
ec->e.state.video_parent_client = tmp;
tmp->e.state.video_child = eina_list_append(tmp->e.state.video_child, ec);
if (ec->desk != tmp->desk)
e_client_desk_set(ec, tmp->desk);
}
}
/* fprintf(stderr, "new parent %x => %p\n", ec->e.state.video_parent, ec->e.state.video_parent_client); */
if (ec->e.state.video_parent_client) ec->e.fetch.video_parent = 0;
rem_change = 1;
}
if (ec->e.fetch.video_position && ec->e.fetch.video_parent == 0)
{
unsigned int xy[2];
ecore_x_window_prop_card32_get(win,
ECORE_X_ATOM_E_VIDEO_POSITION,
xy, 2);
ec->e.state.video_position.x = xy[0];
ec->e.state.video_position.y = xy[1];
ec->e.state.video_position.updated = 1;
ec->e.fetch.video_position = 0;
ec->x = ec->e.state.video_position.x;
ec->y = ec->e.state.video_position.y;
fprintf(stderr, "internal position has been updated [%i, %i]\n", ec->e.state.video_position.x, ec->e.state.video_position.y);
}
if (ec->changes.prop || ec->netwm.update.state)
{
e_hints_window_state_set(ec);
/* Some stats might change the border, like modal */
if (((!ec->lock_border) || (!ec->border.name)) &&
(!(((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN))) &&
ec->comp_data->reparented)
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
if (ec->parent)
{
if (ec->netwm.state.modal)
{
ec->parent->modal = ec;
if (ec->parent->focused)
evas_object_focus_set(ec->frame, 1);
}
}
else if (ec->leader)
{
if (ec->netwm.state.modal)
{
ec->leader->modal = ec;
if (ec->leader->focused)
evas_object_focus_set(ec->frame, 1);
else
{
Eina_List *l;
E_Client *child;
EINA_LIST_FOREACH(ec->leader->group, l, child)
{
if ((child != ec) && (child->focused))
evas_object_focus_set(ec->frame, 1);
}
}
}
}
ec->netwm.update.state = 0;
}
if ((e_config->use_desktop_window_profile) && (need_desk_set))
{
if (!(ec->e.state.profile.name) &&
(ec->e.state.profile.num >= 1))
{
const char *p = NULL;
int i;
for (i = 0; i < ec->e.state.profile.num; i++)
{
if (!ec->e.state.profile.available_list[i])
continue;
p = ec->e.state.profile.available_list[i];
if (strcmp(ec->desk->window_profile, p) == 0)
{
ec->e.state.profile.name = eina_stringshare_add(ec->desk->window_profile);
break;
}
}
if (!ec->e.state.profile.name)
{
E_Comp *c = ec->comp;
E_Desk *desk = NULL;
for (i = 0; i < ec->e.state.profile.num; i++)
{
if (!ec->e.state.profile.available_list[i])
continue;
p = ec->e.state.profile.available_list[i];
desk = e_comp_desk_window_profile_get(c, p);
if ((desk) && (ec->desk != desk))
{
ec->e.state.profile.name = eina_stringshare_add(p);
break;
}
}
}
}
if (!ec->e.state.profile.name)
{
ec->e.state.profile.name = eina_stringshare_add(ec->desk->window_profile);
}
ecore_x_e_window_profile_change_request_send(win,
ec->e.state.profile.name);
ec->e.state.profile.wait_for_done = 1;
}
if (ec->comp_data->fetch_exe)
{
E_Exec_Instance *inst;
if (((!ec->lock_border) || (!ec->border.name)) && (ec->comp_data->reparented))
{
ec->border.changed = 1;
EC_CHANGED(ec);
}
{
char *str = NULL;
if ((!ec->internal) &&
((ecore_x_netwm_startup_id_get(win, &str) && (str)) ||
((ec->icccm.client_leader > 0) &&
ecore_x_netwm_startup_id_get(ec->icccm.client_leader, &str) && (str)))
)
{
if (!strncmp(str, "E_START|", 8))
{
int id;
id = atoi(str + 8);
if (id > 0) ec->netwm.startup_id = id;
}
free(str);
}
}
/* It's ok not to have fetch flag, should only be set on startup
* * and not changed. */
if (!ecore_x_netwm_pid_get(win, &ec->netwm.pid))
{
if (ec->icccm.client_leader)
{
if (!ecore_x_netwm_pid_get(ec->icccm.client_leader, &ec->netwm.pid))
ec->netwm.pid = -1;
}
else
ec->netwm.pid = -1;
}
if (!e_client_util_ignored_get(ec))
{
inst = e_exec_startup_id_pid_instance_find(ec->netwm.startup_id,
ec->netwm.pid);
if (inst)
{
Eina_Bool found;
if (inst->used == 0)
{
E_Zone *zone;
E_Desk *desk;
inst->used++;
zone = e_comp_zone_number_get(ec->comp, inst->screen);
if (zone) e_client_zone_set(ec, zone);
desk = e_desk_at_xy_get(ec->zone, inst->desk_x,
inst->desk_y);
if (desk) e_client_desk_set(ec, desk);
if (ec->netwm.pid != ecore_exe_pid_get(inst->exe))
{
/* most likely what has happened here is that the .desktop launcher
* has spawned a process which then created this border, meaning the
* E_Exec instance will be deleted in a moment, and we will be unable to track it.
* to prevent this, we convert our instance to a phony
*/
inst->phony = 1;
}
}
found = !!inst->clients;
e_exec_instance_client_add(inst, ec);
if (!found)
e_exec_instance_found(inst);
}
if (e_config->window_grouping) // FIXME: We may want to make the border "urgent" so that the user knows it appeared.
{
E_Client *ecl = NULL;
ecl = ec->parent;
if (!ecl)
ecl = ec->leader;
if (!ecl)
{
E_Client *child = e_client_bottom_get(ec->comp);
do
{
if (child == ec) continue;
if (e_object_is_del(E_OBJECT(child))) continue;
if ((ec->icccm.client_leader) &&
(child->icccm.client_leader ==
ec->icccm.client_leader))
{
ecl = child;
break;
}
child = e_client_above_get(child);
} while (child);
}
if (ecl)
{
if (ecl->zone)
e_client_zone_set(ec, ecl->zone);
if (ecl->desk)
e_client_desk_set(ec, ecl->desk);
else
e_client_stick(ec);
}
}
}
ec->comp_data->fetch_exe = 0;
}
ec->changes.prop = 0;
if (rem_change) e_remember_update(ec);
if (!ec->comp_data->reparented) ec->changes.border = 0;
if (ec->changes.icon)
{
/* don't create an icon until we need it */
if (ec->comp_data->reparented) return;
ec->comp_data->change_icon = 1;
ec->changes.icon = 0;
}
}
static void
_e_comp_x_hook_client_new(void *d EINA_UNUSED, E_Client *ec)
{
Ecore_X_Window win;
E_COMP_X_PIXMAP_CHECK;
win = e_pixmap_window_get(ec->pixmap);
ec->ignored = e_comp_ignore_win_find(win);
ec->comp_data = E_NEW(E_Comp_Client_Data, 1);
ec->comp_data->set_win_type = ec->comp_data->fetch_exe = 1;
/* FIXME: ewww - round trip */
ec->argb = ecore_x_window_argb_get(win);
ec->changes.shape = 1;
ec->changes.shape_input = 1;
ec->netwm.type = E_WINDOW_TYPE_UNKNOWN;
ec->icccm.state = ECORE_X_WINDOW_STATE_HINT_NONE;
if (!_e_comp_x_client_new_helper(ec)) return;
eina_hash_add(clients_win_hash, &win, ec);
e_hints_client_list_set();
}
static void
_e_comp_x_hook_client_focus_unset(void *d EINA_UNUSED, E_Client *ec)
{
E_COMP_X_PIXMAP_CHECK;
_e_comp_x_focus_check(ec->comp);
}
static void
_e_comp_x_hook_client_focus_set(void *d EINA_UNUSED, E_Client *ec)
{
focus_time = ecore_x_current_time_get();
if ((e_pixmap_type_get(ec->pixmap) != E_PIXMAP_TYPE_X))
{
e_grabinput_focus(ec->comp->ee_win, E_FOCUS_METHOD_PASSIVE);
return;
}
if ((ec->icccm.take_focus) && (ec->icccm.accepts_focus))
{
e_grabinput_focus(e_client_util_win_get(ec), E_FOCUS_METHOD_LOCALLY_ACTIVE);
/* TODO what if the client didn't take focus ? */
}
else if (!ec->icccm.accepts_focus)
{
e_grabinput_focus(e_client_util_win_get(ec), E_FOCUS_METHOD_GLOBALLY_ACTIVE);
}
else if (!ec->icccm.take_focus)
{
e_grabinput_focus(e_client_util_win_get(ec), E_FOCUS_METHOD_PASSIVE);
}
}
static void
_e_comp_x_hook_client_redirect(void *d EINA_UNUSED, E_Client *ec)
{
E_COMP_X_PIXMAP_CHECK;
if (ec->comp->nocomp)
{
/* first window */
ec->comp->nocomp = 0;
ecore_x_composite_redirect_subwindows(ec->comp->man->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
ecore_x_window_show(ec->comp->win);
}
if (!ec->comp_data->damage)
_e_comp_x_client_damage_add(ec);
}
static void
_e_comp_x_hook_client_unredirect(void *d EINA_UNUSED, E_Client *ec)
{
Ecore_X_Region parts;
E_COMP_X_PIXMAP_CHECK;
eina_hash_del(damages_hash, &ec->comp_data->damage, ec);
parts = ecore_x_region_new(NULL, 0);
ecore_x_damage_subtract(ec->comp_data->damage, 0, parts);
ecore_x_region_free(parts);
ecore_x_damage_free(ec->comp_data->damage);
ec->comp_data->damage = 0;
if (!ec->comp->nocomp) return; //wait for it...
ecore_x_composite_unredirect_subwindows(ec->comp->man->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
ecore_x_window_hide(ec->comp->win);
}
static void
_e_comp_x_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
{
Ecore_X_Window win;
unsigned int visible = 0;
E_COMP_X_PIXMAP_CHECK;
win = e_client_util_win_get(ec);
if ((!stopping) && (!ec->comp_data->deleted))
ecore_x_window_prop_card32_set(e_client_util_win_get(ec), E_ATOM_MANAGED, &visible, 1);
if ((!ec->already_unparented) && ec->comp_data->reparented)
{
e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
_e_comp_x_focus_setdown(ec);
if (!ec->comp_data->deleted)
{
if (stopping)
ecore_x_window_reparent(win, ec->comp->man->root,
ec->client.x, ec->client.y);
else
/* put the window back where we found it to prevent annoying dancing windows */
ecore_x_window_reparent(win, ec->comp->man->root,
ec->comp_data->initial_attributes.x,
ec->comp_data->initial_attributes.y);
if (!ec->internal)
ecore_x_window_save_set_del(win);
}
}
ec->already_unparented = 1;
eina_hash_del_by_key(clients_win_hash, &win);
if (ec->comp_data->damage)
{
eina_hash_del(damages_hash, &ec->comp_data->damage, ec);
ecore_x_damage_free(ec->comp_data->damage);
}
if (ec->comp_data->reparented)
{
win = e_client_util_pwin_get(ec);
eina_hash_del_by_key(clients_win_hash, &win);
e_pixmap_parent_window_set(ec->pixmap, 0);
ecore_x_window_free(win);
}
if (ec->hacks.mapping_change)
_e_comp_x_mapping_change_disabled--;
if (ec->parent && (ec->parent->modal == ec))
{
if (ec->parent->comp_data->lock_win)
{
eina_hash_del_by_key(clients_win_hash, &ec->parent->comp_data->lock_win);
ecore_x_window_hide(ec->parent->comp_data->lock_win);
ecore_x_window_free(ec->parent->comp_data->lock_win);
ec->parent->comp_data->lock_win = 0;
}
ec->parent->lock_close = 0;
ec->parent->modal = NULL;
}
E_FREE(ec->comp_data);
if (post_clients)
post_clients = eina_list_remove(post_clients, ec);
_e_comp_x_focus_check(ec->comp);
}
static void
_e_comp_x_hook_client_move_end(void *d EINA_UNUSED, E_Client *ec)
{
E_COMP_X_PIXMAP_CHECK;
ec->comp_data->moving = 0;
if (!ec->comp_data->move_counter) return;
ec->comp_data->move_counter = 0;
ec->post_move = 1;
_e_comp_x_post_client_idler_add(ec);
}
static void
_e_comp_x_hook_client_move_begin(void *d EINA_UNUSED, E_Client *ec)
{
E_COMP_X_PIXMAP_CHECK;
ec->comp_data->moving = 1;
}
static void
_e_comp_x_hook_client_resize_end(void *d EINA_UNUSED, E_Client *ec)
{
E_COMP_X_PIXMAP_CHECK;
if (!ec->comp_data->alarm) return;
eina_hash_del_by_key(alarm_hash, &ec->comp_data->alarm);
ecore_x_sync_alarm_free(ec->comp_data->alarm);
ec->comp_data->alarm = 0;
ec->netwm.sync.alarm = 0;
/* resize to last geometry if sync alarm for it was not yet handled */
if (ec->pending_resize)
{
EC_CHANGED(ec);
ec->changes.pos = 1;
ec->changes.size = 1;
}
E_FREE_LIST(ec->pending_resize, free);
}
static void
_e_comp_x_hook_client_resize_begin(void *d EINA_UNUSED, E_Client *ec)
{
E_COMP_X_PIXMAP_CHECK;
if (!ec->netwm.sync.request) return;
ec->netwm.sync.alarm = ecore_x_sync_alarm_new(ec->comp_data->sync_counter);
eina_hash_add(alarm_hash, &ec->comp_data->alarm, ec);
ec->netwm.sync.alarm = ec->netwm.sync.serial = 1;
ec->netwm.sync.wait = 0;
ec->netwm.sync.send_time = ecore_loop_time_get();
}
static void
_e_comp_x_hook_client_desk_set(void *d EINA_UNUSED, E_Client *ec)
{
unsigned int num[2];
int x, y;
E_COMP_X_PIXMAP_CHECK;
e_desk_xy_get(ec->desk, &x, &y);
num[0] = x, num[1] = y;
ecore_x_window_prop_card32_set(e_client_util_win_get(ec), E_ATOM_DESK, num, 2);
}
static Eina_Bool
_e_comp_x_cb_ping(void *data EINA_UNUSED, int ev_type EINA_UNUSED, Ecore_X_Event_Ping *ev)
{
E_Client *ec;
ec = _e_comp_x_client_find_by_window(ev->event_win);
if (ec) ec->ping_ok = 1;
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_screensaver_idle_timer_cb(void *d __UNUSED__)
{
ecore_event_add(E_EVENT_SCREENSAVER_ON, NULL, NULL, NULL);
screensaver_idle_timer = NULL;
return EINA_FALSE;
}
static Eina_Bool
_e_comp_x_screensaver_notify_cb(void *data __UNUSED__, int type __UNUSED__, Ecore_X_Event_Screensaver_Notify *ev)
{
static Eina_Bool saver_on = EINA_FALSE;
if ((ev->on) && (!saver_on))
{
saver_on = EINA_TRUE;
if (e_config->backlight.idle_dim)
{
double t = e_config->screensaver_timeout -
e_config->backlight.timer;
if (t < 1.0) t = 1.0;
E_FREE_FUNC(screensaver_idle_timer, ecore_timer_del);
if (e_config->screensaver_enable)
screensaver_idle_timer = ecore_timer_add
(t, _e_comp_x_screensaver_idle_timer_cb, NULL);
if (e_backlight_mode_get(NULL) != E_BACKLIGHT_MODE_DIM)
{
e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_DIM);
screensaver_dimmed = EINA_TRUE;
}
}
else
{
if (!e_screensaver_on_get())
ecore_event_add(E_EVENT_SCREENSAVER_ON, NULL, NULL, NULL);
}
}
else if ((!ev->on) && (saver_on))
{
saver_on = EINA_FALSE;
if (screensaver_idle_timer)
{
E_FREE_FUNC(screensaver_idle_timer, ecore_timer_del);
if (e_config->backlight.idle_dim)
{
if (e_backlight_mode_get(NULL) != E_BACKLIGHT_MODE_NORMAL)
e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_NORMAL);
}
}
else
{
if (screensaver_dimmed)
{
if (e_backlight_mode_get(NULL) != E_BACKLIGHT_MODE_NORMAL)
e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_NORMAL);
screensaver_dimmed = EINA_FALSE;
}
if (e_screensaver_on_get())
ecore_event_add(E_EVENT_SCREENSAVER_OFF, NULL, NULL, NULL);
}
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_comp_x_cb_frame_extents_request(void *data EINA_UNUSED, int ev_type EINA_UNUSED, Ecore_X_Event_Frame_Extents_Request *ev)
{
E_Manager *man;
Ecore_X_Window_Type type;
Ecore_X_MWM_Hint_Decor decor;
Ecore_X_Window_State *state;
Ecore_X_Window win;
Frame_Extents *extents;
const char *border, *sig, *key;
int ok;
unsigned int i, num;
win = ecore_x_window_parent_get(ev->win);
man = e_manager_find_by_root(win);
if (!man) return ECORE_CALLBACK_PASS_ON;
/* TODO:
* * We need to check if we remember this window, and border locking is set
*/
border = "default";
key = border;
ok = ecore_x_mwm_hints_get(ev->win, NULL, &decor, NULL);
if ((ok) &&
(!(decor & ECORE_X_MWM_HINT_DECOR_ALL)) &&
(!(decor & ECORE_X_MWM_HINT_DECOR_TITLE)) &&
(!(decor & ECORE_X_MWM_HINT_DECOR_BORDER)))
{
border = "borderless";
key = border;
}
ok = ecore_x_netwm_window_type_get(ev->win, &type);
if ((ok) &&
((type == ECORE_X_WINDOW_TYPE_DESKTOP) ||
(type == ECORE_X_WINDOW_TYPE_DOCK)))
{
border = "borderless";
key = border;
}
sig = NULL;
ecore_x_netwm_window_state_get(ev->win, &state, &num);
if (state)
{
int maximized = 0;
for (i = 0; i < num; i++)
{
switch (state[i])
{
case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT:
maximized++;
break;
case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ:
maximized++;
break;
case ECORE_X_WINDOW_STATE_FULLSCREEN:
border = "borderless";
key = border;
break;
case ECORE_X_WINDOW_STATE_SHADED:
case ECORE_X_WINDOW_STATE_SKIP_TASKBAR:
case ECORE_X_WINDOW_STATE_SKIP_PAGER:
case ECORE_X_WINDOW_STATE_HIDDEN:
case ECORE_X_WINDOW_STATE_ICONIFIED:
case ECORE_X_WINDOW_STATE_MODAL:
case ECORE_X_WINDOW_STATE_STICKY:
case ECORE_X_WINDOW_STATE_ABOVE:
case ECORE_X_WINDOW_STATE_BELOW:
case ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION:
case ECORE_X_WINDOW_STATE_UNKNOWN:
break;
}
}
if ((maximized == 2) &&
(e_config->maximize_policy == E_MAXIMIZE_FULLSCREEN))
{
sig = "ev,action,maximize,fullscreen";
key = "maximize,fullscreen";
}
free(state);
}
extents = eina_hash_find(frame_extents, key);
if (!extents)
{
Evas_Object *o;
char buf[1024];
extents = E_NEW(Frame_Extents, 1);
if (!extents) return ECORE_CALLBACK_RENEW;
o = edje_object_add(man->comp->evas);
snprintf(buf, sizeof(buf), "ev/widgets/border/%s/border", border);
ok = e_theme_edje_object_set(o, "base/theme/borders", buf);
if (ok)
{
Evas_Coord x, y, w, h;
if (sig)
{
edje_object_signal_emit(o, sig, "ev");
edje_object_message_signal_process(o);
}
evas_object_resize(o, 1000, 1000);
edje_object_calc_force(o);
edje_object_part_geometry_get(o, "ev.swallow.client",
&x, &y, &w, &h);
extents->l = x;
extents->r = 1000 - (x + w);
extents->t = y;
extents->b = 1000 - (y + h);
}
else
{
extents->l = 0;
extents->r = 0;
extents->t = 0;
extents->b = 0;
}
evas_object_del(o);
eina_hash_add(frame_extents, key, extents);
}
if (extents)
ecore_x_netwm_frame_size_set(ev->win, extents->l, extents->r, extents->t, extents->b);
return ECORE_CALLBACK_RENEW;
}
static void
_e_comp_x_pre_swap(void *data, Evas *e EINA_UNUSED)
{
E_Comp *c = data;
if (!e_comp_config_get()->grab) return;
if (!c->grabbed) return;
ecore_x_ungrab();
c->grabbed = 0;
}
static Eina_Bool
_e_comp_x_xinerama_setup(int rw, int rh)
{
int n, i;
E_Screen *screen;
Eina_List *all_screens = NULL;
/* first (and only) root window */
/* get number of xinerama screens */
n = ecore_x_xinerama_screen_count_get();
if (n < 2)
{
screen = E_NEW(E_Screen, 1);
screen->escreen = screen->screen = 0;
screen->x = 0;
screen->y = 0;
screen->w = rw;
screen->h = rh;
all_screens = eina_list_append(all_screens, screen);
}
else
{
for (i = 0; i < n; i++)
{
int x, y, w, h;
/* get each xinerama screen geometry */
if (ecore_x_xinerama_screen_geometry_get(i, &x, &y, &w, &h))
{
INF("E19 INIT: XINERAMA SCREEN: [%i][%i], %ix%i+%i+%i",
i, i, w, h, x, y);
/* add it to our list */
screen = E_NEW(E_Screen, 1);
screen->escreen = screen->screen = i;
screen->x = x;
screen->y = y;
screen->w = w;
screen->h = h;
all_screens = eina_list_append(all_screens, screen);
}
}
}
e_xinerama_screens_set(all_screens);
return EINA_TRUE;
}
static void
_e_comp_x_ee_resize(Ecore_Evas *ee)
{
E_Client *ec;
E_Comp *c = ecore_evas_data_get(ee, "comp");
ecore_x_netwm_desk_size_set(c->man->root, c->man->w, c->man->h);
_e_comp_x_xinerama_setup(c->man->w, c->man->h);
e_comp_canvas_update(c);
ec = e_client_bottom_get(c);
while (ec)
{
_e_comp_x_client_zone_geometry_set(ec);
ec = e_client_above_get(ec);
}
}
static void
_e_comp_x_del(E_Comp *c)
{
unsigned int i;
ecore_x_window_key_ungrab(c->man->root, "F", ECORE_EVENT_MODIFIER_SHIFT |
ECORE_EVENT_MODIFIER_CTRL |
ECORE_EVENT_MODIFIER_ALT, 0);
ecore_x_window_key_ungrab(c->man->root, "Home", ECORE_EVENT_MODIFIER_SHIFT |
ECORE_EVENT_MODIFIER_CTRL |
ECORE_EVENT_MODIFIER_ALT, 0);
if (c->grabbed)
{
c->grabbed = 0;
ecore_x_ungrab();
}
for (i = e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); i <= e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); i++)
ecore_x_window_free(c->layers[i].win);
ecore_x_composite_unredirect_subwindows
(c->man->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
if (c->block_win) ecore_x_window_free(c->block_win);
ecore_x_composite_render_window_disable(c->win);
if (c->man->num == 0) e_alert_composite_win(c->man->root, 0);
ecore_x_window_free(c->cm_selection);
ecore_x_screen_is_composited_set(c->man->num, 0);
free(c->comp_data);
}
static void
_e_comp_x_manage_windows(E_Comp *c)
{
E_Manager *man = c->man;
Ecore_X_Window *windows;
int wnum;
int i;
const char *atom_names[] =
{
"_XEMBED_INFO",
"_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
"KWM_DOCKWINDOW"
};
Ecore_X_Atom atoms[3];
Ecore_X_Atom atom_xmbed, atom_kde_netwm_systray, atom_kwm_dockwindow;
int count;
/* a manager is designated for each root. lets get all the windows in
the managers root */
windows = ecore_x_window_children_get(man->root, &wnum);
if (!windows) return;
ecore_x_atoms_get(atom_names, 3, atoms);
atom_xmbed = atoms[0];
atom_kde_netwm_systray = atoms[1];
atom_kwm_dockwindow = atoms[2];
for (i = 0; i < wnum; i++)
{
unsigned int ret_val, deskxy[2];
unsigned char *data = NULL;
int ret;
E_Client *ec = NULL;
if ((c->win == windows[i]) || (c->ee_win == windows[i]) ||
(c->man->root == windows[i]) || (c->cm_selection == windows[i]))
continue;
if (_e_comp_x_client_find_by_window(windows[i]))
continue;
if (!ecore_x_window_prop_property_get(windows[i],
atom_kde_netwm_systray,
atom_xmbed, 32,
&data, &count))
data = NULL;
if (!data)
{
if (!ecore_x_window_prop_property_get(windows[i],
atom_kwm_dockwindow,
atom_kwm_dockwindow, 32,
&data, &count))
data = NULL;
}
if (data)
{
E_FREE(data);
continue;
}
ret = ecore_x_window_prop_card32_get(windows[i],
E_ATOM_MANAGED,
&ret_val, 1);
/* we have seen this window before */
if ((ret > -1) && (ret_val == 1))
{
E_Zone *zone = NULL;
E_Desk *desk = NULL;
unsigned int id;
char *path;
Efreet_Desktop *desktop = NULL;
/* get all information from window before it is
* reset by e_client_new */
ret = ecore_x_window_prop_card32_get(windows[i],
E_ATOM_ZONE,
&id, 1);
if (ret == 1)
zone = e_comp_zone_number_get(c, id);
if (!zone)
zone = e_zone_current_get(c);
ret = ecore_x_window_prop_card32_get(windows[i],
E_ATOM_DESK,
deskxy, 2);
if (ret == 2)
desk = e_desk_at_xy_get(zone,
deskxy[0],
deskxy[1]);
path = ecore_x_window_prop_string_get(windows[i],
E_ATOM_DESKTOP_FILE);
if (path)
{
desktop = efreet_desktop_get(path);
free(path);
}
{
ec = _e_comp_x_client_new(c, windows[i], 1);
if (ec)
{
if (desk) e_client_desk_set(ec, desk);
ec->desktop = desktop;
}
}
}
else
{
/* We have not seen this window, and X tells us it
* should be seen */
ec = _e_comp_x_client_new(c, windows[i], 1);
}
if (ec && (!ec->comp_data->initial_attributes.visible))
E_FREE_FUNC(ec, e_object_del);
if (ec)
{
if (ec->override)
{
_e_comp_x_client_evas_init(ec);
if (!ec->input_only)
_e_comp_x_client_damage_add(ec);
e_pixmap_usable_set(ec->pixmap, 1);
ec->comp_data->first_map = 1;
}
ec->ignore_first_unmap = 1;
evas_object_show(ec->frame);
}
}
free(windows);
}
static void
_e_comp_x_bindings_grab_cb(E_Comp *c)
{
Eina_List *l;
E_Client *ec;
EINA_LIST_FOREACH(c->clients, l, ec)
{
if (e_client_util_ignored_get(ec)) continue;
_e_comp_x_focus_setup(ec);
e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
}
}
static void
_e_comp_x_bindings_ungrab_cb(E_Comp *c)
{
Eina_List *l;
E_Client *ec;
EINA_LIST_FOREACH(c->clients, l, ec)
{
if (e_client_util_ignored_get(ec)) continue;
_e_comp_x_focus_setdown(ec);
e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
}
}
static void
_e_comp_x_grab_cb(E_Comp *c)
{
if (!c->grabbed)
{
ecore_x_grab();
ecore_x_sync();
}
else
ecore_x_ungrab();
}
static Eina_Bool
_e_comp_x_setup(E_Comp *c, Ecore_X_Window root, int w, int h)
{
Ecore_X_Window_Attributes att;
Eina_Bool res;
unsigned int i;
res = ecore_x_screen_is_composited(c->num);
if (res)
{
e_util_dialog_internal(_("Compositor Error"),
_("Another compositor is already running<br>"
"on your display server."));
return EINA_FALSE;
}
if (!ecore_x_window_manage(root)) return EINA_FALSE;
E_OBJECT_DEL_SET(c, _e_comp_x_del);
c->comp_data = E_NEW(E_Comp_Data, 1);
ecore_x_e_window_profile_supported_set(root, e_config->use_desktop_window_profile);
c->cm_selection = ecore_x_window_input_new(root, 0, 0, 1, 1);
if (!c->cm_selection) return EINA_FALSE;
ecore_x_icccm_name_class_set(c->cm_selection, "comp", "cm_selection");
e_comp_ignore_win_add(E_PIXMAP_TYPE_X, c->cm_selection);
e_hints_init(root, c->cm_selection);
ecore_x_window_background_color_set(root, 0, 0, 0);
ecore_x_screen_is_composited_set(c->num, c->cm_selection);
c->win = ecore_x_composite_render_window_enable(root);
if (!c->win)
{
e_util_dialog_internal(_("Compositor Error"),
_("Your display server does not support the<br>"
"compositor overlay window. This is needed<br>"
"for it to function."));
return EINA_FALSE;
}
c->man = e_manager_new(root, c, w, h);
memset((&att), 0, sizeof(Ecore_X_Window_Attributes));
ecore_x_window_attributes_get(c->win, &att);
if ((att.depth != 24) && (att.depth != 32))
{
/*
e_util_dialog_internal
(_("Compositor Error"), _("Your screen is not in 24/32bit display mode.<br>"
"This is required to be your default depth<br>"
"setting for the compositor to work properly."));
ecore_x_composite_render_window_disable(c->win);
free(c);
return NULL;
*/
}
c->depth = att.depth;
if (!c->num) e_alert_composite_win(root, c->win);
if (e_comp_gl_get() && (e_comp_config_get()->engine == E_COMP_ENGINE_GL))
{
int opt[20];
int opt_i = 0;
if (e_comp_config_get()->indirect)
{
opt[opt_i] = ECORE_EVAS_GL_X11_OPT_INDIRECT;
opt_i++;
opt[opt_i] = 1;
opt_i++;
}
if (e_comp_config_get()->vsync)
{
opt[opt_i] = ECORE_EVAS_GL_X11_OPT_VSYNC;
opt_i++;
opt[opt_i] = 1;
opt_i++;
}
#ifdef ECORE_EVAS_GL_X11_OPT_SWAP_MODE
if (e_comp_config_get()->swap_mode)
{
opt[opt_i] = ECORE_EVAS_GL_X11_OPT_SWAP_MODE;
opt_i++;
opt[opt_i] = e_comp_config_get()->swap_mode;
opt_i++;
}
#endif
if (opt_i > 0)
{
opt[opt_i] = ECORE_EVAS_GL_X11_OPT_NONE;
c->ee = ecore_evas_gl_x11_options_new(NULL, c->win, 0, 0, w, h, opt);
}
if (!c->ee)
c->ee = ecore_evas_gl_x11_new(NULL, c->win, 0, 0, w, h);
if (c->ee)
{
c->gl = 1;
ecore_evas_gl_x11_pre_post_swap_callback_set(c->ee, c, _e_comp_x_pre_swap, NULL);
}
}
if (!c->ee)
{
c->ee = ecore_evas_software_x11_new(NULL, c->win, 0, 0, w, h);
if (e_comp_config_get()->engine == E_COMP_ENGINE_GL)
ecore_job_add(_e_comp_x_add_fail_job, NULL);
e_comp_gl_set(0);
}
ecore_x_composite_redirect_subwindows(root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
ecore_x_window_key_grab(root, "Home", ECORE_EVENT_MODIFIER_SHIFT |
ECORE_EVENT_MODIFIER_CTRL |
ECORE_EVENT_MODIFIER_ALT, 0);
ecore_x_window_key_grab(root, "F", ECORE_EVENT_MODIFIER_SHIFT |
ECORE_EVENT_MODIFIER_CTRL |
ECORE_EVENT_MODIFIER_ALT, 0);
ecore_evas_callback_resize_set(c->ee, _e_comp_x_ee_resize);
ecore_evas_data_set(c->ee, "comp", c);
c->grab_cb = (Ecore_Cb)_e_comp_x_grab_cb;
c->bindings_grab_cb = (Ecore_Cb)_e_comp_x_bindings_grab_cb;
c->bindings_ungrab_cb = (Ecore_Cb)_e_comp_x_bindings_ungrab_cb;
if (!e_comp_canvas_init(c)) return EINA_FALSE;
e_grabinput_focus(c->ee_win, E_FOCUS_METHOD_PASSIVE);
/* init layers */
for (i = e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); i <= e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); i++)
{
char buf[64];
c->layers[i].win = ecore_x_window_input_new(root, 0, 0, 1, 1);
ecore_x_window_show(c->layers[i].win);
snprintf(buf, sizeof(buf), "%d", e_comp_canvas_layer_map_to(i));
ecore_x_icccm_name_class_set(c->layers[i].win, buf, "e_layer_win");
if (i - e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP) > 0)
ecore_x_window_configure(c->layers[i].win,
ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
0, 0, 0, 0, 0,
c->layers[i - 1].win, ECORE_X_WINDOW_STACK_ABOVE);
else
ecore_x_window_raise(c->layers[i].win);
}
ecore_evas_lower(c->ee);
_e_comp_x_manage_windows(c);
return !!c->bg_blank_object;
}
static Eina_Bool
_e_comp_x_screens_setup(void)
{
int n, i;
Ecore_X_Window *roots;
Eina_Bool success = EINA_FALSE;
roots = ecore_x_window_root_list(&n);
if ((!roots) || (n <= 0))
{
free(roots);
e_error_message_show("X reports there are no root windows and %i screens!\n",
n);
return 0;
}
for (i = 0; i < n; i++)
{
int rw, rh;
Ecore_X_Window root = roots[i];
E_Comp *c;
ecore_x_window_size_get(root, &rw, &rh);
if (n == 1)
{
/* more than 1 root window - xinerama wont be active */
success = _e_comp_x_xinerama_setup(rw, rh);
if (!success) break;
}
if (!success) break;
c = e_comp_new();
c->comp_type = E_PIXMAP_TYPE_X;
success = _e_comp_x_setup(c, root, rw, rh);
if (!success) break;
}
free(roots);
return success;
}
EINTERN Eina_Bool
e_comp_x_init(void)
{
clients_win_hash = eina_hash_int32_new(NULL);
damages_hash = eina_hash_int32_new(NULL);
alarm_hash = eina_hash_int32_new(NULL);
frame_extents = eina_hash_string_superfast_new(free);
if (!ecore_x_init(NULL))
{
e_error_message_show(_("Enlightenment cannot initialize Ecore_X!\n"));
return EINA_FALSE;
}
ecore_x_io_error_handler_set(_e_main_cb_x_fatal, NULL);
if (!ecore_x_composite_query())
{
e_error_message_show
(_("Your display server does not support XComposite, "
"or Ecore-X was built without XComposite support. "
"Note that for composite support you will also need "
"XRender and XFixes support in X11 and Ecore."));
return EINA_FALSE;
}
if (!ecore_x_damage_query())
{
e_error_message_show
(_("Your display server does not support XDamage "
"or Ecore was built without XDamage support."));
return EINA_FALSE;
}
if (!getenv("ECORE_X_NO_XLIB"))
{
if (ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_OPENGL_X11))
e_comp_gl_set(EINA_TRUE);
}
ecore_x_screensaver_event_listen_set(1);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_DESTROY, _e_comp_x_destroy, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHOW, _e_comp_x_show, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHOW_REQUEST, _e_comp_x_show_request, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_RESIZE_REQUEST, _e_comp_x_resize_request, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_HIDE, _e_comp_x_hide, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_REPARENT, _e_comp_x_reparent, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_CONFIGURE, _e_comp_x_configure, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST, _e_comp_x_configure_request, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STATE_REQUEST, _e_comp_x_state_request, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STACK, _e_comp_x_stack, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STACK_REQUEST, _e_comp_x_stack_request, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_CLIENT_MESSAGE, _e_comp_x_message, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_PROPERTY, _e_comp_x_property, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHAPE, _e_comp_x_shape, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_DAMAGE_NOTIFY, _e_comp_x_damage, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_DAMAGE, _e_comp_x_damage_win, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MAPPING_CHANGE, _e_comp_x_mapping_change, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_FOCUS_IN, _e_comp_x_focus_in, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_FOCUS_OUT, _e_comp_x_focus_out, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST,
_e_comp_x_move_resize_request, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_DESKTOP_CHANGE,
_e_comp_x_desktop_change, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SYNC_ALARM,
_e_comp_x_sync_alarm, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN,
_e_comp_x_mouse_down, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_UP,
_e_comp_x_mouse_up, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_WHEEL,
_e_comp_x_mouse_wheel, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_MOVE,
_e_comp_x_mouse_move, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MOUSE_IN,
_e_comp_x_mouse_in, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MOUSE_OUT,
_e_comp_x_mouse_out, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_ZONE_SET,
_e_comp_x_client_zone_set, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_PROPERTY,
_e_comp_x_client_property, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_FRAME_EXTENTS_REQUEST,
_e_comp_x_cb_frame_extents_request, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_PING,
_e_comp_x_cb_ping, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SCREENSAVER_NOTIFY, _e_comp_x_screensaver_notify_cb, NULL);;
ecore_x_screensaver_custom_blanking_enable();
e_screensaver_attrs_set(ecore_x_screensaver_timeout_get(),
ecore_x_screensaver_blank_get(),
ecore_x_screensaver_expose_get());
ecore_x_passive_grab_replay_func_set(_e_comp_x_grab_replay, NULL);
e_client_hook_add(E_CLIENT_HOOK_DESK_SET, _e_comp_x_hook_client_desk_set, NULL);
e_client_hook_add(E_CLIENT_HOOK_RESIZE_BEGIN, _e_comp_x_hook_client_resize_begin, NULL);
e_client_hook_add(E_CLIENT_HOOK_RESIZE_END, _e_comp_x_hook_client_resize_end, NULL);
e_client_hook_add(E_CLIENT_HOOK_MOVE_BEGIN, _e_comp_x_hook_client_move_begin, NULL);
e_client_hook_add(E_CLIENT_HOOK_MOVE_END, _e_comp_x_hook_client_move_end, NULL);
e_client_hook_add(E_CLIENT_HOOK_DEL, _e_comp_x_hook_client_del, NULL);
e_client_hook_add(E_CLIENT_HOOK_NEW_CLIENT, _e_comp_x_hook_client_new, NULL);
e_client_hook_add(E_CLIENT_HOOK_EVAL_FETCH, _e_comp_x_hook_client_fetch, NULL);
e_client_hook_add(E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN, _e_comp_x_hook_client_pre_frame_assign, NULL);
e_client_hook_add(E_CLIENT_HOOK_UNREDIRECT, _e_comp_x_hook_client_unredirect, NULL);
e_client_hook_add(E_CLIENT_HOOK_REDIRECT, _e_comp_x_hook_client_redirect, NULL);
e_client_hook_add(E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT, _e_comp_x_hook_client_post_new_client, NULL);
e_client_hook_add(E_CLIENT_HOOK_FOCUS_SET, _e_comp_x_hook_client_focus_set, NULL);
e_client_hook_add(E_CLIENT_HOOK_FOCUS_UNSET, _e_comp_x_hook_client_focus_unset, NULL);
e_client_hook_add(E_CLIENT_HOOK_EVAL_END, _e_comp_x_hook_client_eval_end, NULL);
if (!e_randr_init()) return 0;
if (!e_atoms_init()) return 0;
if (!_e_comp_x_screens_setup()) return EINA_FALSE;
if (!e_xsettings_init())
e_error_message_show(_("Enlightenment cannot initialize the XSettings system.\n"));
ecore_x_sync();
return EINA_TRUE;
}
EINTERN void
e_comp_x_shutdown(void)
{
E_FREE_LIST(handlers, ecore_event_handler_del);
E_FREE_FUNC(clients_win_hash, eina_hash_free);
E_FREE_FUNC(damages_hash, eina_hash_free);
E_FREE_FUNC(alarm_hash, eina_hash_free);
E_FREE_FUNC(frame_extents, eina_hash_free);
e_xsettings_shutdown();
ecore_x_screensaver_custom_blanking_disable();
if (x_fatal) return;
e_atoms_shutdown();
e_randr_shutdown();
/* ecore_x_ungrab(); */
ecore_x_focus_reset();
ecore_x_events_allow_all();
ecore_x_shutdown();
}