From c75b38a9d9ef6ab033b6a99eaba20303d91df9e4 Mon Sep 17 00:00:00 2001 From: Carsten Haitzler Date: Mon, 11 Feb 2013 12:26:30 +0000 Subject: [PATCH] work on contact. SVN revision: 83822 --- src/modules/Makefile_contact.am | 6 +- src/modules/contact/e_edges.c | 250 +++++++++++++++++++++++++++++++ src/modules/contact/e_edges.h | 20 +++ src/modules/contact/e_mod_main.c | 68 +++++++++ src/modules/contact/e_mod_main.h | 2 + src/modules/contact/e_policy.c | 243 ++++++++++++++++++++++++++++++ src/modules/contact/e_policy.h | 8 + 7 files changed, 596 insertions(+), 1 deletion(-) create mode 100644 src/modules/contact/e_edges.c create mode 100644 src/modules/contact/e_edges.h create mode 100644 src/modules/contact/e_policy.c create mode 100644 src/modules/contact/e_policy.h diff --git a/src/modules/Makefile_contact.am b/src/modules/Makefile_contact.am index e02243973..8b8300fc0 100644 --- a/src/modules/Makefile_contact.am +++ b/src/modules/Makefile_contact.am @@ -9,7 +9,11 @@ contactpkgdir = $(MDIR)/contact/$(MODULE_ARCH) contactpkg_LTLIBRARIES = contact/module.la contact_module_la_SOURCES = contact/e_mod_main.c \ - contact/e_mod_main.h + contact/e_mod_main.h \ + contact/e_policy.c \ + contact/e_policy.h \ + contact/e_edges.c \ + contact/e_edges.h # TODO: incomplete .PHONY: contact install-contact diff --git a/src/modules/contact/e_edges.c b/src/modules/contact/e_edges.c new file mode 100644 index 000000000..6d906f27c --- /dev/null +++ b/src/modules/contact/e_edges.c @@ -0,0 +1,250 @@ +#include "e_mod_main.h" + +typedef struct _Edgeset Edgeset; +typedef struct _Edgehandler Edgehandler; + +struct _Edgeset +{ + E_Zone *zone; + struct { + Evas_Object *obj; + } l, r, t, b; + struct { + int button, x, y; + Eina_Bool recognized : 1; + } down; +}; + +struct _Edgehandler +{ + E_Edges_Event event; + void (*func) (void *data, int d, double v); + void *data; +}; + +static Edgehandler *_handler_find(E_Edges_Event event); +static Evas_Object *_input_obj(Edgeset *es, int x, int y, int w, int h); +static Edgeset *_edgeset_new(E_Zone *zone); +static void _edgeset_free(Edgeset *es); +static void _cb_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event); +static void _cb_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event); +static void _cb_move(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event); + +static Eina_List *edges = NULL; +static Eina_List *handlers = NULL; + +void +e_edges_init(void) +{ + Eina_List *l, *ll, *lll; + E_Manager *man; + E_Container *con; + E_Zone *zone; + + EINA_LIST_FOREACH(e_manager_list(), l, man) + { + EINA_LIST_FOREACH(man->containers, ll, con) + { + EINA_LIST_FOREACH(con->zones, lll, zone) + { + Edgeset *es = _edgeset_new(zone); + + if (es) edges = eina_list_append(edges, es); + } + } + } +} + +void +e_edges_shutdown(void) +{ + Edgeset *es; + Edgehandler *eh; + + EINA_LIST_FREE(edges, es) _edgeset_free(es); + EINA_LIST_FREE(handlers, eh) free(eh); +} + +void +e_edges_handler_set(E_Edges_Event event, void (*func) (void *data, int d, double v), void *data) +{ + Edgehandler *eh; + + eh = _handler_find(event); + if (!eh) + { + eh = calloc(1, sizeof(*eh)); + if (!eh) return; + handlers = eina_list_append(handlers, eh); + } + eh->event = event; + eh->func = func; + eh->data = data; +} + +static Edgehandler * +_handler_find(E_Edges_Event event) +{ + Eina_List *l; + Edgehandler *eh; + + EINA_LIST_FOREACH(handlers, l, eh) + { + if (eh->event == event) + { + handlers = eina_list_promote_list(handlers, l); + return eh; + } + } + return NULL; +} + +static void +_handler_call(E_Edges_Event event, int d, double v) +{ + Edgehandler *eh = _handler_find(event); + + if (!eh) return; + if (!eh->func) return; + eh->func(eh->data, d, v); +} + +static Evas_Object * +_input_obj(Edgeset *es, int x, int y, int w, int h) +{ + E_Comp *c = es->zone->container->manager->comp; + Evas_Object *o = evas_object_rectangle_add(c->evas); + evas_object_color_set(o, 0, 0, 0, 0); + evas_object_move(o, x, y); + evas_object_resize(o, w, h); + evas_object_layer_set(o, 999); + evas_object_show(o); + evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _cb_down, es); + evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _cb_up, es); + evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _cb_move, es); + return o; +} + +static Edgeset * +_edgeset_new(E_Zone *zone) +{ + Edgeset *es = calloc(1, sizeof(*es)); + + if (!es) return NULL; + es->zone = zone; + + es->t.obj = _input_obj(es, zone->x, zone->y, zone->w, 8); + es->b.obj = _input_obj(es, zone->x, zone->y + zone->h - 8, zone->w, 8); + es->l.obj = _input_obj(es, zone->x, zone->y, 8, zone->h); + es->r.obj = _input_obj(es, zone->x + zone->w - 8, zone->y, 8, zone->h); + return es; +} + +static void +_edgeset_free(Edgeset *es) +{ + evas_object_del(es->t.obj); + evas_object_del(es->b.obj); + evas_object_del(es->l.obj); + evas_object_del(es->r.obj); + free(es); +} + +static void +_cb_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event) +{ + Edgeset *es = data; + Evas_Event_Mouse_Down *ev = event; + if (ev->button != 1) return; + es->down.button = ev->button; + es->down.x = ev->canvas.x; + es->down.y = ev->canvas.y; + es->down.recognized = EINA_FALSE; +} + +static void +_cb_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event) +{ + Edgeset *es = data; + Evas_Event_Mouse_Up *ev = event; + if (ev->button != 1) return; + es->down.button = 0; +} + +static void +_cb_move(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event) +{ + Edgeset *es = data; + Evas_Event_Mouse_Move *ev = event; + int dx, dy, d; + double v; + + if (!es->down.button) return; + dx = ev->cur.canvas.x - es->down.x; + dy = ev->cur.canvas.y - es->down.y; + d = 40; + if (obj == es->l.obj) + { + if ((!es->down.recognized) && (dx > d) && (abs(dy) < d)) + { + es->down.recognized = EINA_TRUE; + _handler_call(E_EDGES_LEFT_IN_BEGIN, 0, 0); + } + if (es->down.recognized) + { + d = (dx - d); + if (d < 0) d = 0; + if (es->zone->w > 1) v = (double)d / (es->zone->w / 2); + else v = 1.0; + _handler_call(E_EDGES_LEFT_IN_SLIDE, d, v); + } + } + else if (obj == es->r.obj) + { + if ((!es->down.recognized) && (-dx > d) && (abs(dy) < d)) + { + es->down.recognized = EINA_TRUE; + _handler_call(E_EDGES_RIGHT_IN_BEGIN, 0, 0); + } + if (es->down.recognized) + { + d = (-dx - d); + if (d < 0) d = 0; + if (es->zone->w > 1) v = (double)d / (es->zone->w / 2); + else v = 1.0; + _handler_call(E_EDGES_RIGHT_IN_SLIDE, d, v); + } + } + else if (obj == es->t.obj) + { + if ((!es->down.recognized) && (dy > d) && (abs(dx) < d)) + { + es->down.recognized = EINA_TRUE; + _handler_call(E_EDGES_TOP_IN_BEGIN, 0, 0); + } + if (es->down.recognized) + { + d = (dy - d); + if (d < 0) d = 0; + if (es->zone->h > 1) v = (double)d / (es->zone->h / 2); + else v = 1.0; + _handler_call(E_EDGES_TOP_IN_SLIDE, d, v); + } + } + else if (obj == es->b.obj) + { + if ((!es->down.recognized) && (-dy > d) && (abs(dx) < d)) + { + es->down.recognized = EINA_TRUE; + _handler_call(E_EDGES_BOTTOM_IN_BEGIN, 0, 0); + } + if (es->down.recognized) + { + d = (-dy - d); + if (d < 0) d = 0; + if (es->zone->h > 1) v = (double)d / (es->zone->h / 2); + else v = 1.0; + _handler_call(E_EDGES_BOTTOM_IN_SLIDE, d, v); + } + } +} diff --git a/src/modules/contact/e_edges.h b/src/modules/contact/e_edges.h new file mode 100644 index 000000000..3f8fad28b --- /dev/null +++ b/src/modules/contact/e_edges.h @@ -0,0 +1,20 @@ +#ifndef E_EDGES_H +# define E_EDGES_H + +typedef enum +{ + E_EDGES_LEFT_IN_BEGIN, + E_EDGES_RIGHT_IN_BEGIN, + E_EDGES_TOP_IN_BEGIN, + E_EDGES_BOTTOM_IN_BEGIN, + E_EDGES_LEFT_IN_SLIDE, + E_EDGES_RIGHT_IN_SLIDE, + E_EDGES_TOP_IN_SLIDE, + E_EDGES_BOTTOM_IN_SLIDE +} E_Edges_Event; + +void e_edges_init(void); +void e_edges_shutdown(void); +void e_edges_handler_set(E_Edges_Event event, void (*func) (void *data, int d, double v), void *data); + +#endif diff --git a/src/modules/contact/e_mod_main.c b/src/modules/contact/e_mod_main.c index 342597718..bdad7e4ec 100644 --- a/src/modules/contact/e_mod_main.c +++ b/src/modules/contact/e_mod_main.c @@ -2,15 +2,83 @@ EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Contact" }; +static void +_cb_in_left(void *data, int d, double v) +{ + // show PREV window in list from urrent focused window on top of current + // window but in an inital "off to the right" state in comp +} + +static void +_cb_in_left_go(void *data, int d, double v) +{ + // as v > 0 (and heads towards 1.0) flip/slide new window in unbtil v > 1.0 + // and once over 1.0 just do transition until end +} + +static void +_cb_in_right(void *data, int d, double v) +{ + // show NEXT window in list from urrent focused window on top of current + // window but in an inital "off to the right" state in comp +} + +static void +_cb_in_right_go(void *data, int d, double v) +{ + // as v > 0 (and heads towards 1.0) flip/slide new window in unbtil v > 1.0 + // and once over 1.0 just do transition until end +} + +static void +_cb_in_top(void *data, int d, double v) +{ + // show/populate top controls if not already there and start in offscreen + // state and beign slide in anim and place controls at final spot +} + +static void +_cb_in_top_go(void *data, int d, double v) +{ + // for now nothing - but animation would be nice for top controls +} + +static void +_cb_in_bottom(void *data, int d, double v) +{ + // force kbd activation if no kbd + e_policy_kbd_override_set(EINA_TRUE); + // if kbd already up... hmmm show app menu? +} + +static void +_cb_in_bottom_go(void *data, int d, double v) +{ + // for now nothing - but slide animation is nice +} + EAPI void * e_modapi_init(E_Module *m __UNUSED__) { + e_policy_init(); + e_edges_init(); + + e_edges_handler_set(E_EDGES_LEFT_IN_BEGIN, _cb_in_left, NULL); + e_edges_handler_set(E_EDGES_LEFT_IN_SLIDE, _cb_in_left_go, NULL); + e_edges_handler_set(E_EDGES_RIGHT_IN_BEGIN, _cb_in_right, NULL); + e_edges_handler_set(E_EDGES_RIGHT_IN_SLIDE, _cb_in_right_go, NULL); + e_edges_handler_set(E_EDGES_TOP_IN_BEGIN, _cb_in_top, NULL); + e_edges_handler_set(E_EDGES_TOP_IN_SLIDE, _cb_in_top_go, NULL); + e_edges_handler_set(E_EDGES_BOTTOM_IN_BEGIN, _cb_in_bottom, NULL); + e_edges_handler_set(E_EDGES_BOTTOM_IN_SLIDE, _cb_in_bottom_go, NULL); return m; } EAPI int e_modapi_shutdown(E_Module *m __UNUSED__) { + e_edges_shutdown(); + e_policy_shutdown(); return 1; } diff --git a/src/modules/contact/e_mod_main.h b/src/modules/contact/e_mod_main.h index 945f46ff8..8e1527af3 100644 --- a/src/modules/contact/e_mod_main.h +++ b/src/modules/contact/e_mod_main.h @@ -2,5 +2,7 @@ # define E_MOD_MAIN_H # include "e.h" +# include "e_policy.h" +# include "e_edges.h" #endif diff --git a/src/modules/contact/e_policy.c b/src/modules/contact/e_policy.c new file mode 100644 index 000000000..236516816 --- /dev/null +++ b/src/modules/contact/e_policy.c @@ -0,0 +1,243 @@ +#include "e_mod_main.h" + +static Eina_Bool _cb_event_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _cb_event_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event); +static void _cb_hook_post_fetch(void *data __UNUSED__, void *data2); +static void _cb_hook_post_assign(void *data __UNUSED__, void *data2); +static void _cb_hook_layout(void *data __UNUSED__, void *data2); + +static Eina_List *hooks = NULL; +static Eina_List *handlers = NULL; + +static Eina_Bool kbd_on = EINA_FALSE; +static Eina_Bool kbd_override = EINA_FALSE; + +#define LADD(l, f) l = eina_list_append(l, f) + +void +e_policy_init(void) +{ + LADD(hooks, e_border_hook_add(E_BORDER_HOOK_EVAL_POST_FETCH, + _cb_hook_post_fetch, NULL)); + LADD(hooks, e_border_hook_add(E_BORDER_HOOK_EVAL_POST_BORDER_ASSIGN, + _cb_hook_post_assign, NULL)); + LADD(hooks, e_border_hook_add(E_BORDER_HOOK_CONTAINER_LAYOUT, + _cb_hook_layout, NULL)); + LADD(handlers, ecore_event_handler_add(E_EVENT_BORDER_FOCUS_IN, + _cb_event_focus_in, NULL)); + LADD(handlers, ecore_event_handler_add(E_EVENT_BORDER_FOCUS_OUT, + _cb_event_focus_out, NULL)); +} + +void +e_policy_shutdown(void) +{ + E_Border_Hook *bh; + Ecore_Event_Handler *eh; + + EINA_LIST_FREE(hooks, bh) e_border_hook_del(bh); + EINA_LIST_FREE(handlers, eh) ecore_event_handler_del(eh); +} + +static Eina_Bool +_cb_event_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + E_Border *bd = event; + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_event_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + E_Border *bd = event; + + if (kbd_on) e_policy_kbd_override_set(EINA_FALSE); + return ECORE_CALLBACK_PASS_ON; +} + +static void +_cb_hook_post_fetch(void *data __UNUSED__, void *data2) +{ + E_Border *bd = data2; + + if (!bd) return; + /* NB: for this policy we disable all remembers set on a border */ + if (bd->remember) e_remember_del(bd->remember); + bd->remember = NULL; + + /* set this border to borderless */ + bd->borderless = 1; + bd->client.border.changed = 1; +} + +static void +_cb_hook_post_assign(void *data __UNUSED__, void *data2) +{ + E_Border *bd = data2; + + if (!bd) return; + + bd->internal_no_remember = 1; + + /* do not allow client to change these properties */ + bd->lock_client_size = 1; + bd->lock_client_shade = 1; + bd->lock_client_maximize = 1; + bd->lock_client_location = 1; + bd->lock_client_stacking = 1; + + /* do not allow the user to change these properties */ + bd->lock_user_location = 1; + bd->lock_user_size = 1; + bd->lock_user_shade = 1; + + /* clear any centered states */ + /* NB: this is mainly needed for E's main config dialog */ + bd->client.e.state.centered = 0; + + /* lock the border type so user/client cannot change */ + bd->lock_border = 1; +} + +void +e_policy_kbd_override_set(Eina_Bool override) +{ + Eina_List *l; + E_Border *bd, *kbd = NULL;; + + if (kbd_override == override) return; + kbd_override = override; + EINA_LIST_FOREACH(e_border_client_list(), l, bd) + { + if (bd->client.vkbd.vkbd) + { + kbd = bd; + } + } + if (kbd) + { + bd = kbd; + e_border_uniconify(bd); + e_border_raise(bd); + e_border_show(bd); + } +} + +static void +_cb_hook_layout(void *data __UNUSED__, void *data2) +{ + E_Container *con = data2; + Eina_List *l; + E_Border *bd, *kbd = NULL;; + Eina_Bool want_kbd = EINA_FALSE; + Eina_Bool have_focused = EINA_FALSE; + int kx = 0, ky = 0, kw = 0, kh = 0; + + if (!con) return; + + EINA_LIST_FOREACH(e_border_client_list(), l, bd) + { + if (bd->focused) have_focused = EINA_TRUE; + if ((bd->focused) && + (bd->client.vkbd.state > ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)) + want_kbd = EINA_TRUE; + if (bd->client.vkbd.vkbd) kbd = bd; + } + + if ((have_focused) && (kbd_override)) want_kbd = EINA_TRUE; + + if (kbd) + { + kw = kbd->zone->w; + kh = kbd->client.icccm.min_h; + kx = kbd->zone->x; + ky = kbd->zone->y + kbd->zone->h - kh; + } + EINA_LIST_FOREACH(e_border_client_list(), l, bd) + { + int x, y, w, h; + + if (!bd->zone) continue; + + w = bd->zone->w; + h = bd->zone->h; + x = bd->zone->x; + y = bd->zone->y; + + if (bd->client.vkbd.vkbd) + { + x = kx; y = ky; w = kw; h = kh; + if (want_kbd) + { + e_border_uniconify(bd); + e_border_raise(bd); + e_border_show(bd); + } + else + { + e_border_iconify(bd); + } + } + else if (((bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG) || + (bd->client.icccm.transient_for != 0)) && + ((bd->client.icccm.min_w == bd->client.icccm.max_w) && + (bd->client.icccm.min_h == bd->client.icccm.max_h))) + { + // center dialog at min size + w = bd->client.icccm.min_w; + h = bd->client.icccm.min_h; + if (w > (bd->zone->w)) w = bd->zone->w; + if (h > (bd->zone->h - kh)) h = (bd->zone->h - kh); + x = bd->zone->x + ((bd->zone->w - w) / 2); + y = bd->zone->y + ((bd->zone->h - kh - h) / 2); + } + else + { + if (bd->client.illume.conformant.conformant) + { + if (kbd_on != want_kbd) + { + if (want_kbd) + ecore_x_e_illume_keyboard_geometry_set(bd->client.win, + kx, ky, kw, kh); + else + ecore_x_e_illume_keyboard_geometry_set(bd->client.win, + 0, 0, 0, 0); + } + } + else + { + // just make all windows fill the zone... + if (want_kbd) + { + w = bd->zone->w; + h = bd->zone->h - kh; + x = bd->zone->x; + y = bd->zone->y; + } + } + } + + // implement the positioning/sizing + if ((bd->x != x) || (bd->y != y)) + { + bd->placed = 1; + bd->x = x; + bd->y = y; + bd->changes.pos = 1; + bd->changed = 1; + } + if ((bd->w != w) || (bd->h != h)) + { + bd->w = w; + bd->h = h; + bd->client.w = (bd->w - (bd->client_inset.l + bd->client_inset.r)); + bd->client.h = (bd->h - (bd->client_inset.t + bd->client_inset.b)); + bd->changes.size = 1; + bd->changed = 1; + } + } + + kbd_on = want_kbd; +} diff --git a/src/modules/contact/e_policy.h b/src/modules/contact/e_policy.h new file mode 100644 index 000000000..44df36a5f --- /dev/null +++ b/src/modules/contact/e_policy.h @@ -0,0 +1,8 @@ +#ifndef E_POLICY_H +# define E_POLICY_H + +void e_policy_init(void); +void e_policy_shutdown(void); +void e_policy_kbd_override_set(Eina_Bool override); + +#endif