enlightenment/src/modules/illume2/e_mod_layout.c

873 lines
22 KiB
C

#include "e.h"
#include "e_mod_main.h"
#include "e_mod_layout.h"
#include "e_mod_layout_illume.h"
#include "e_mod_config.h"
#include "e_kbd.h"
// internal calls
static void _e_mod_layout_cb_hook_container_layout(void *data, void *data2);
static void _e_mod_layout_cb_hook_post_fetch(void *data, void *data2);
static void _e_mod_layout_cb_hook_post_border_assign(void *data, void *data2);
static void _e_mod_layout_cb_hook_end(void *data, void *data2);
static int _cb_event_border_add(void *data, int type, void *event);
static int _cb_event_border_remove(void *data, int type, void *event);
static int _cb_event_border_focus_in(void *data, int type, void *event);
static int _cb_event_border_focus_out(void *data, int type, void *event);
static int _cb_event_border_show(void *data, int type, void *event);
static int _cb_event_border_hide(void *data, int type, void *event);
static int _cb_event_zone_move_resize(void *data, int type, void *event);
static int _cb_event_client_message(void *data, int type, void *event);
// state
static E_Border_Hook *hook1 = NULL;
static E_Border_Hook *hook2 = NULL;
static E_Border_Hook *hook3 = NULL;
static E_Border_Hook *hook4 = NULL;
static Eina_List *handlers = NULL;
void
e_mod_layout_init(E_Module *m)
{
Eina_List *l;
hook1 = e_border_hook_add(E_BORDER_HOOK_EVAL_POST_FETCH,
_e_mod_layout_cb_hook_post_fetch, NULL);
hook2 = e_border_hook_add(E_BORDER_HOOK_EVAL_POST_BORDER_ASSIGN,
_e_mod_layout_cb_hook_post_border_assign, NULL);
hook3 = e_border_hook_add(E_BORDER_HOOK_EVAL_END,
_e_mod_layout_cb_hook_end, NULL);
hook4 = e_border_hook_add(E_BORDER_HOOK_CONTAINER_LAYOUT,
_e_mod_layout_cb_hook_container_layout, NULL);
handlers = eina_list_append
(handlers, ecore_event_handler_add
(E_EVENT_BORDER_ADD, _cb_event_border_add, NULL));
handlers = eina_list_append
(handlers, ecore_event_handler_add
(E_EVENT_BORDER_REMOVE, _cb_event_border_remove, NULL));
handlers = eina_list_append
(handlers, ecore_event_handler_add
(E_EVENT_BORDER_FOCUS_IN, _cb_event_border_focus_in, NULL));
handlers = eina_list_append
(handlers, ecore_event_handler_add
(E_EVENT_BORDER_FOCUS_OUT, _cb_event_border_focus_out, NULL));
handlers = eina_list_append
(handlers, ecore_event_handler_add
(E_EVENT_BORDER_SHOW, _cb_event_border_show, NULL));
handlers = eina_list_append
(handlers, ecore_event_handler_add
(E_EVENT_BORDER_HIDE, _cb_event_border_hide, NULL));
handlers = eina_list_append
(handlers, ecore_event_handler_add
(E_EVENT_ZONE_MOVE_RESIZE, _cb_event_zone_move_resize, NULL));
handlers = eina_list_append
(handlers, ecore_event_handler_add
(ECORE_X_EVENT_CLIENT_MESSAGE, _cb_event_client_message, NULL));
illume_layout_illume_init();
}
void
e_mod_layout_shutdown(void)
{
Ecore_Event_Handler *handle;
illume_layout_illume_shutdown();
if (hook1) e_border_hook_del(hook1);
if (hook2) e_border_hook_del(hook2);
if (hook3) e_border_hook_del(hook3);
if (hook4) e_border_hook_del(hook4);
hook1 = NULL;
hook2 = NULL;
hook3 = NULL;
hook4 = NULL;
EINA_LIST_FREE(handlers, handle)
ecore_event_handler_del(handle);
}
//////////////////////////////////////////////////////////////////////////////
// :: Convenience routines to make it easy to write layout logic code ::
static Eina_List *modes = NULL;
static const Illume_Layout_Mode *mode = NULL;
void
illume_layout_mode_register(const Illume_Layout_Mode *laymode)
{
if (!modes) mode = laymode;
modes = eina_list_append(modes, laymode);
}
void
illume_layout_mode_unregister(const Illume_Layout_Mode *laymode)
{
if (mode == laymode) mode = NULL;
modes = eina_list_remove(modes, laymode);
}
Eina_List *
illume_layout_modes_get(void)
{
return modes;
}
//////////////////////////////////////////////////////////////////////////////
// :: Convenience routines to make it easy to write layout logic code ::
// activate a window - meant for main app and home app windows
void
illume_border_activate(E_Border *bd)
{
e_desk_show(bd->desk);
e_border_uniconify(bd);
e_border_raise(bd);
e_border_show(bd);
e_border_focus_set(bd, 1, 1);
}
// activate a window that isnt meant to get the focus - like panels, kbd etc.
void
illume_border_show(E_Border *bd)
{
e_desk_show(bd->desk);
e_border_uniconify(bd);
e_border_raise(bd);
e_border_show(bd);
}
// get a window away from being visile (but maintain it)
void
illume_border_deactivate(E_Border *bd)
{
e_border_iconify(bd);
}
// get window info - is this one a dialog?
Eina_Bool
illume_border_is_dialog(E_Border *bd)
{
int isdialog = 0, i;
if (bd->client.icccm.transient_for != 0) isdialog = 1;
if (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG)
{
isdialog = 1;
if (bd->client.netwm.extra_types)
{
for (i = 0; i < bd->client.netwm.extra_types_num; i++)
{
if (bd->client.netwm.extra_types[i] ==
ECORE_X_WINDOW_TYPE_UNKNOWN) continue;
if ((bd->client.netwm.extra_types[i] !=
ECORE_X_WINDOW_TYPE_DIALOG) &&
(bd->client.netwm.extra_types[i] !=
ECORE_X_WINDOW_TYPE_SPLASH))
{
return 0;
}
}
}
}
return isdialog;
}
// get window info - is this a vkbd window
Eina_Bool
illume_border_is_keyboard(E_Border *bd)
{
if (bd->client.vkbd.vkbd) return 1;
if (il_cfg->policy.vkbd.match.title)
{
if ((bd->client.icccm.title) &&
(!strcmp(bd->client.icccm.title, il_cfg->policy.vkbd.title)))
return 1;
}
if (il_cfg->policy.vkbd.match.name)
{
if ((bd->client.icccm.name) &&
(!strcmp(bd->client.icccm.name, il_cfg->policy.vkbd.name)))
return 1;
}
if (il_cfg->policy.vkbd.match.class)
{
if ((bd->client.icccm.class) &&
(!strcmp(bd->client.icccm.class, il_cfg->policy.vkbd.class)))
return 1;
}
if ((bd->client.icccm.name) &&
((!strcmp(bd->client.icccm.name, "multitap-pad")))
&& (bd->client.netwm.state.skip_taskbar)
&& (bd->client.netwm.state.skip_pager))
return 1;
return 0;
}
// get window info - is it a bottom app panel window (eg qtopia softmenu)
Eina_Bool
illume_border_is_bottom_panel(E_Border *bd)
{
if (il_cfg->policy.softkey.match.title)
{
if ((bd->client.icccm.title) &&
(!strcmp(bd->client.icccm.title, il_cfg->policy.softkey.title)))
return 1;
}
if (il_cfg->policy.softkey.match.name)
{
if ((bd->client.icccm.name) &&
(!strcmp(bd->client.icccm.name, il_cfg->policy.softkey.name)))
return 1;
}
if (il_cfg->policy.softkey.match.class)
{
if ((bd->client.icccm.class) &&
(!strcmp(bd->client.icccm.class, il_cfg->policy.softkey.class)))
return 1;
}
if (((bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DOCK) ||
(bd->client.qtopia.soft_menu)))
return 1;
return 0;
}
// get window info - is it a top shelf window
Eina_Bool
illume_border_is_top_shelf(E_Border *bd)
{
if (il_cfg->policy.indicator.match.title)
{
if ((bd->client.icccm.title) &&
(!strcmp(bd->client.icccm.title, il_cfg->policy.indicator.title)))
return 1;
}
if (il_cfg->policy.indicator.match.name)
{
if ((bd->client.icccm.name) &&
(!strcmp(bd->client.icccm.name, il_cfg->policy.indicator.name)))
return 1;
}
if (il_cfg->policy.indicator.match.class)
{
if ((bd->client.icccm.class) &&
(!strcmp(bd->client.icccm.class, il_cfg->policy.indicator.class)))
return 1;
}
return 0;
}
// get window info - is it a mini app window
Eina_Bool
illume_border_is_mini_app(E_Border *bd)
{
// FIXME: detect
return 0;
}
// get window info - is it a notification window
Eina_Bool
illume_border_is_notification(E_Border *bd)
{
// FIXME: detect
return 0;
}
// get window info - is it a home window
Eina_Bool
illume_border_is_home(E_Border *bd)
{
if (il_cfg->policy.home.match.title)
{
if ((bd->client.icccm.title) &&
(!strcmp(bd->client.icccm.title, il_cfg->policy.home.title)))
return 1;
}
if (il_cfg->policy.home.match.name)
{
if ((bd->client.icccm.name) &&
(!strcmp(bd->client.icccm.name, il_cfg->policy.home.name)))
return 1;
}
if (il_cfg->policy.home.match.class)
{
if ((bd->client.icccm.class) &&
(!strcmp(bd->client.icccm.class, il_cfg->policy.home.class)))
return 1;
}
return 0;
}
// get window info - is it side pane (left) window
Eina_Bool
illume_border_is_side_pane_left(E_Border *bd)
{
// FIXME: detect
return 0;
}
// get window info - is it side pane (right) window
Eina_Bool
illume_border_is_side_pane_right(E_Border *bd)
{
// FIXME: detect
return 0;
}
// get window info - is it overlay window (eg expose display of windows etc.)
Eina_Bool
illume_border_is_overlay(E_Border *bd)
{
// FIXME: detect
return 0;
}
Eina_Bool
illume_border_is_conformant(E_Border *bd)
{
if (strstr(bd->client.icccm.class, "config")) return EINA_FALSE;
return ecore_x_e_illume_conformant_get(bd->client.win);
}
Eina_List *
illume_border_valid_borders_get(void)
{
Eina_List *bds, *l, *ret = NULL;
E_Border *bd;
bds = e_border_client_list();
EINA_LIST_FOREACH(bds, l, bd)
{
if (!bd) continue;
if (illume_border_is_top_shelf(bd)) continue;
if (illume_border_is_bottom_panel(bd)) continue;
if (illume_border_is_keyboard(bd)) continue;
if (illume_border_is_dialog(bd)) continue;
ret = eina_list_append(ret, bd);
}
return ret;
}
E_Border *
illume_border_valid_border_get(void)
{
Eina_List *bds, *l;
E_Border *bd, *ret = NULL;
bds = e_border_client_list();
EINA_LIST_FOREACH(bds, l, bd)
{
if (!bd) continue;
if (illume_border_is_top_shelf(bd)) continue;
if (illume_border_is_bottom_panel(bd)) continue;
if (illume_border_is_keyboard(bd)) continue;
if (illume_border_is_dialog(bd)) continue;
ret = bd;
break;
}
return ret;
}
int
illume_border_valid_count_get(void)
{
Eina_List *l;
int count;
l = illume_border_valid_borders_get();
count = eina_list_count(l);
eina_list_free(l);
return count;
}
E_Border *
illume_border_at_xy_get(int x, int y)
{
Eina_List *bds, *l;
E_Border *bd, *b = NULL;
bds = illume_border_valid_borders_get();
EINA_LIST_FOREACH(bds, l, bd)
{
if (((bd->fx.x == x) && (bd->fx.y == y)) ||
((bd->x == x) && (bd->y == y)))
{
b = bd;
break;
}
}
eina_list_free(bds);
return b;
}
E_Border *
illume_border_in_region_get(int x, int y, int w, int h)
{
Eina_List *bds, *l;
E_Border *bd, *b = NULL;
bds = illume_border_valid_borders_get();
EINA_LIST_FOREACH(bds, l, bd)
{
if (E_INSIDE(bd->x, bd->fx.y, x, y, w, h))
{
b = bd;
break;
}
}
eina_list_free(bds);
return b;
}
E_Border *
illume_border_top_shelf_get(void)
{
Eina_List *bds, *l;
E_Border *bd, *b = NULL;
bds = e_border_client_list();
EINA_LIST_FOREACH(bds, l, bd)
{
if (!illume_border_is_top_shelf(bd)) continue;
b = bd;
break;
}
return b;
}
E_Border *
illume_border_bottom_panel_get(void)
{
Eina_List *bds, *l;
E_Border *bd, *b = NULL;
bds = e_border_client_list();
EINA_LIST_FOREACH(bds, l, bd)
{
if (!illume_border_is_bottom_panel(bd)) continue;
b = bd;
break;
}
return b;
}
void
illume_border_top_shelf_pos_get(int *x, int *y)
{
E_Border *bd;
if (!(bd = illume_border_top_shelf_get())) return;
if (x) *x = bd->x;
if (y) *y = bd->y;
}
void
illume_border_top_shelf_size_get(int *w, int *h)
{
E_Border *bd;
if (!(bd = illume_border_top_shelf_get())) return;
if (w) *w = bd->w;
if (h) *h = bd->h;
}
void
illume_border_bottom_panel_pos_get(int *x, int *y)
{
E_Border *bd;
if (!(bd = illume_border_bottom_panel_get())) return;
if (x) *x = bd->x;
if (y) *y = bd->y;
}
void
illume_border_bottom_panel_size_get(int *w, int *h)
{
E_Border *bd;
if (!(bd = illume_border_bottom_panel_get())) return;
if (w) *w = bd->w;
if (h) *h = bd->h;
}
void
illume_border_slide_to(E_Border *bd, int x, int y, Illume_Anim_Class aclass)
{
// FIXME: do
// 1. if an existing slide exists, use is current offset x,y as current border pos, new x,y as new pos and start slide again
}
void
illume_border_min_get(E_Border *bd, int *mw, int *mh)
{
if (mw)
{
if (bd->client.icccm.base_w > bd->client.icccm.min_w)
*mw = bd->client.icccm.base_w;
else
*mw = bd->client.icccm.min_w;
}
if (mh)
{
if (bd->client.icccm.base_h > bd->client.icccm.min_h)
*mh = bd->client.icccm.base_h;
else
*mh = bd->client.icccm.min_h;
}
}
void
illume_border_max_get(E_Border *bd, int *mw, int *mh)
{
if (mw)
{
if (bd->client.icccm.base_w > bd->client.icccm.max_w)
*mw = bd->client.icccm.base_w;
else
*mw = bd->client.icccm.max_w;
}
if (mh)
{
if (bd->client.icccm.base_h > bd->client.icccm.max_h)
*mh = bd->client.icccm.base_h;
else
*mh = bd->client.icccm.max_h;
}
}
void
illume_border_app1_safe_region_get(E_Zone *zone, int *x, int *y, int *w, int *h)
{
int ty, nx, ny, nw, nh;
if (!zone) return;
e_kbd_safe_app_region_get(zone, &nx, &ny, &nw, &nh);
illume_border_top_shelf_pos_get(NULL, &ty);
if (nh >= zone->h) nh = (ny + ty);
if (x) *x = nx;
if (y) *y = ny;
if (w) *w = nw;
if (h) *h = nh;
}
void
illume_border_app2_safe_region_get(E_Zone *zone, int *x, int *y, int *w, int *h)
{
int ty, th, bh;
int nx, ny, nw, nh;
if (!zone) return;
e_kbd_safe_app_region_get(zone, &nx, NULL, &nw, &nh);
illume_border_top_shelf_pos_get(NULL, &ty);
illume_border_top_shelf_size_get(NULL, &th);
illume_border_bottom_panel_size_get(NULL, &bh);
ny = (ty + th);
nh = (nh - ny - bh);
if (x) *x = nx;
if (y) *y = ny;
if (w) *w = nw;
if (h) *h = nh;
}
static void
_e_mod_layout_cb_hook_container_layout(void *data, void *data2)
{
Eina_List *l;
E_Zone *zone;
E_Container *con;
if (!(con = data2)) return;
EINA_LIST_FOREACH(con->zones, l, zone)
{
if ((mode) && (mode->funcs.zone_layout))
mode->funcs.zone_layout(zone);
}
}
static void
_e_mod_layout_cb_hook_post_fetch(void *data, void *data2)
{
E_Border *bd;
if (!(bd = data2)) return;
if (bd->stolen) return;
if (bd->new_client)
{
if (bd->remember)
{
if (bd->bordername)
{
eina_stringshare_del(bd->bordername);
bd->bordername = NULL;
bd->client.border.changed = 1;
}
e_remember_unuse(bd->remember);
bd->remember = NULL;
}
eina_stringshare_replace(&bd->bordername, "borderless");
bd->client.border.changed = 1;
bd->client.e.state.centered = 0;
}
}
static void
_e_mod_layout_cb_hook_post_border_assign(void *data, void *data2)
{
E_Border *bd;
int zx, zy, zw, zh, pbx, pby, pbw, pbh;
if (!(bd = data2)) return;
if (bd->stolen) return;
pbx = bd->x; pby = bd->y; pbw = bd->w; pbh = bd->h;
zx = bd->zone->x; zy = bd->zone->y; zw = bd->zone->w; zh = bd->zone->h;
bd->placed = 1;
bd->client.e.state.centered = 0;
if (!((bd->need_fullscreen) || (bd->fullscreen)))
{
/*
bd->x = zx; bd->y = zy; bd->w = zw; bd->h = zh;
bd->client.w = bd->w; bd->client.h = bd->h;
if ((pbx != bd->x) || (pby != bd->y) ||
(pbw != bd->w) || (pbh != bd->h))
{
bd->changed = 1;
bd->changes.pos = 1;
bd->changes.size = 1;
}
*/
}
else
{
/*
bd->x = zx; bd->y = zy; bd->w = zw; bd->h = zh;
bd->client.w = bd->w; bd->client.h = bd->h;
if ((pbx != bd->x) || (pby != bd->y) ||
(pbw != bd->w) || (pbh != bd->h))
{
if (bd->internal_ecore_evas)
ecore_evas_managed_move(bd->internal_ecore_evas,
bd->x + bd->fx.x + bd->client_inset.l,
bd->y + bd->fx.y + bd->client_inset.t);
ecore_x_icccm_move_resize_send
(bd->client.win,
bd->x + bd->fx.x + bd->client_inset.l,
bd->y + bd->fx.y + bd->client_inset.t,
bd->client.w,
bd->client.h);
bd->changed = 1;
bd->changes.pos = 1;
bd->changes.size = 1;
}
*/
}
if (bd->remember)
{
e_remember_unuse(bd->remember);
bd->remember = NULL;
}
bd->lock_border = 1;
bd->lock_client_location = 1;
bd->lock_client_size = 1;
bd->lock_client_desk = 1;
bd->lock_client_sticky = 1;
bd->lock_client_shade = 1;
bd->lock_client_maximize = 1;
bd->lock_user_location = 1;
bd->lock_user_size = 1;
bd->lock_user_sticky = 1;
}
static void
_e_mod_layout_cb_hook_end(void *data, void *data2)
{
}
static int
_cb_event_border_add(void *data, int type, void *event)
{
E_Event_Border_Add *ev;
E_Border *bd;
ev = event;
if (ev->border->stolen) return 1;
bd = ev->border;
if ((mode) && (mode->funcs.border_add))
mode->funcs.border_add(bd);
return 1;
}
static int
_cb_event_border_remove(void *data, int type, void *event)
{
E_Event_Border_Remove *ev;
E_Border *bd;
ev = event;
if (ev->border->stolen) return 1;
bd = ev->border;
if ((mode) && (mode->funcs.border_del))
mode->funcs.border_del(bd);
return 1;
}
static int
_cb_event_border_focus_in(void *data, int type, void *event)
{
E_Event_Border_Focus_In *ev;
E_Border *bd;
ev = event;
if (ev->border->stolen) return 1;
bd = ev->border;
if ((mode) && (mode->funcs.border_focus_in))
mode->funcs.border_focus_in(bd);
return 1;
}
static int
_cb_event_border_focus_out(void *data, int type, void *event)
{
E_Event_Border_Focus_Out *ev;
E_Border *bd;
ev = event;
if (ev->border->stolen) return 1;
bd = ev->border;
if ((mode) && (mode->funcs.border_focus_out))
mode->funcs.border_focus_out(bd);
return 1;
}
static int
_cb_event_border_show(void *data, int type, void *event)
{
E_Event_Border_Show *ev;
ev = event;
if (ev->border->stolen) return 1;
return 1;
}
static int
_cb_event_border_hide(void *data, int type, void *event)
{
E_Event_Border_Hide *ev;
ev = event;
if (ev->border->stolen) return 1;
return 1;
}
static int
_cb_event_zone_move_resize(void *data, int type, void *event)
{
E_Event_Zone_Move_Resize *ev;
ev = event;
if ((mode) && (mode->funcs.zone_move_resize))
mode->funcs.zone_move_resize(ev->zone);
return 1;
}
static int
_cb_event_client_message(void *data, int type, void *event)
{
Ecore_X_Event_Client_Message *ev;
ev = event;
if (ev->message_type == ECORE_X_ATOM_NET_ACTIVE_WINDOW)
{
E_Border *bd;
bd = e_border_find_by_client_window(ev->win);
if ((!bd) || (bd->stolen)) return 1;
if ((mode) && (mode->funcs.border_activate))
mode->funcs.border_activate(bd);
}
else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_MODE)
{
Ecore_X_Illume_Mode mode;
E_Border *bd;
int lock = 1;
mode = ecore_x_e_illume_mode_get(ev->win);
if (mode == ECORE_X_ILLUME_MODE_SINGLE)
il_cfg->policy.mode.dual = 0;
else if (mode == ECORE_X_ILLUME_MODE_DUAL)
il_cfg->policy.mode.dual = 1;
else /* unknown */
il_cfg->policy.mode.dual = 0;
e_config_save_queue();
if (mode == ECORE_X_ILLUME_MODE_DUAL)
{
if (il_cfg->policy.mode.side == 0) lock = 0;
}
bd = illume_border_top_shelf_get();
if (bd)
ecore_x_e_illume_drag_locked_set(bd->client.win, lock);
bd = illume_border_bottom_panel_get();
if (bd)
ecore_x_e_illume_drag_locked_set(bd->client.win, lock);
}
else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_BACK)
{
E_Border *bd, *fbd;
Eina_List *focused, *l;
if (!(bd = e_border_focused_get())) return 1;
focused = e_border_focus_stack_get();
EINA_LIST_REVERSE_FOREACH(focused, l, fbd)
{
E_Border *fb;
if (e_object_is_del(E_OBJECT(fbd))) continue;
if ((!fbd->client.icccm.accepts_focus) &&
(!fbd->client.icccm.take_focus)) continue;
if (fbd->client.netwm.state.skip_taskbar) continue;
if (fbd == bd)
{
if (!(fb = focused->next->data)) continue;
if (e_object_is_del(E_OBJECT(fb))) continue;
if ((!fb->client.icccm.accepts_focus) &&
(!fb->client.icccm.take_focus)) continue;
if (fb->client.netwm.state.skip_taskbar) continue;
e_border_raise(fb);
e_border_focus_set(fb, 1, 1);
break;
}
}
}
else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_CLOSE)
{
E_Border *bd;
if (!(bd = e_border_focused_get())) return 1;
e_border_act_close_begin(bd);
}
else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_DRAG_START)
{
E_Border *bd;
bd = e_border_find_by_client_window(ev->win);
if ((!bd) || (bd->stolen)) return 1;
if ((mode) && (mode->funcs.drag_start))
mode->funcs.drag_start(bd);
}
else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_DRAG_END)
{
E_Border *bd;
bd = e_border_find_by_client_window(ev->win);
if ((!bd) || (bd->stolen)) return 1;
if ((mode) && (mode->funcs.drag_end))
mode->funcs.drag_end(bd);
}
return 1;
}