enlightenment/src/modules/winlist/e_winlist.c

1356 lines
40 KiB
C

#include "e.h"
#include "e_mod_main.h"
/* local subsystem functions */
typedef struct _E_Winlist_Win E_Winlist_Win;
struct _E_Winlist_Win
{
Evas_Object *bg_object;
Evas_Object *icon_object;
E_Client *client;
unsigned char was_iconified : 1;
unsigned char was_shaded : 1;
};
static void _e_winlist_size_adjust(void);
static void _e_winlist_client_add(E_Client *ec, E_Zone *zone, E_Desk *desk);
static void _e_winlist_client_del(E_Client *ec);
static void _e_winlist_activate_nth(int n);
static void _e_winlist_activate(void);
static void _e_winlist_deactivate(void);
static void _e_winlist_show_active(void);
static Eina_Bool _e_winlist_cb_event_border_add(void *data, int type, void *event);
static Eina_Bool _e_winlist_cb_event_border_remove(void *data, int type, void *event);
static Eina_Bool _e_winlist_cb_key_down(void *data, int type, void *event);
static Eina_Bool _e_winlist_cb_key_up(void *data, int type, void *event);
static Eina_Bool _e_winlist_cb_mouse_down(void *data, int type, void *event);
static Eina_Bool _e_winlist_cb_mouse_up(void *data, int type, void *event);
static Eina_Bool _e_winlist_cb_mouse_wheel(void *data, int type, void *event);
static Eina_Bool _e_winlist_cb_mouse_move(void *data, int type, void *event);
static Eina_Bool _e_winlist_scroll_timer(void *data);
static Eina_Bool _e_winlist_animator(void *data);
#if 0
static void _e_winlist_cb_item_mouse_in(void *data, Evas *evas,
Evas_Object *obj, void *event_info);
#endif
/* local subsystem globals */
static Evas_Object *_winlist = NULL;
static E_Zone *_winlist_zone = NULL;
static Evas_Object *_bg_object = NULL;
static Evas_Object *_list_object = NULL;
static Evas_Object *_icon_object = NULL;
static Eina_List *_wins = NULL;
static Eina_List *_win_selected = NULL;
static E_Desk *_last_desk = NULL;
static int _last_pointer_x = 0;
static int _last_pointer_y = 0;
static E_Client *_last_client = NULL;
static int _hold_count = 0;
static int _hold_mod = 0;
static E_Winlist_Activate_Type _activate_type = 0;
static Eina_List *_handlers = NULL;
static Ecore_X_Window _input_window = 0;
static int _scroll_to = 0;
static double _scroll_align_to = 0.0;
static double _scroll_align = 0.0;
static Ecore_Timer *_scroll_timer = NULL;
static Ecore_Animator *_animator = NULL;
static E_Client *_ec_next = NULL;
static Eina_Bool
_wmclass_picked(const Eina_List *lst, const char *wmclass)
{
const Eina_List *l;
const char *s;
if (!wmclass) return EINA_FALSE;
EINA_LIST_FOREACH(lst, l, s)
if (s == wmclass)
return EINA_TRUE;
return EINA_FALSE;
}
/* externally accessible functions */
int
e_winlist_init(void)
{
return 1;
}
int
e_winlist_shutdown(void)
{
e_winlist_hide();
return 1;
}
int
e_winlist_show(E_Zone *zone, E_Winlist_Filter filter)
{
int x, y, w, h;
Evas_Object *o;
Eina_List *l;
E_Desk *desk;
E_Client *ec;
Eina_List *wmclasses = NULL;
E_OBJECT_CHECK_RETURN(zone, 0);
E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, 0);
if (_winlist) return 0;
_input_window = ecore_x_window_input_new(zone->comp->man->root, 0, 0, 1, 1);
ecore_x_window_show(_input_window);
if (!e_grabinput_get(_input_window, 0, _input_window))
{
ecore_x_window_free(_input_window);
_input_window = 0;
return 0;
}
w = (double)zone->w * e_config->winlist_pos_size_w;
if (w > e_config->winlist_pos_max_w) w = e_config->winlist_pos_max_w;
else if (w < e_config->winlist_pos_min_w)
w = e_config->winlist_pos_min_w;
if (w > zone->w) w = zone->w;
x = zone->x + (double)(zone->w - w) * e_config->winlist_pos_align_x;
h = (double)zone->h * e_config->winlist_pos_size_h;
if (h > e_config->winlist_pos_max_h) h = e_config->winlist_pos_max_h;
else if (h < e_config->winlist_pos_min_h)
h = e_config->winlist_pos_min_h;
if (h > zone->h) h = zone->h;
y = zone->y + (double)(zone->h - h) * e_config->winlist_pos_align_y;
_winlist_zone = zone;
e_client_move_cancel();
e_client_resize_cancel();
e_client_focus_track_freeze();
evas_event_feed_mouse_in(zone->comp->evas, ecore_x_current_time_get(), NULL);
evas_event_feed_mouse_move(zone->comp->evas, -1000000, -1000000,
ecore_x_current_time_get(), NULL);
evas_event_freeze(zone->comp->evas);
o = edje_object_add(zone->comp->evas);
_winlist = e_comp_object_util_add(o, E_COMP_OBJECT_TYPE_POPUP);
evas_object_layer_set(_winlist, E_LAYER_CLIENT_POPUP);
evas_object_move(_winlist, x, y);
_bg_object = o;
e_theme_edje_object_set(o, "base/theme/winlist",
"e/widgets/winlist/main");
o = e_box_add(zone->comp->evas);
_list_object = o;
e_box_align_set(o, 0.5, 0.0);
e_box_orientation_set(o, 0);
e_box_homogenous_set(o, 1);
e_comp_object_util_del_list_append(_winlist, o);
edje_object_part_swallow(_bg_object, "e.swallow.list", o);
edje_object_part_text_set(_bg_object, "e.text.title", _("Select a window"));
evas_object_show(o);
_last_client = e_client_focused_get();
desk = e_desk_current_get(_winlist_zone);
e_box_freeze(_list_object);
EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec)
{
Eina_Bool pick;
switch (filter)
{
case E_WINLIST_FILTER_CLASS_WINDOWS:
if (!_last_client)
pick = EINA_FALSE;
else
pick = _last_client->icccm.class == ec->icccm.class;
break;
case E_WINLIST_FILTER_CLASSES:
pick = (!_wmclass_picked(wmclasses, ec->icccm.class));
if (pick)
wmclasses = eina_list_append(wmclasses, ec->icccm.class);
break;
default:
pick = EINA_TRUE;
}
if (pick) _e_winlist_client_add(ec, _winlist_zone, desk);
}
e_box_thaw(_list_object);
eina_list_free(wmclasses);
if (!_wins)
{
e_winlist_hide();
return 1;
}
if (e_config->winlist_list_show_other_desk_windows ||
e_config->winlist_list_show_other_screen_windows)
_last_desk = e_desk_current_get(_winlist_zone);
if (e_config->winlist_warp_while_selecting)
ecore_evas_pointer_xy_get(_winlist_zone->comp->ee,
&_last_pointer_x, &_last_pointer_y);
_e_winlist_activate_nth(1);
if ((eina_list_count(_wins) > 1))
{
E_Winlist_Win *ww;
ww = eina_list_data_get(_win_selected);
if (ww && (ww->client == _last_client))
e_winlist_next();
}
evas_event_thaw(zone->comp->evas);
_e_winlist_size_adjust();
E_LIST_HANDLER_APPEND(_handlers, E_EVENT_CLIENT_ADD, _e_winlist_cb_event_border_add, NULL);
E_LIST_HANDLER_APPEND(_handlers, E_EVENT_CLIENT_REMOVE, _e_winlist_cb_event_border_remove, NULL);
E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_KEY_DOWN, _e_winlist_cb_key_down, NULL);
E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_KEY_UP, _e_winlist_cb_key_up, NULL);
E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_winlist_cb_mouse_down, NULL);
E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_MOUSE_BUTTON_UP, _e_winlist_cb_mouse_up, NULL);
E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_MOUSE_WHEEL, _e_winlist_cb_mouse_wheel, NULL);
E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_MOUSE_MOVE, _e_winlist_cb_mouse_move, NULL);
evas_object_show(_winlist);
return 1;
}
void
e_winlist_hide(void)
{
E_Client *ec = NULL;
E_Winlist_Win *ww;
if (!_winlist) return;
if (_win_selected)
{
ww = _win_selected->data;
ec = ww->client;
}
evas_object_hide(_winlist);
EINA_LIST_FREE(_wins, ww)
{
if ((!ec) || (ww->client != ec))
e_object_unref(E_OBJECT(ww->client));
free(ww);
}
_win_selected = NULL;
_icon_object = NULL;
evas_object_del(_winlist);
e_client_focus_track_thaw();
_winlist = NULL;
_winlist_zone = NULL;
_hold_count = 0;
_hold_mod = 0;
_activate_type = 0;
E_FREE_LIST(_handlers, ecore_event_handler_del);
E_FREE_FUNC(_scroll_timer, ecore_timer_del);
E_FREE_FUNC(_animator, ecore_animator_del);
e_grabinput_release(_input_window, _input_window);
ecore_x_window_free(_input_window);
_input_window = 0;
if (ec)
{
if (ec->shaded)
{
if (!ec->lock_user_shade)
e_client_unshade(ec, ec->shade_dir);
}
if (e_config->winlist_list_move_after_select)
{
e_client_zone_set(ec, e_zone_current_get(e_util_comp_current_get()));
e_client_desk_set(ec, e_desk_current_get(ec->zone));
}
else if (ec->desk)
{
if (!ec->sticky) e_desk_show(ec->desk);
}
if (!ec->lock_user_stacking)
{
evas_object_raise(ec->frame);
e_client_raise_latest_set(ec);
}
if ((e_config->focus_policy != E_FOCUS_CLICK) ||
(e_config->winlist_warp_at_end) ||
(e_config->winlist_warp_while_selecting))
{
e_client_pointer_warp_to_center_now(ec);
}
else if (!ec->lock_focus_out)
{
if (ec->iconic)
e_client_uniconify(ec);
if (ec->shaded)
e_client_unshade(ec, ec->shade_dir);
evas_object_focus_set(ec->frame, 1);
e_client_focus_latest_set(ec);
}
e_object_unref(E_OBJECT(ec));
}
}
void
e_winlist_next(void)
{
if (!_winlist) return;
if (eina_list_count(_wins) == 1)
{
if (!_win_selected)
{
_win_selected = _wins;
_e_winlist_show_active();
_e_winlist_activate();
}
return;
}
_e_winlist_deactivate();
if (!_win_selected)
_win_selected = _wins;
else
_win_selected = _win_selected->next;
if (!_win_selected) _win_selected = _wins;
_e_winlist_show_active();
_e_winlist_activate();
}
void
e_winlist_prev(void)
{
if (!_winlist) return;
if (eina_list_count(_wins) == 1)
{
if (!_win_selected)
{
_win_selected = _wins;
_e_winlist_show_active();
_e_winlist_activate();
}
return;
}
_e_winlist_deactivate();
if (!_win_selected)
_win_selected = _wins;
else
_win_selected = _win_selected->prev;
if (!_win_selected) _win_selected = eina_list_last(_wins);
_e_winlist_show_active();
_e_winlist_activate();
}
static void
_e_winlist_select(E_Client *ec)
{
Eina_Bool focus = EINA_FALSE;
if (ec->shaded)
{
if (!ec->lock_user_shade)
e_client_unshade(ec, ec->shade_dir);
}
if (ec->iconic)
e_client_uniconify(ec);
if ((!ec->lock_focus_out) &&
(!e_config->winlist_no_warp_on_direction) &&
((e_config->focus_policy != E_FOCUS_CLICK) ||
(e_config->winlist_warp_at_end) ||
(e_config->winlist_warp_while_selecting)))
{
if (!e_client_pointer_warp_to_center(ec))
focus = EINA_TRUE;
if (_list_object && (!_animator))
_animator = ecore_animator_add(_e_winlist_animator, NULL);
}
if ((!ec->lock_user_stacking) &&
(e_config->winlist_list_raise_while_selecting))
{
e_client_raise_latest_set(ec);
evas_object_raise(ec->frame);
}
if ((!ec->lock_focus_out) &&
(e_config->winlist_list_focus_while_selecting))
focus = EINA_TRUE;
if (focus)
evas_object_focus_set(ec->frame, 1);
}
void
e_winlist_left(E_Zone *zone)
{
E_Client *ec;
Eina_List *l;
E_Desk *desk;
E_Client *ec_orig;
int delta = INT_MAX;
int delta2 = INT_MAX;
int center;
_ec_next = NULL;
E_OBJECT_CHECK(zone);
E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
ec_orig = e_client_focused_get();
if (!ec_orig) return;
center = ec_orig->x + ec_orig->w / 2;
desk = e_desk_current_get(zone);
EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec)
{
int center_next;
int delta_next;
int delta2_next;
if (ec == ec_orig) continue;
if ((!ec->icccm.accepts_focus) &&
(!ec->icccm.take_focus)) continue;
if (ec->netwm.state.skip_taskbar) continue;
if (ec->user_skip_winlist) continue;
if (ec->iconic)
{
if (!e_config->winlist_list_show_iconified) continue;
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_iconified))
continue;
if ((ec->desk != desk) &&
(!e_config->winlist_list_show_other_desk_iconified)) continue;
}
else
{
if (ec->sticky)
{
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_windows))
continue;
}
else
{
if (ec->desk != desk)
{
if ((ec->zone) && (ec->zone != zone))
{
if (!e_config->winlist_list_show_other_screen_windows)
continue;
}
else if (!e_config->winlist_list_show_other_desk_windows)
continue;
}
}
}
/* ec is suitable */
center_next = ec->x + ec->w / 2;
if (center_next >= center) continue;
delta_next = ec_orig->x - (ec->x + ec->w);
if (delta_next < 0) delta_next = center - center_next;
delta2_next = abs(ec_orig->y - ec_orig->h / 2 - ec->y + ec->h/2);
if (delta_next >= 0 && delta_next <= delta &&
delta2_next >= 0 && delta2_next <= delta2)
{
_ec_next = ec;
delta = delta_next;
delta2 = delta2_next;
}
}
if (_ec_next) _e_winlist_select(_ec_next);
}
void
e_winlist_down(E_Zone *zone)
{
E_Client *ec;
Eina_List *l;
E_Desk *desk;
E_Client *ec_orig;
int delta = INT_MAX;
int delta2 = INT_MAX;
int center;
_ec_next = NULL;
E_OBJECT_CHECK(zone);
E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
ec_orig = e_client_focused_get();
if (!ec_orig) return;
center = ec_orig->y + ec_orig->h / 2;
desk = e_desk_current_get(zone);
EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec)
{
int center_next;
int delta_next;
int delta2_next;
if (ec == ec_orig) continue;
if ((!ec->icccm.accepts_focus) &&
(!ec->icccm.take_focus)) continue;
if (ec->netwm.state.skip_taskbar) continue;
if (ec->user_skip_winlist) continue;
if (ec->iconic)
{
if (!e_config->winlist_list_show_iconified) continue;
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_iconified))
continue;
if ((ec->desk != desk) &&
(!e_config->winlist_list_show_other_desk_iconified)) continue;
}
else
{
if (ec->sticky)
{
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_windows))
continue;
}
else
{
if (ec->desk != desk)
{
if ((ec->zone) && (ec->zone != zone))
{
if (!e_config->winlist_list_show_other_screen_windows)
continue;
}
else if (!e_config->winlist_list_show_other_desk_windows)
continue;
}
}
}
/* ec is suitable */
center_next = ec->y + ec->h / 2;
if (center_next <= center) continue;
delta_next = ec->y - (ec_orig->y + ec_orig->h);
if (delta_next < 0) delta_next = center - center_next;
delta2_next = abs(ec_orig->x - ec_orig->w / 2 - ec->x + ec->w/2);
if (delta_next >= 0 && delta_next <= delta &&
delta2_next >= 0 && delta2_next <= delta2)
{
_ec_next = ec;
delta = delta_next;
delta2 = delta2_next;
}
}
if (_ec_next) _e_winlist_select(_ec_next);
}
void
e_winlist_up(E_Zone *zone)
{
E_Client *ec;
Eina_List *l;
E_Desk *desk;
E_Client *ec_orig;
int delta = INT_MAX;
int delta2 = INT_MAX;
int center;
_ec_next = NULL;
E_OBJECT_CHECK(zone);
E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
ec_orig = e_client_focused_get();
if (!ec_orig) return;
center = ec_orig->y + ec_orig->h / 2;
desk = e_desk_current_get(zone);
EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec)
{
int center_next;
int delta_next;
int delta2_next;
if (ec == ec_orig) continue;
if ((!ec->icccm.accepts_focus) &&
(!ec->icccm.take_focus)) continue;
if (ec->netwm.state.skip_taskbar) continue;
if (ec->user_skip_winlist) continue;
if (ec->iconic)
{
if (!e_config->winlist_list_show_iconified) continue;
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_iconified))
continue;
if ((ec->desk != desk) &&
(!e_config->winlist_list_show_other_desk_iconified)) continue;
}
else
{
if (ec->sticky)
{
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_windows))
continue;
}
else
{
if (ec->desk != desk)
{
if ((ec->zone) && (ec->zone != zone))
{
if (!e_config->winlist_list_show_other_screen_windows)
continue;
}
else if (!e_config->winlist_list_show_other_desk_windows)
continue;
}
}
}
/* ec is suitable */
center_next = ec->y + ec->h / 2;
if (center_next >= center) continue;
delta_next = ec_orig->y - (ec->y + ec->h);
if (delta_next < 0) delta_next = center - center_next;
delta2_next = abs(ec_orig->x - ec_orig->w / 2 - ec->x + ec->w/2);
if (delta_next >= 0 && delta_next <= delta &&
delta2_next >= 0 && delta2_next <= delta2)
{
_ec_next = ec;
delta = delta_next;
delta2 = delta2_next;
}
}
if (_ec_next) _e_winlist_select(_ec_next);
}
void
e_winlist_right(E_Zone *zone)
{
E_Client *ec;
Eina_List *l;
E_Desk *desk;
E_Client *ec_orig;
int delta = INT_MAX;
int delta2 = INT_MAX;
int center;
_ec_next = NULL;
E_OBJECT_CHECK(zone);
E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
ec_orig = e_client_focused_get();
if (!ec_orig) return;
center = ec_orig->x + ec_orig->w / 2;
desk = e_desk_current_get(zone);
EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec)
{
int center_next;
int delta_next;
int delta2_next;
if (ec == ec_orig) continue;
if ((!ec->icccm.accepts_focus) &&
(!ec->icccm.take_focus)) continue;
if (ec->netwm.state.skip_taskbar) continue;
if (ec->user_skip_winlist) continue;
if (ec->iconic)
{
if (!e_config->winlist_list_show_iconified) continue;
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_iconified))
continue;
if ((ec->desk != desk) &&
(!e_config->winlist_list_show_other_desk_iconified)) continue;
}
else
{
if (ec->sticky)
{
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_windows))
continue;
}
else
{
if (ec->desk != desk)
{
if ((ec->zone) && (ec->zone != zone))
{
if (!e_config->winlist_list_show_other_screen_windows)
continue;
}
else if (!e_config->winlist_list_show_other_desk_windows)
continue;
}
}
}
/* ec is suitable */
center_next = ec->x + ec->w / 2;
if (center_next <= center) continue;
delta_next = ec->x - (ec_orig->x + ec_orig->w);
if (delta_next < 0) delta = center_next - center;
delta2_next = abs(ec_orig->y - ec_orig->h / 2 - ec->y + ec->h/2);
if (delta_next >= 0 && delta_next <= delta &&
delta2_next >= 0 && delta2_next <= delta2)
{
_ec_next = ec;
delta = delta_next;
delta2 = delta2_next;
}
}
if (_ec_next) _e_winlist_select(_ec_next);
}
void
e_winlist_modifiers_set(int mod, E_Winlist_Activate_Type type)
{
if (!_winlist) return;
_hold_mod = mod;
_hold_count = 0;
_activate_type = type;
if (type == E_WINLIST_ACTIVATE_TYPE_MOUSE) _hold_count++;
if (_hold_mod & ECORE_EVENT_MODIFIER_SHIFT) _hold_count++;
if (_hold_mod & ECORE_EVENT_MODIFIER_CTRL) _hold_count++;
if (_hold_mod & ECORE_EVENT_MODIFIER_ALT) _hold_count++;
if (_hold_mod & ECORE_EVENT_MODIFIER_WIN) _hold_count++;
}
/* local subsystem functions */
static void
_e_winlist_size_adjust(void)
{
Evas_Coord mw, mh;
E_Zone *zone;
int x, y, w, h;
e_box_freeze(_list_object);
e_box_size_min_get(_list_object, &mw, &mh);
edje_extern_object_min_size_set(_list_object, mw, mh);
edje_object_part_swallow(_bg_object, "e.swallow.list", _list_object);
edje_object_size_min_calc(_bg_object, &mw, &mh);
edje_extern_object_min_size_set(_list_object, -1, -1);
edje_object_part_swallow(_bg_object, "e.swallow.list", _list_object);
e_box_thaw(_list_object);
zone = _winlist_zone;
w = (double)zone->w * e_config->winlist_pos_size_w;
if (w < mw) w = mw;
if (w > e_config->winlist_pos_max_w) w = e_config->winlist_pos_max_w;
else if (w < e_config->winlist_pos_min_w)
w = e_config->winlist_pos_min_w;
if (w > zone->w) w = zone->w;
x = zone->x + (double)(zone->w - w) * e_config->winlist_pos_align_x;
h = mh;
if (h > e_config->winlist_pos_max_h) h = e_config->winlist_pos_max_h;
else if (h < e_config->winlist_pos_min_h)
h = e_config->winlist_pos_min_h;
if (h > zone->h) h = zone->h;
y = zone->y + (double)(zone->h - h) * e_config->winlist_pos_align_y;
evas_object_geometry_set(_winlist, x, y, w, h);
}
static void
_e_winlist_client_add(E_Client *ec, E_Zone *zone, E_Desk *desk)
{
E_Winlist_Win *ww;
Evas_Coord mw, mh;
Evas_Object *o;
if ((!ec->icccm.accepts_focus) &&
(!ec->icccm.take_focus)) return;
if (ec->netwm.state.skip_taskbar) return;
if (ec->user_skip_winlist) return;
if (ec->iconic)
{
if (!e_config->winlist_list_show_iconified) return;
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_iconified)) return;
if ((ec->desk != desk) &&
(!e_config->winlist_list_show_other_desk_iconified)) return;
}
else
{
if (ec->sticky)
{
if ((ec->zone != zone) &&
(!e_config->winlist_list_show_other_screen_windows)) return;
}
else
{
if (ec->desk != desk)
{
if ((ec->zone) && (ec->zone != zone))
{
if (!e_config->winlist_list_show_other_screen_windows)
return;
if (ec->zone && ec->desk && (ec->desk != e_desk_current_get(ec->zone)))
{
if (!e_config->winlist_list_show_other_desk_windows)
return;
}
}
else if (!e_config->winlist_list_show_other_desk_windows)
return;
}
}
}
ww = E_NEW(E_Winlist_Win, 1);
if (!ww) return;
ww->client = ec;
_wins = eina_list_append(_wins, ww);
o = edje_object_add(ec->comp->evas);
e_comp_object_util_del_list_append(_winlist, o);
ww->bg_object = o;
e_theme_edje_object_set(o, "base/theme/winlist",
"e/widgets/winlist/item");
edje_object_part_text_set(o, "e.text.label", e_client_util_name_get(ww->client));
evas_object_show(o);
if (edje_object_part_exists(ww->bg_object, "e.swallow.icon"))
{
o = e_client_icon_add(ec, ec->comp->evas);
ww->icon_object = o;
e_comp_object_util_del_list_append(_winlist, o);
edje_object_part_swallow(ww->bg_object, "e.swallow.icon", o);
evas_object_show(o);
}
if (ec->shaded)
edje_object_signal_emit(ww->bg_object, "e,state,shaded", "e");
else if (ec->iconic)
edje_object_signal_emit(ww->bg_object, "e,state,iconified", "e");
else if (ec->desk != desk)
{
if (!((ec->sticky) && (ec->zone == zone)))
edje_object_signal_emit(ww->bg_object, "e,state,invisible", "e");
}
edje_object_size_min_calc(ww->bg_object, &mw, &mh);
e_box_pack_end(_list_object, ww->bg_object);
e_box_pack_options_set(ww->bg_object,
1, 1, /* fill */
1, 0, /* expand */
0.5, 0.5, /* align */
mw, mh, /* min */
9999, mh /* max */
);
e_object_ref(E_OBJECT(ww->client));
}
static void
_e_winlist_client_del(E_Client *ec)
{
E_Winlist_Win *ww;
Eina_List *l;
if (ec == _last_client) _last_client = NULL;
EINA_LIST_FOREACH(_wins, l, ww)
{
if (ww->client == ec)
{
e_object_unref(E_OBJECT(ww->client));
if (l == _win_selected)
{
_win_selected = l->next;
if (!_win_selected) _win_selected = l->prev;
_e_winlist_show_active();
_e_winlist_activate();
}
e_comp_object_util_del_list_remove(_winlist, ww->bg_object);
evas_object_del(ww->bg_object);
if (ww->icon_object)
{
e_comp_object_util_del_list_remove(_winlist, ww->icon_object);
evas_object_del(ww->icon_object);
}
E_FREE(ww);
_wins = eina_list_remove_list(_wins, l);
return;
}
}
}
static void
_e_winlist_activate_nth(int n)
{
Eina_List *l;
int cnt;
_e_winlist_deactivate();
cnt = eina_list_count(_wins);
if (n >= cnt) n = cnt - 1;
l = eina_list_nth_list(_wins, n);
if (!l) return;
_win_selected = l;
_e_winlist_show_active();
_e_winlist_activate();
}
static void
_e_winlist_activate(void)
{
E_Winlist_Win *ww;
Evas_Object *o;
int ok = 0;
if (!_win_selected) return;
ww = _win_selected->data;
edje_object_signal_emit(ww->bg_object, "e,state,selected", "e");
if (ww->icon_object)
edje_object_signal_emit(ww->icon_object,
"e,state,selected", "e");
if ((ww->client->iconic) &&
(e_config->winlist_list_uncover_while_selecting))
{
if (!ww->client->lock_user_iconify)
e_client_uniconify(ww->client);
ww->was_iconified = 1;
ok = 1;
}
if ((!ww->client->sticky) &&
(ww->client->desk != e_desk_current_get(_winlist_zone)) &&
(e_config->winlist_list_jump_desk_while_selecting))
{
if (ww->client->desk) e_desk_show(ww->client->desk);
ok = 1;
}
if ((ww->client->shaded || ww->client->shading) &&
(ww->client->desk == e_desk_current_get(_winlist_zone)) &&
(e_config->winlist_list_uncover_while_selecting))
{
if (!ww->client->lock_user_shade)
e_client_unshade(ww->client, ww->client->shade_dir);
ww->was_shaded = 1;
ok = 1;
}
if ((!ww->client->iconic) &&
((ww->client->desk == e_desk_current_get(_winlist_zone)) ||
(ww->client->sticky)))
ok = 1;
if (ok)
{
int set = 1;
if (e_config->winlist_warp_while_selecting)
{
if (!e_client_pointer_warp_to_center_now(ww->client))
{
evas_object_focus_set(ww->client->frame, 1);
set = 0;
}
if (!_animator)
_animator = ecore_animator_add(_e_winlist_animator, NULL);
}
else
{
E_FREE_FUNC(_animator, ecore_animator_del);
}
if ((!ww->client->lock_user_stacking) &&
(e_config->winlist_list_raise_while_selecting))
evas_object_raise(ww->client->frame);
if ((!ww->client->lock_focus_out) &&
(e_config->winlist_list_focus_while_selecting))
{
if (set)
evas_object_focus_set(ww->client->frame, 1);
}
}
edje_object_part_text_set(_bg_object, "e.text.label",
e_client_util_name_get(ww->client));
if (_icon_object)
{
e_comp_object_util_del_list_remove(_winlist, _icon_object);
evas_object_del(_icon_object);
_icon_object = NULL;
}
if (edje_object_part_exists(_bg_object, "e.swallow.icon"))
{
o = e_client_icon_add(ww->client, evas_object_evas_get(_winlist));
_icon_object = o;
e_comp_object_util_del_list_append(_winlist, o);
edje_object_part_swallow(_bg_object, "e.swallow.icon", o);
evas_object_show(o);
}
edje_object_signal_emit(_bg_object, "e,state,selected", "e");
}
static void
_e_winlist_deactivate(void)
{
E_Winlist_Win *ww;
if (!_win_selected) return;
ww = _win_selected->data;
if (ww->was_shaded)
{
if (!ww->client->lock_user_shade)
e_client_shade(ww->client, ww->client->shade_dir);
}
if (ww->was_iconified)
{
if (!ww->client->lock_user_iconify)
e_client_iconify(ww->client);
}
ww->was_shaded = 0;
ww->was_iconified = 0;
edje_object_part_text_set(_bg_object, "e.text.label", "");
edje_object_signal_emit(ww->bg_object, "e,state,unselected", "e");
if (ww->icon_object)
edje_object_signal_emit(ww->icon_object,
"e,state,unselected", "e");
if (!ww->client->lock_focus_in)
evas_object_focus_set(ww->client->frame, 0);
}
static void
_e_winlist_show_active(void)
{
Eina_List *l;
int i, n;
if (!_wins) return;
for (i = 0, l = _wins; l; l = l->next, i++)
if (l == _win_selected) break;
n = eina_list_count(_wins);
if (n <= 1) return;
_scroll_align_to = (double)i / (double)(n - 1);
if (e_config->winlist_scroll_animate)
{
_scroll_to = 1;
if (!_scroll_timer)
_scroll_timer = ecore_timer_add(0.01, _e_winlist_scroll_timer, NULL);
if (!_animator)
_animator = ecore_animator_add(_e_winlist_animator, NULL);
}
else
{
_scroll_align = _scroll_align_to;
e_box_align_set(_list_object, 0.5, _scroll_align);
}
}
static void
_e_winlist_restore_desktop(void)
{
if (_last_desk &&
(e_config->winlist_list_show_other_desk_windows ||
e_config->winlist_list_show_other_screen_windows))
e_desk_show(_last_desk);
if (e_config->winlist_warp_while_selecting)
ecore_evas_pointer_warp(_winlist_zone->comp->ee,
_last_pointer_x, _last_pointer_y);
_e_winlist_deactivate();
_win_selected = NULL;
e_winlist_hide();
if (_last_client)
{
evas_object_focus_set(_last_client->frame, 1);
_last_client = NULL;
}
}
static Eina_Bool
_e_winlist_cb_event_border_add(void *data __UNUSED__, int type __UNUSED__,
void *event)
{
E_Event_Client *ev = event;
_e_winlist_client_add(ev->ec, _winlist_zone,
e_desk_current_get(_winlist_zone));
_e_winlist_size_adjust();
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_winlist_cb_event_border_remove(void *data __UNUSED__, int type __UNUSED__,
void *event)
{
E_Event_Client *ev = event;
_e_winlist_client_del(ev->ec);
_e_winlist_size_adjust();
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_winlist_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event)
{
Ecore_Event_Key *ev;
ev = event;
if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
if (!strcmp(ev->key, "Up"))
e_winlist_prev();
else if (!strcmp(ev->key, "Down"))
e_winlist_next();
else if (!strcmp(ev->key, "Left"))
e_winlist_prev();
else if (!strcmp(ev->key, "Right"))
e_winlist_next();
else if (!strcmp(ev->key, "Return"))
e_winlist_hide();
else if (!strcmp(ev->key, "space"))
e_winlist_hide();
else if (!strcmp(ev->key, "Escape"))
_e_winlist_restore_desktop();
else if (!strcmp(ev->key, "1"))
_e_winlist_activate_nth(0);
else if (!strcmp(ev->key, "2"))
_e_winlist_activate_nth(1);
else if (!strcmp(ev->key, "3"))
_e_winlist_activate_nth(2);
else if (!strcmp(ev->key, "4"))
_e_winlist_activate_nth(3);
else if (!strcmp(ev->key, "5"))
_e_winlist_activate_nth(4);
else if (!strcmp(ev->key, "6"))
_e_winlist_activate_nth(5);
else if (!strcmp(ev->key, "7"))
_e_winlist_activate_nth(6);
else if (!strcmp(ev->key, "8"))
_e_winlist_activate_nth(7);
else if (!strcmp(ev->key, "9"))
_e_winlist_activate_nth(8);
else if (!strcmp(ev->key, "0"))
_e_winlist_activate_nth(9);
else
{
Eina_List *l;
E_Config_Binding_Key *binding;
E_Binding_Modifier mod;
EINA_LIST_FOREACH(e_bindings->key_bindings, l, binding)
{
if (binding->action != _winlist_act) continue;
mod = 0;
if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)
mod |= E_BINDING_MODIFIER_SHIFT;
if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)
mod |= E_BINDING_MODIFIER_CTRL;
if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT)
mod |= E_BINDING_MODIFIER_ALT;
if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN)
mod |= E_BINDING_MODIFIER_WIN;
if (binding->key && (!strcmp(binding->key, ev->key)) &&
((binding->modifiers == mod) || (binding->any_mod)))
{
if (!_act_winlist) continue;
if (_act_winlist->func.go_key)
_act_winlist->func.go_key(E_OBJECT(_winlist_zone), binding->params, ev);
else if (_act_winlist->func.go)
_act_winlist->func.go(E_OBJECT(_winlist_zone), binding->params);
}
}
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_winlist_cb_key_up(void *data __UNUSED__, int type __UNUSED__, void *event)
{
Ecore_Event_Key *ev;
Eina_List *l;
E_Config_Binding_Key *binding;
E_Binding_Modifier mod;
ev = event;
if (!_winlist) return ECORE_CALLBACK_PASS_ON;
if (_hold_mod)
{
#define KEY_CHECK(MOD, NAME) \
if ((_hold_mod & ECORE_EVENT_MODIFIER_##MOD) && (!strcmp(ev->key, NAME))) \
_hold_count--, _hold_mod &= ~ECORE_EVENT_MODIFIER_##MOD
KEY_CHECK(SHIFT, "Shift_L");
else KEY_CHECK(SHIFT, "Shift_R");
else KEY_CHECK(CTRL, "Control_L");
else KEY_CHECK(CTRL, "Control_R");
else KEY_CHECK(ALT, "Alt_L");
else KEY_CHECK(ALT, "Alt_R");
else KEY_CHECK(ALT, "Meta_L");
else KEY_CHECK(ALT, "Meta_R");
else KEY_CHECK(WIN, "Meta_L");
else KEY_CHECK(WIN, "Meta_R");
else KEY_CHECK(ALT, "Super_L");
else KEY_CHECK(ALT, "Super_R");
else KEY_CHECK(WIN, "Super_L");
else KEY_CHECK(WIN, "Super_R");
else KEY_CHECK(WIN, "Mode_switch");
if ((_hold_count <= 0) || ((!_hold_mod) && (_activate_type == E_WINLIST_ACTIVATE_TYPE_KEY)))
{
e_winlist_hide();
return 1;
}
}
EINA_LIST_FOREACH(e_bindings->key_bindings, l, binding)
{
if (binding->action != _winlist_act) continue;
mod = 0;
if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)
mod |= E_BINDING_MODIFIER_SHIFT;
if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)
mod |= E_BINDING_MODIFIER_CTRL;
if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT)
mod |= E_BINDING_MODIFIER_ALT;
if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN)
mod |= E_BINDING_MODIFIER_WIN;
if (binding->key && (!strcmp(binding->key, ev->key)) &&
((binding->modifiers == mod) || (binding->any_mod)))
{
if (!_act_winlist) continue;
if (_act_winlist->func.end_key)
_act_winlist->func.end_key(E_OBJECT(_winlist_zone), binding->params, ev);
else if (_act_winlist->func.end)
_act_winlist->func.end(E_OBJECT(_winlist_zone), binding->params);
}
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_winlist_cb_mouse_down(void *data __UNUSED__, int type __UNUSED__, void *event)
{
Ecore_Event_Mouse_Button *ev;
ev = event;
if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
e_bindings_mouse_down_ecore_event_handle(E_BINDING_CONTEXT_WINLIST,
E_OBJECT(_winlist_zone), ev);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_winlist_cb_mouse_up(void *data __UNUSED__, int type __UNUSED__, void *event)
{
Ecore_Event_Mouse_Button *ev;
ev = event;
if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
if (e_bindings_mouse_up_ecore_event_handle(E_BINDING_CONTEXT_WINLIST, E_OBJECT(_winlist_zone), ev))
return ECORE_CALLBACK_RENEW;
if (_activate_type != E_WINLIST_ACTIVATE_TYPE_MOUSE) return ECORE_CALLBACK_RENEW;
if (!--_hold_count) e_winlist_hide();
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_winlist_cb_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event)
{
Ecore_Event_Mouse_Wheel *ev;
int i;
ev = event;
if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
e_bindings_wheel_ecore_event_handle(E_BINDING_CONTEXT_WINLIST,
E_OBJECT(_winlist_zone), ev);
if (ev->z < 0) /* up */
{
for (i = ev->z; i < 0; i++)
e_winlist_prev();
}
else if (ev->z > 0) /* down */
{
for (i = ev->z; i > 0; i--)
e_winlist_next();
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_winlist_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event)
{
Ecore_Event_Mouse_Move *ev;
int x, y, w, h;
ev = event;
if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
evas_object_geometry_get(_winlist, &x, &y, &w, &h);
/* only feed mouse move if it's within the winlist popup */
if (E_INSIDE(ev->x, ev->y, x, y, w, h))
evas_event_feed_mouse_move(evas_object_evas_get(_winlist), ev->x, ev->y, ev->timestamp, NULL);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_winlist_scroll_timer(void *data __UNUSED__)
{
if (_scroll_to)
{
double spd;
spd = e_config->winlist_scroll_speed;
_scroll_align = (_scroll_align * (1.0 - spd)) +
(_scroll_align_to * spd);
return 1;
}
_scroll_timer = NULL;
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_e_winlist_animator(void *data __UNUSED__)
{
if (_scroll_to)
{
double da;
da = _scroll_align - _scroll_align_to;
if (da < 0.0) da = -da;
if (da < 0.01)
{
_scroll_align = _scroll_align_to;
_scroll_to = 0;
}
e_box_align_set(_list_object, 0.5, 1.0 - _scroll_align);
}
if (!_scroll_to) _animator = NULL;
return _scroll_to;
}
#if 0
static void
_e_winlist_cb_item_mouse_in(void *data, Evas *evas, Evas_Object *obj, void *event_info)
{
E_Winlist_Win *ww;
E_Winlist_Win *lww;
Eina_List *l;
if (!(ww = data)) return;
if (!_wins) return;
EINA_LIST_FOREACH(_wins, l, lww)
if (lww == ww) break;
_e_winlist_deactivate();
_win_selected = l;
_e_winlist_show_active();
_e_winlist_activate();
}
#endif