#include "e_illume_private.h" #include "e_mod_main.h" /* local function prototypes */ static Eina_Bool _e_mod_quickpanel_cb_client_message(void *data __UNUSED__, int type __UNUSED__, void *event); static Eina_Bool _e_mod_quickpanel_cb_mouse_up(void *data, int type __UNUSED__, void *event); static Eina_Bool _e_mod_quickpanel_cb_border_add(void *data __UNUSED__, int type __UNUSED__, void *event); static Eina_Bool _e_mod_quickpanel_cb_border_remove(void *data __UNUSED__, int type __UNUSED__, void *event); static Eina_Bool _e_mod_quickpanel_cb_border_resize(void *data __UNUSED__, int type __UNUSED__, void *event); static Eina_Bool _e_mod_quickpanel_cb_border_uniconify(void *data __UNUSED__, int type __UNUSED__, void *event); static void _e_mod_quickpanel_cb_post_fetch(void *data __UNUSED__, void *data2); static void _e_mod_quickpanel_cb_free(E_Illume_Quickpanel *qp); static Eina_Bool _e_mod_quickpanel_cb_delay_hide(void *data); static void _e_mod_quickpanel_slide(E_Illume_Quickpanel *qp, int visible, double len); static void _e_mod_quickpanel_hide(E_Illume_Quickpanel *qp); static Eina_Bool _e_mod_quickpanel_cb_animate(void *data); static void _e_mod_quickpanel_position_update(E_Illume_Quickpanel *qp); static void _e_mod_quickpanel_animate_down(E_Illume_Quickpanel *qp); static void _e_mod_quickpanel_animate_up(E_Illume_Quickpanel *qp); static void _e_mod_quickpanel_clickwin_show(E_Illume_Quickpanel *qp); static void _e_mod_quickpanel_clickwin_hide(E_Illume_Quickpanel *qp); /* local variables */ static Eina_List *_qp_hdls = NULL; static E_Border_Hook *_qp_hook = NULL; int e_mod_quickpanel_init(void) { /* add handlers for messages we are interested in */ _qp_hdls = eina_list_append(_qp_hdls, ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _e_mod_quickpanel_cb_client_message, NULL)); _qp_hdls = eina_list_append(_qp_hdls, ecore_event_handler_add(E_EVENT_BORDER_ADD, _e_mod_quickpanel_cb_border_add, NULL)); _qp_hdls = eina_list_append(_qp_hdls, ecore_event_handler_add(E_EVENT_BORDER_REMOVE, _e_mod_quickpanel_cb_border_remove, NULL)); _qp_hdls = eina_list_append(_qp_hdls, ecore_event_handler_add(E_EVENT_BORDER_RESIZE, _e_mod_quickpanel_cb_border_resize, NULL)); _qp_hdls = eina_list_append(_qp_hdls, ecore_event_handler_add(E_EVENT_BORDER_UNICONIFY, _e_mod_quickpanel_cb_border_uniconify, NULL)); /* add hook for new borders so we can test for qp borders */ _qp_hook = e_border_hook_add(E_BORDER_HOOK_EVAL_PRE_POST_FETCH, _e_mod_quickpanel_cb_post_fetch, NULL); return 1; } int e_mod_quickpanel_shutdown(void) { Ecore_Event_Handler *hdl; /* delete the event handlers */ EINA_LIST_FREE(_qp_hdls, hdl) ecore_event_handler_del(hdl); /* delete the border hook */ if (_qp_hook) e_border_hook_del(_qp_hook); _qp_hook = NULL; return 1; } E_Illume_Quickpanel * e_mod_quickpanel_new(E_Zone *zone) { E_Illume_Quickpanel *qp; /* try to allocate a new quickpanel object */ qp = E_OBJECT_ALLOC(E_Illume_Quickpanel, E_ILLUME_QP_TYPE, _e_mod_quickpanel_cb_free); if (!qp) return NULL; /* set quickpanel zone */ qp->zone = zone; qp->vert.dir = 0; qp->mouse_hdl = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _e_mod_quickpanel_cb_mouse_up, qp); return qp; } void e_mod_quickpanel_show(E_Illume_Quickpanel *qp) { E_Illume_Config_Zone *cz; int duration; if (!qp) return; /* delete the animator if it exists */ if (qp->animator) ecore_animator_del(qp->animator); qp->animator = NULL; /* delete any existing timer */ if (qp->timer) ecore_timer_del(qp->timer); qp->timer = NULL; /* if it's already visible, or has no borders to show, then get out */ if ((qp->visible) || (!qp->borders)) return; duration = _e_illume_cfg->animation.quickpanel.duration; /* grab the height of the indicator */ cz = e_illume_zone_config_get(qp->zone->num); qp->vert.isize = cz->indicator.size; /* check animation duration */ if (duration <= 0) { Eina_List *l; E_Border *bd; int ny = 0; ny = qp->vert.isize; if (qp->vert.dir == 1) ny = 0; /* if we are not animating, just show the borders */ EINA_LIST_FOREACH(qp->borders, l, bd) { if (!bd->visible) e_illume_border_show(bd); if (qp->vert.dir == 0) { e_border_fx_offset(bd, 0, ny); ny += bd->h; } else { ny -= bd->h; e_border_fx_offset(bd, 0, ny); } } qp->visible = 1; _e_mod_quickpanel_clickwin_show(qp); } else _e_mod_quickpanel_slide(qp, 1, (double)duration / 1000.0); } void e_mod_quickpanel_hide(E_Illume_Quickpanel *qp) { if (!qp->visible) return; if (!qp->timer) qp->timer = ecore_timer_add(0.2, _e_mod_quickpanel_cb_delay_hide, qp); } /* local functions */ static Eina_Bool _e_mod_quickpanel_cb_client_message(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_X_Event_Client_Message *ev; ev = event; if (ev->message_type == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE) { E_Zone *zone; if ((zone = e_util_zone_window_find(ev->win))) { E_Illume_Quickpanel *qp; if ((qp = e_illume_quickpanel_by_zone_get(zone))) { if (ev->data.l[0] == (int)ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF) _e_mod_quickpanel_hide(qp); else e_mod_quickpanel_show(qp); } } } else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE) { E_Zone *zone; if ((zone = e_util_zone_window_find(ev->win))) { E_Illume_Quickpanel *qp; if ((qp = e_illume_quickpanel_by_zone_get(zone))) { if (qp->visible) _e_mod_quickpanel_hide(qp); else e_mod_quickpanel_show(qp); } } } else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE) { E_Border *bd; E_Illume_Quickpanel *qp; if (!(bd = e_border_find_by_client_window(ev->win))) return ECORE_CALLBACK_PASS_ON; if (!(qp = e_illume_quickpanel_by_zone_get(bd->zone))) return ECORE_CALLBACK_PASS_ON; _e_mod_quickpanel_position_update(qp); } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_mod_quickpanel_cb_mouse_up(void *data, int type __UNUSED__, void *event) { Ecore_Event_Mouse_Button *ev; E_Illume_Quickpanel *qp; ev = event; if (!(qp = data)) return ECORE_CALLBACK_PASS_ON; if (ev->event_window != qp->clickwin) return ECORE_CALLBACK_PASS_ON; if (qp->visible) e_mod_quickpanel_hide(qp); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_mod_quickpanel_cb_border_add(void *data __UNUSED__, int type __UNUSED__, void *event) { E_Event_Border_Add *ev; E_Illume_Quickpanel *qp; E_Zone *zone; int iy; ev = event; if (!ev->border->client.illume.quickpanel.quickpanel) return ECORE_CALLBACK_PASS_ON; if (!(zone = ev->border->zone)) return ECORE_CALLBACK_PASS_ON; /* if this border should be on a different zone, get requested zone */ if ((int)zone->num != ev->border->client.illume.quickpanel.zone) { E_Container *con; int zn = 0; /* find this zone */ if (!(con = e_container_current_get(e_manager_current_get()))) return ECORE_CALLBACK_PASS_ON; zn = ev->border->client.illume.quickpanel.zone; zone = e_util_container_zone_number_get(con->num, zn); if (!zone) zone = e_util_container_zone_number_get(con->num, 0); if (!zone) return ECORE_CALLBACK_PASS_ON; } if (!(qp = e_illume_quickpanel_by_zone_get(zone))) return ECORE_CALLBACK_PASS_ON; /* set position and zone */ e_illume_border_indicator_pos_get(zone, NULL, &iy); if ((ev->border->x != zone->x) || (ev->border->y != iy)) e_border_move(ev->border, zone->x, iy); if (ev->border->zone != zone) e_border_zone_set(ev->border, zone); /* hide this border */ e_illume_border_hide(ev->border); qp->vert.size += ev->border->h; /* add this border to QP border collection */ qp->borders = eina_list_append(qp->borders, ev->border); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_mod_quickpanel_cb_border_remove(void *data __UNUSED__, int type __UNUSED__, void *event) { E_Event_Border_Remove *ev; E_Illume_Quickpanel *qp; E_Zone *zone; Eina_List *l; E_Border *bd; ev = event; if (!ev->border->client.illume.quickpanel.quickpanel) return ECORE_CALLBACK_PASS_ON; if (!(zone = ev->border->zone)) return ECORE_CALLBACK_PASS_ON; /* if this border should be on a different zone, get requested zone */ if ((int)zone->num != ev->border->client.illume.quickpanel.zone) { E_Container *con; int zn = 0; /* find this zone */ if (!(con = e_container_current_get(e_manager_current_get()))) return ECORE_CALLBACK_PASS_ON; zn = ev->border->client.illume.quickpanel.zone; zone = e_util_container_zone_number_get(con->num, zn); if (!zone) zone = e_util_container_zone_number_get(con->num, 0); if (!zone) return ECORE_CALLBACK_PASS_ON; } if (!(qp = e_illume_quickpanel_by_zone_get(zone))) return ECORE_CALLBACK_PASS_ON; /* add this border to QP border collection */ if (qp->borders) qp->borders = eina_list_remove(qp->borders, ev->border); qp->vert.size = 0; EINA_LIST_FOREACH(qp->borders, l, bd) qp->vert.size += bd->h; return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_mod_quickpanel_cb_border_resize(void *data __UNUSED__, int type __UNUSED__, void *event) { E_Event_Border_Resize *ev; E_Illume_Quickpanel *qp; Eina_List *l; E_Border *bd; ev = event; if (!ev->border->client.illume.quickpanel.quickpanel) return ECORE_CALLBACK_PASS_ON; if (!(qp = e_illume_quickpanel_by_zone_get(ev->border->zone))) return ECORE_CALLBACK_PASS_ON; qp->vert.size = 0; EINA_LIST_FOREACH(qp->borders, l, bd) qp->vert.size += bd->h; return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_mod_quickpanel_cb_border_uniconify(void *data __UNUSED__, int type __UNUSED__, void *event) { E_Event_Border_Uniconify *ev; E_Illume_Quickpanel *qp; ev = event; if (!ev->border->client.illume.quickpanel.quickpanel) return ECORE_CALLBACK_PASS_ON; if (!(qp = e_illume_quickpanel_by_zone_get(ev->border->zone))) return ECORE_CALLBACK_PASS_ON; e_mod_quickpanel_show(qp); return ECORE_CALLBACK_PASS_ON; } static void _e_mod_quickpanel_cb_post_fetch(void *data __UNUSED__, void *data2) { E_Border *bd; if (!(bd = data2)) return; if (!bd->client.illume.quickpanel.quickpanel) return; bd->stolen = 1; } static void _e_mod_quickpanel_cb_free(E_Illume_Quickpanel *qp) { E_Border *bd; /* delete the animator if it exists */ if (qp->animator) ecore_animator_del(qp->animator); qp->animator = NULL; /* delete the timer if it exists */ if (qp->timer) ecore_timer_del(qp->timer); qp->timer = NULL; /* delete the clickwin */ if (qp->clickwin) ecore_x_window_free(qp->clickwin); qp->clickwin = 0; /* delete the mouse handler */ if (qp->mouse_hdl) ecore_event_handler_del(qp->mouse_hdl); qp->mouse_hdl = NULL; /* set the borders of this quickpanel to not stolen */ EINA_LIST_FREE(qp->borders, bd) bd->stolen = 0; /* free the structure */ E_FREE(qp); } static Eina_Bool _e_mod_quickpanel_cb_delay_hide(void *data) { E_Illume_Quickpanel *qp; if (!(qp = data)) return ECORE_CALLBACK_CANCEL; _e_mod_quickpanel_hide(qp); return ECORE_CALLBACK_CANCEL; } static void _e_mod_quickpanel_slide(E_Illume_Quickpanel *qp, int visible, double len) { if (!qp) return; qp->start = ecore_loop_time_get(); qp->len = len; qp->vert.adjust_start = qp->vert.adjust; qp->vert.adjust_end = 0; if (qp->vert.dir == 0) { if (visible) qp->vert.adjust_end = qp->vert.size; } else { if (visible) qp->vert.adjust_end = -qp->vert.size; } if (!qp->animator) qp->animator = ecore_animator_add(_e_mod_quickpanel_cb_animate, qp); } static void _e_mod_quickpanel_hide(E_Illume_Quickpanel *qp) { int duration; if (!qp) return; /* delete the animator if it exists */ if (qp->animator) ecore_animator_del(qp->animator); qp->animator = NULL; /* delete the timer if it exists */ if (qp->timer) ecore_timer_del(qp->timer); qp->timer = NULL; /* if it's not visible, we can't hide it */ if (!qp->visible) return; duration = _e_illume_cfg->animation.quickpanel.duration; if (duration <= 0) { Eina_List *l; E_Border *bd; /* if we are not animating, hide the qp borders */ EINA_LIST_REVERSE_FOREACH(qp->borders, l, bd) { e_border_fx_offset(bd, 0, 0); if (bd->visible) e_illume_border_hide(bd); } qp->visible = 0; _e_mod_quickpanel_clickwin_hide(qp); } else _e_mod_quickpanel_slide(qp, 0, (double)duration / 1000.0); } static Eina_Bool _e_mod_quickpanel_cb_animate(void *data) { E_Illume_Quickpanel *qp; double t, v = 1.0; if (!(qp = data)) return ECORE_CALLBACK_CANCEL; t = (ecore_loop_time_get() - qp->start); if (t > qp->len) t = qp->len; if (qp->len > 0.0) { v = (t / qp->len); v = (1.0 - v); v = (v * v * v * v); v = (1.0 - v); } else t = qp->len; qp->vert.adjust = ((qp->vert.adjust_end * v) + (qp->vert.adjust_start * (1.0 - v))); if (qp->vert.dir == 0) _e_mod_quickpanel_animate_down(qp); else _e_mod_quickpanel_animate_up(qp); if (t == qp->len) { qp->animator = NULL; if (qp->visible) { qp->visible = 0; _e_mod_quickpanel_clickwin_hide(qp); } else { qp->visible = 1; _e_mod_quickpanel_clickwin_show(qp); } return ECORE_CALLBACK_CANCEL; } return ECORE_CALLBACK_RENEW; } static void _e_mod_quickpanel_position_update(E_Illume_Quickpanel *qp) { Eina_List *l; E_Border *bd; int iy = 0; if (!qp) return; _e_mod_quickpanel_hide(qp); if (!qp->zone) return; e_illume_border_indicator_pos_get(qp->zone, NULL, &iy); EINA_LIST_FOREACH(qp->borders, l, bd) e_border_move(bd, qp->zone->x, iy); qp->vert.dir = 0; if ((iy + qp->vert.isize + qp->vert.size) > qp->zone->h) qp->vert.dir = 1; } static void _e_mod_quickpanel_animate_down(E_Illume_Quickpanel *qp) { Eina_List *l; E_Border *bd; int pbh = 0; if (!qp) return; pbh = (qp->vert.isize - qp->vert.size); EINA_LIST_FOREACH(qp->borders, l, bd) { /* don't adjust borders that are being deleted */ if (e_object_is_del(E_OBJECT(bd))) continue; if (bd->fx.y != (qp->vert.adjust + pbh)) e_border_fx_offset(bd, 0, (qp->vert.adjust + pbh)); pbh += bd->h; if (!qp->visible) { if (bd->fx.y > 0) { if (!bd->visible) e_illume_border_show(bd); } } else { if (bd->fx.y <= 10) { if (bd->visible) e_illume_border_hide(bd); } } } } static void _e_mod_quickpanel_animate_up(E_Illume_Quickpanel *qp) { Eina_List *l; E_Border *bd; int pbh = 0; if (!qp) return; pbh = qp->vert.size; EINA_LIST_FOREACH(qp->borders, l, bd) { /* don't adjust borders that are being deleted */ if (e_object_is_del(E_OBJECT(bd))) continue; pbh -= bd->h; if (bd->fx.y != (qp->vert.adjust + pbh)) e_border_fx_offset(bd, 0, (qp->vert.adjust + pbh)); if (!qp->visible) { if (bd->fx.y < 0) { if (!bd->visible) e_illume_border_show(bd); } } else { if (bd->fx.y >= -10) { if (bd->visible) e_illume_border_hide(bd); } } } } static void _e_mod_quickpanel_clickwin_show(E_Illume_Quickpanel *qp) { E_Border *ind; if ((!qp) || (!qp->borders) || (!qp->zone)) return; if (!(ind = eina_list_nth(qp->borders, 0))) return; if (qp->clickwin) ecore_x_window_free(qp->clickwin); qp->clickwin = 0; qp->clickwin = ecore_x_window_input_new(qp->zone->container->win, qp->zone->x, qp->zone->y, qp->zone->w, qp->zone->h); ecore_x_window_configure(qp->clickwin, ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING | ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE, qp->zone->x, qp->zone->y, qp->zone->w, qp->zone->h, 0, ind->win, ECORE_X_WINDOW_STACK_BELOW); ecore_x_window_show(qp->clickwin); } static void _e_mod_quickpanel_clickwin_hide(E_Illume_Quickpanel *qp) { if (!qp) return; if (qp->clickwin) ecore_x_window_free(qp->clickwin); qp->clickwin = 0; }