#include "e.h" /* E_Zone is a child object of E_Comp. There is one zone per screen * in a xinerama setup. Each zone has one or more desktops. */ static void _e_zone_free(E_Zone *zone); static void _e_zone_cb_bg_mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info); static void _e_zone_cb_bg_mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info); static Eina_Bool _e_zone_cb_edge_timer(void *data); static void _e_zone_event_generic_free(void *data, void *ev); static void _e_zone_object_del_attach(void *o); static E_Zone_Edge _e_zone_detect_edge(E_Zone *zone, Evas_Object *obj); static void _e_zone_edge_move_resize(E_Zone *zone); static void _e_zone_obstacle_free(E_Zone_Obstacle *obs); E_API int E_EVENT_ZONE_DESK_COUNT_SET = 0; E_API int E_EVENT_POINTER_WARP = 0; E_API int E_EVENT_ZONE_USEFUL_GEOMETRY_CHANGED = 0; E_API int E_EVENT_ZONE_MOVE_RESIZE = 0; E_API int E_EVENT_ZONE_ADD = 0; E_API int E_EVENT_ZONE_DEL = 0; E_API int E_EVENT_ZONE_EDGE_IN = 0; E_API int E_EVENT_ZONE_EDGE_OUT = 0; E_API int E_EVENT_ZONE_EDGE_MOVE = 0; E_API int E_EVENT_ZONE_STOW = 0; E_API int E_EVENT_ZONE_UNSTOW = 0; #define E_ZONE_FLIP_LEFT(zone) (((e_config->desk_flip_wrap && ((zone)->desk_x_count > 1)) || ((zone)->desk_x_current > 0)) && (zone)->edge.left) #define E_ZONE_FLIP_RIGHT(zone) (((e_config->desk_flip_wrap && ((zone)->desk_x_count > 1)) || (((zone)->desk_x_current + 1) < (zone)->desk_x_count)) && (zone)->edge.right) #define E_ZONE_FLIP_UP(zone) (((e_config->desk_flip_wrap && ((zone)->desk_y_count > 1)) || ((zone)->desk_y_current > 0)) && (zone)->edge.top) #define E_ZONE_FLIP_DOWN(zone) (((e_config->desk_flip_wrap && ((zone)->desk_y_count > 1)) || (((zone)->desk_y_current + 1) < (zone)->desk_y_count)) && (zone)->edge.bottom) #define E_ZONE_CORNER_RATIO 0.025; EINTERN int e_zone_init(void) { E_EVENT_ZONE_DESK_COUNT_SET = ecore_event_type_new(); E_EVENT_POINTER_WARP = ecore_event_type_new(); E_EVENT_ZONE_MOVE_RESIZE = ecore_event_type_new(); E_EVENT_ZONE_USEFUL_GEOMETRY_CHANGED = ecore_event_type_new(); E_EVENT_ZONE_ADD = ecore_event_type_new(); E_EVENT_ZONE_DEL = ecore_event_type_new(); E_EVENT_ZONE_EDGE_IN = ecore_event_type_new(); E_EVENT_ZONE_EDGE_OUT = ecore_event_type_new(); E_EVENT_ZONE_EDGE_MOVE = ecore_event_type_new(); E_EVENT_ZONE_STOW = ecore_event_type_new(); E_EVENT_ZONE_UNSTOW = ecore_event_type_new(); return 1; } EINTERN int e_zone_shutdown(void) { return 1; } E_API void e_zone_all_edge_flip_eval(void) { const Eina_List *l; E_Zone *zone; EINA_LIST_FOREACH(e_comp->zones, l, zone) e_zone_edge_flip_eval(zone); } static void _e_zone_cb_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Evas_Event_Mouse_In *ev = event_info; E_Event_Zone_Edge *zev; E_Zone_Edge edge; E_Zone *zone = data; if (!ev->timestamp) return; edge = _e_zone_detect_edge(zone, obj); if (edge == E_ZONE_EDGE_NONE) return; zev = E_NEW(E_Event_Zone_Edge, 1); zev->zone = zone; zev->edge = edge; zev->x = ev->output.x; zev->y = ev->output.y; zev->modifiers = e_bindings_evas_modifiers_convert(ev->modifiers); zev->drag = !!evas_pointer_button_down_mask_get(e_comp->evas); ecore_event_add(E_EVENT_ZONE_EDGE_IN, zev, NULL, NULL); e_bindings_edge_in_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), zev); } static void _e_zone_cb_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Evas_Event_Mouse_Out *ev = event_info; E_Event_Zone_Edge *zev; E_Zone_Edge edge; E_Zone *zone = data; if (!ev->timestamp) return; edge = _e_zone_detect_edge(zone, obj); if (edge == E_ZONE_EDGE_NONE) return; zev = E_NEW(E_Event_Zone_Edge, 1); zev->zone = zone; zev->edge = edge; zev->x = ev->output.x; zev->y = ev->output.y; zev->modifiers = e_bindings_evas_modifiers_convert(ev->modifiers); zev->drag = !!evas_pointer_button_down_mask_get(e_comp->evas); ecore_event_add(E_EVENT_ZONE_EDGE_OUT, zev, NULL, NULL); e_bindings_edge_out_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), zev); } static void _e_zone_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Evas_Event_Mouse_Down *ev = event_info; E_Event_Zone_Edge *zev; E_Zone_Edge edge; E_Zone *zone = data; if (!ev->timestamp) return; edge = _e_zone_detect_edge(zone, obj); if (edge == E_ZONE_EDGE_NONE) return; zev = E_NEW(E_Event_Zone_Edge, 1); zev->zone = zone; zev->edge = edge; zev->x = ev->output.x; zev->y = ev->output.y; zev->button = ev->button; zev->modifiers = e_bindings_evas_modifiers_convert(ev->modifiers); ecore_event_add(E_EVENT_ZONE_EDGE_OUT, zev, NULL, NULL); e_bindings_edge_down_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), zev); } static void _e_zone_cb_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Evas_Event_Mouse_Up *ev = event_info; E_Event_Zone_Edge *zev; E_Zone_Edge edge; E_Zone *zone = data; if (!ev->timestamp) return; edge = _e_zone_detect_edge(zone, obj); if (edge == E_ZONE_EDGE_NONE) return; zev = E_NEW(E_Event_Zone_Edge, 1); zev->zone = zone; zev->edge = edge; zev->x = ev->output.x; zev->y = ev->output.y; zev->button = ev->button; zev->modifiers = e_bindings_evas_modifiers_convert(ev->modifiers); ecore_event_add(E_EVENT_ZONE_EDGE_OUT, zev, NULL, NULL); e_bindings_edge_up_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), zev); } static void _e_zone_cb_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Evas_Event_Mouse_Move *ev = event_info; E_Event_Zone_Edge *zev; E_Zone_Edge edge; E_Zone *zone = data; edge = _e_zone_detect_edge(zone, obj); if (edge == E_ZONE_EDGE_NONE) return; zev = E_NEW(E_Event_Zone_Edge, 1); zev->zone = zone; zev->edge = edge; zev->x = ev->cur.output.x; zev->y = ev->cur.output.y; zev->modifiers = e_bindings_evas_modifiers_convert(ev->modifiers); ecore_event_add(E_EVENT_ZONE_EDGE_MOVE, zev, NULL, NULL); } E_API E_Zone * e_zone_new(int num, int id, int x, int y, int w, int h) { E_Zone *zone; Evas_Object *o; E_Event_Zone_Add *ev; char name[40]; zone = E_OBJECT_ALLOC(E_Zone, E_ZONE_TYPE, _e_zone_free); if (!zone) return NULL; zone->x = x; zone->y = y; zone->w = w; zone->h = h; zone->num = num; zone->id = id; zone->useful_geometry_dirty = 1; zone->useful_geometry[0].x = zone->useful_geometry[0].y = zone->useful_geometry[0].w = zone->useful_geometry[0].h = -1; zone->useful_geometry[1].x = zone->useful_geometry[1].y = zone->useful_geometry[1].w = zone->useful_geometry[1].h = -1; //printf("@@@@@@@@@@ e_zone_new: %i %i | %i %i %ix%i = %p\n", num, id, x, y, w, h, zone); snprintf(name, sizeof(name), "Zone %d", zone->num); zone->name = eina_stringshare_add(name); e_comp->zones = eina_list_append(e_comp->zones, zone); o = evas_object_rectangle_add(e_comp->evas); zone->bg_clip_object = o; evas_object_repeat_events_set(o, 1); evas_object_layer_set(o, E_LAYER_BG); evas_object_name_set(o, "zone->bg_clip_object"); evas_object_move(o, x, y); evas_object_resize(o, w, h); evas_object_color_set(o, 255, 255, 255, 255); evas_object_show(o); o = evas_object_rectangle_add(e_comp->evas); zone->bg_event_object = o; evas_object_name_set(o, "zone->bg_event_object"); evas_object_clip_set(o, zone->bg_clip_object); evas_object_layer_set(o, E_LAYER_BG); evas_object_repeat_events_set(o, 1); evas_object_move(o, x, y); evas_object_resize(o, w, h); evas_object_color_set(o, 0, 0, 0, 0); evas_object_repeat_events_set(o, 1); evas_object_show(o); evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _e_zone_cb_bg_mouse_down, zone); evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _e_zone_cb_bg_mouse_up, zone); /* TODO: config the ecore_evas type. */ zone->desk_x_count = 0; zone->desk_y_count = 0; zone->desk_x_current = 0; zone->desk_y_current = 0; e_zone_desk_count_set(zone, e_config->zone_desks_x_count, e_config->zone_desks_y_count); e_object_del_attach_func_set(E_OBJECT(zone), _e_zone_object_del_attach); e_zone_all_edge_flip_eval(); if (starting) return zone; ev = E_NEW(E_Event_Zone_Add, 1); ev->zone = zone; e_object_ref(E_OBJECT(ev->zone)); ecore_event_add(E_EVENT_ZONE_ADD, ev, _e_zone_event_generic_free, NULL); return zone; } E_API void e_zone_name_set(E_Zone *zone, const char *name) { E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if (zone->name) eina_stringshare_del(zone->name); zone->name = eina_stringshare_add(name); } static void e_zone_reconfigure_clients(E_Zone *zone, int dx, int dy) { E_Client *ec; E_CLIENT_FOREACH(ec) { if (ec->zone != zone) continue; if ((dx != 0) || (dy != 0)) evas_object_move(ec->frame, ec->x + dx, ec->y + dy); } } E_API void e_zone_move(E_Zone *zone, int x, int y) { E_Event_Zone_Move_Resize *ev; int dx, dy; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if ((x == zone->x) && (y == zone->y)) return; dx = x - zone->x; dy = y - zone->y; zone->x = x; zone->y = y; evas_object_move(zone->bg_object, x, y); evas_object_move(zone->bg_event_object, x, y); evas_object_move(zone->bg_clip_object, x, y); ev = E_NEW(E_Event_Zone_Move_Resize, 1); ev->zone = zone; e_object_ref(E_OBJECT(ev->zone)); ecore_event_add(E_EVENT_ZONE_MOVE_RESIZE, ev, _e_zone_event_generic_free, NULL); _e_zone_edge_move_resize(zone); e_zone_bg_reconfigure(zone); e_zone_reconfigure_clients(zone, dx, dy); } E_API void e_zone_resize(E_Zone *zone, int w, int h) { E_Event_Zone_Move_Resize *ev; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if ((w == zone->w) && (h == zone->h)) return; zone->w = w; zone->h = h; evas_object_resize(zone->bg_object, w, h); evas_object_resize(zone->bg_event_object, w, h); evas_object_resize(zone->bg_clip_object, w, h); ev = E_NEW(E_Event_Zone_Move_Resize, 1); ev->zone = zone; e_object_ref(E_OBJECT(ev->zone)); ecore_event_add(E_EVENT_ZONE_MOVE_RESIZE, ev, _e_zone_event_generic_free, NULL); _e_zone_edge_move_resize(zone); e_zone_bg_reconfigure(zone); e_zone_reconfigure_clients(zone, 0, 0); } E_API Eina_Bool e_zone_move_resize(E_Zone *zone, int x, int y, int w, int h) { E_Event_Zone_Move_Resize *ev; int dx, dy; E_OBJECT_CHECK_RETURN(zone, EINA_FALSE); E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE); if ((x == zone->x) && (y == zone->y) && (w == zone->w) && (h == zone->h)) return EINA_FALSE; dx = x - zone->x; dy = y - zone->y; zone->x = x; zone->y = y; zone->w = w; zone->h = h; evas_object_move(zone->bg_object, x, y); evas_object_move(zone->bg_event_object, x, y); evas_object_move(zone->bg_clip_object, x, y); evas_object_resize(zone->bg_object, w, h); evas_object_resize(zone->bg_event_object, w, h); evas_object_resize(zone->bg_clip_object, w, h); ev = E_NEW(E_Event_Zone_Move_Resize, 1); ev->zone = zone; e_object_ref(E_OBJECT(ev->zone)); ecore_event_add(E_EVENT_ZONE_MOVE_RESIZE, ev, _e_zone_event_generic_free, NULL); _e_zone_edge_move_resize(zone); e_zone_bg_reconfigure(zone); e_zone_reconfigure_clients(zone, dx, dy); return EINA_TRUE; } E_API E_Zone * e_zone_current_get(void) { Eina_List *l = NULL; E_Zone *zone; if (!e_comp) return NULL; if (!starting) { int x, y; ecore_evas_pointer_xy_get(e_comp->ee, &x, &y); EINA_LIST_FOREACH(e_comp->zones, l, zone) { if (E_INSIDE(x, y, zone->x, zone->y, zone->w, zone->h)) return zone; } } if (!e_comp->zones) return NULL; return eina_list_data_get(e_comp->zones); } E_API void e_zone_bg_reconfigure(E_Zone *zone) { E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); e_bg_zone_update(zone, E_BG_TRANSITION_CHANGE); } E_API void e_zone_flip_coords_handle(E_Zone *zone, int x, int y) { E_Event_Zone_Edge *zev; E_Binding_Edge *binding; E_Zone_Edge edge; Eina_List *l; E_Shelf *es; int ok = 0; int one_row = 1; int one_col = 1; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if (zone->flip.switching) { int cx, cy, w, h; switch (zone->flip.switching) { case E_ZONE_EDGE_LEFT: evas_object_geometry_get(zone->edge.left, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) zone->flip.switching = E_ZONE_EDGE_NONE; break; case E_ZONE_EDGE_RIGHT: evas_object_geometry_get(zone->edge.right, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) zone->flip.switching = E_ZONE_EDGE_NONE; break; case E_ZONE_EDGE_TOP: evas_object_geometry_get(zone->edge.top, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) zone->flip.switching = E_ZONE_EDGE_NONE; break; case E_ZONE_EDGE_BOTTOM: evas_object_geometry_get(zone->edge.bottom, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) zone->flip.switching = E_ZONE_EDGE_NONE; break; case E_ZONE_EDGE_TOP_LEFT: evas_object_geometry_get(zone->corner.left_top, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) { evas_object_geometry_get(zone->corner.top_left, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) zone->flip.switching = E_ZONE_EDGE_NONE; } break; case E_ZONE_EDGE_TOP_RIGHT: evas_object_geometry_get(zone->corner.right_top, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) { evas_object_geometry_get(zone->corner.top_right, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) zone->flip.switching = E_ZONE_EDGE_NONE; } break; case E_ZONE_EDGE_BOTTOM_RIGHT: evas_object_geometry_get(zone->corner.right_bottom, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) { evas_object_geometry_get(zone->corner.bottom_right, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) zone->flip.switching = E_ZONE_EDGE_NONE; } break; case E_ZONE_EDGE_BOTTOM_LEFT: evas_object_geometry_get(zone->corner.left_bottom, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) { evas_object_geometry_get(zone->corner.bottom_left, &cx, &cy, &w, &h); if (!E_INSIDE(x, y, cx, cy, w, h)) zone->flip.switching = E_ZONE_EDGE_NONE; } break; default: break; } if (zone->flip.switching) return; } if (!e_config->edge_flip_dragging) return; /* if we have only 1 row we can flip up/down even if we have xinerama */ if (eina_list_count(e_comp->zones) > 1) { Eina_List *zones; E_Zone *next_zone; int cx, cy; zones = e_comp->zones; next_zone = (E_Zone *)eina_list_data_get(zones); cx = next_zone->x; cy = next_zone->y; zones = eina_list_next(zones); EINA_LIST_FOREACH(eina_list_next(zones), zones, next_zone) { if (next_zone->x != cx) one_col = 0; if (next_zone->y != cy) one_row = 0; } } if (!E_INSIDE(x, y, zone->x, zone->y, zone->w, zone->h)) goto noflip; if ((one_row) && (y == 0)) edge = E_ZONE_EDGE_TOP; else if ((one_col) && (x == (zone->w - 1))) edge = E_ZONE_EDGE_RIGHT; else if ((one_row) && (y == (zone->h - 1))) edge = E_ZONE_EDGE_BOTTOM; else if ((one_col) && (x == 0)) edge = E_ZONE_EDGE_LEFT; else { noflip: if (zone->flip.es) e_shelf_toggle(zone->flip.es, 0); zone->flip.es = NULL; return; } EINA_LIST_FOREACH(e_shelf_list(), l, es) { if (es->zone != zone) continue; switch (es->gadcon->orient) { case E_GADCON_ORIENT_TOP: case E_GADCON_ORIENT_CORNER_TL: case E_GADCON_ORIENT_CORNER_TR: if (edge == E_ZONE_EDGE_TOP) ok = 1; break; case E_GADCON_ORIENT_BOTTOM: case E_GADCON_ORIENT_CORNER_BL: case E_GADCON_ORIENT_CORNER_BR: if (edge == E_ZONE_EDGE_BOTTOM) ok = 1; break; case E_GADCON_ORIENT_LEFT: case E_GADCON_ORIENT_CORNER_LT: case E_GADCON_ORIENT_CORNER_LB: if (edge == E_ZONE_EDGE_LEFT) ok = 1; break; case E_GADCON_ORIENT_RIGHT: case E_GADCON_ORIENT_CORNER_RT: case E_GADCON_ORIENT_CORNER_RB: if (edge == E_ZONE_EDGE_RIGHT) ok = 1; break; default: ok = 0; break; } if (!ok) continue; if (!E_INSIDE(x, y, es->x, es->y, es->w, es->h)) continue; if (zone->flip.es) e_shelf_toggle(zone->flip.es, 0); zone->flip.es = es; e_shelf_toggle(es, 1); } ok = 0; switch (edge) { case E_ZONE_EDGE_LEFT: if (E_ZONE_FLIP_LEFT(zone)) ok = 1; break; case E_ZONE_EDGE_TOP: if (E_ZONE_FLIP_UP(zone)) ok = 1; break; case E_ZONE_EDGE_RIGHT: if (E_ZONE_FLIP_RIGHT(zone)) ok = 1; break; case E_ZONE_EDGE_BOTTOM: if (E_ZONE_FLIP_DOWN(zone)) ok = 1; break; default: ok = 0; break; } if (!ok) return; binding = e_bindings_edge_get("desk_flip_in_direction", edge, 0); if (!binding) binding = e_bindings_edge_get("desk_flip_by", edge, 0); if (binding && (!binding->timer)) { zev = E_NEW(E_Event_Zone_Edge, 1); zev->zone = zone; zev->x = x; zev->y = y; zev->edge = edge; zone->flip.ev = zev; zone->flip.bind = binding; zone->flip.switching = edge; binding->timer = ecore_timer_loop_add(((double)binding->delay), _e_zone_cb_edge_timer, zone); } } E_API void e_zone_desk_count_set(E_Zone *zone, int x_count, int y_count) { E_Desk **new_desks; E_Desk *desk, *new_desk; E_Client *ec; E_Event_Zone_Desk_Count_Set *ev; int x, y, xx, yy, moved, nx, ny; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); xx = x_count; if (xx < 1) xx = 1; yy = y_count; if (yy < 1) yy = 1; /* Orphaned window catcher; in case desk count gets reset */ moved = 0; if (zone->desk_x_current >= xx) moved = 1; if (zone->desk_y_current >= yy) moved = 1; if (moved) { nx = zone->desk_x_current; ny = zone->desk_y_current; if (zone->desk_x_current >= xx) nx = xx - 1; if (zone->desk_y_current >= yy) ny = yy - 1; e_desk_show(e_desk_at_xy_get(zone, nx, ny)); } new_desks = malloc(xx * yy * sizeof(E_Desk *)); for (x = 0; x < xx; x++) { for (y = 0; y < yy; y++) { if ((x < zone->desk_x_count) && (y < zone->desk_y_count)) desk = zone->desks[x + (y * zone->desk_x_count)]; else desk = e_desk_new(zone, x, y); new_desks[x + (y * xx)] = desk; } } /* catch windows that have fallen off the end if we got smaller */ if (xx < zone->desk_x_count) { for (y = 0; y < zone->desk_y_count; y++) { new_desk = zone->desks[xx - 1 + (y * zone->desk_x_count)]; for (x = xx; x < zone->desk_x_count; x++) { desk = zone->desks[x + (y * zone->desk_x_count)]; E_CLIENT_FOREACH(ec) { if (ec->desk == desk) e_client_desk_set(ec, new_desk); } e_object_del(E_OBJECT(desk)); } } } if (yy < zone->desk_y_count) { for (x = 0; x < zone->desk_x_count; x++) { new_desk = zone->desks[x + ((yy - 1) * zone->desk_x_count)]; for (y = yy; y < zone->desk_y_count; y++) { desk = zone->desks[x + (y * zone->desk_x_count)]; E_CLIENT_FOREACH(ec) { if (ec->desk == desk) e_client_desk_set(ec, new_desk); } e_object_del(E_OBJECT(desk)); } } } free(zone->desks); zone->desks = new_desks; zone->desk_x_count = xx; zone->desk_y_count = yy; e_config->zone_desks_x_count = xx; e_config->zone_desks_y_count = yy; e_config_save_queue(); /* Cannot call desk_current_get until the zone desk counts have been set * or else we end up with a "white background" because desk_current_get will * return NULL. */ desk = e_desk_current_get(zone); if (desk) { /* need to simulate "startup" conditions to force desk show to reevaluate here */ int s = starting; desk->visible = 0; starting = 1; e_desk_show(desk); starting = s; } e_zone_edge_flip_eval(zone); ev = E_NEW(E_Event_Zone_Desk_Count_Set, 1); if (!ev) return; ev->zone = zone; e_object_ref(E_OBJECT(ev->zone)); ecore_event_add(E_EVENT_ZONE_DESK_COUNT_SET, ev, _e_zone_event_generic_free, NULL); } E_API void e_zone_desk_count_get(E_Zone *zone, int *x_count, int *y_count) { E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if (x_count) *x_count = zone->desk_x_count; if (y_count) *y_count = zone->desk_y_count; } E_API void e_zone_desk_flip_by(E_Zone *zone, int dx, int dy) { E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); dx = zone->desk_x_current + dx; dy = zone->desk_y_current + dy; e_zone_desk_flip_to(zone, dx, dy); e_zone_edge_flip_eval(zone); } E_API void e_zone_desk_flip_to(E_Zone *zone, int x, int y) { E_Desk *desk; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if (e_config->desk_flip_wrap) { x = x % zone->desk_x_count; y = y % zone->desk_y_count; if (x < 0) x += zone->desk_x_count; if (y < 0) y += zone->desk_y_count; } else { if (x < 0) x = 0; else if (x >= zone->desk_x_count) x = zone->desk_x_count - 1; if (y < 0) y = 0; else if (y >= zone->desk_y_count) y = zone->desk_y_count - 1; } desk = e_desk_at_xy_get(zone, x, y); if (!desk) return; e_desk_show(desk); e_zone_edge_flip_eval(zone); } E_API void e_zone_desk_linear_flip_by(E_Zone *zone, int dx) { E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); dx = zone->desk_x_current + (zone->desk_y_current * zone->desk_x_count) + dx; if ((!e_config->desk_flip_wrap) && ((dx < 0) || (dx >= zone->desk_x_count * zone->desk_y_count))) return; dx = dx % (zone->desk_x_count * zone->desk_y_count); while (dx < 0) dx += (zone->desk_x_count * zone->desk_y_count); e_zone_desk_linear_flip_to(zone, dx); } E_API void e_zone_desk_linear_flip_to(E_Zone *zone, int x) { int y; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); y = x / zone->desk_x_count; x = x - (y * zone->desk_x_count); e_zone_desk_flip_to(zone, x, y); } E_API void e_zone_edge_enable(void) { const Eina_List *l; E_Zone *zone; EINA_LIST_FOREACH(e_comp->zones, l, zone) { if (zone->edge.left) evas_object_show(zone->edge.left); if (zone->edge.right) evas_object_show(zone->edge.right); if (zone->edge.top) evas_object_show(zone->edge.top); if (zone->edge.bottom) evas_object_show(zone->edge.bottom); if (zone->corner.left_top) evas_object_show(zone->corner.left_top); if (zone->corner.top_left) evas_object_show(zone->corner.top_left); if (zone->corner.top_right) evas_object_show(zone->corner.top_right); if (zone->corner.right_top) evas_object_show(zone->corner.right_top); if (zone->corner.right_bottom) evas_object_show(zone->corner.right_bottom); if (zone->corner.bottom_right) evas_object_show(zone->corner.bottom_right); if (zone->corner.bottom_left) evas_object_show(zone->corner.bottom_left); if (zone->corner.left_bottom) evas_object_show(zone->corner.left_bottom); e_zone_edge_flip_eval(zone); } } E_API void e_zone_edge_disable(void) { const Eina_List *l; E_Zone *zone; EINA_LIST_FOREACH(e_comp->zones, l, zone) { zone->flip.switching = E_ZONE_EDGE_NONE; if (zone->edge.left) evas_object_hide(zone->edge.left); if (zone->edge.right) evas_object_hide(zone->edge.right); if (zone->edge.top) evas_object_hide(zone->edge.top); if (zone->edge.bottom) evas_object_hide(zone->edge.bottom); if (zone->corner.left_top) evas_object_hide(zone->corner.left_top); if (zone->corner.top_left) evas_object_hide(zone->corner.top_left); if (zone->corner.top_right) evas_object_hide(zone->corner.top_right); if (zone->corner.right_top) evas_object_hide(zone->corner.right_top); if (zone->corner.right_bottom) evas_object_hide(zone->corner.right_bottom); if (zone->corner.bottom_right) evas_object_hide(zone->corner.bottom_right); if (zone->corner.bottom_left) evas_object_hide(zone->corner.bottom_left); if (zone->corner.left_bottom) evas_object_hide(zone->corner.left_bottom); } } E_API void e_zone_edges_desk_flip_capable(E_Zone *zone, Eina_Bool l, Eina_Bool r, Eina_Bool t, Eina_Bool b) { #define NEED_FLIP_EDGE(x) \ (e_bindings_edge_flippable_get(x) || e_bindings_edge_non_flippable_get(x)) #define NEED_EDGE(x) \ (e_bindings_edge_non_flippable_get(x)) #define CHECK_EDGE(v, ed, obj) \ do { \ if (v) { \ if (NEED_FLIP_EDGE(ed)) { if (zone->edge.obj) evas_object_show(zone->edge.obj); } \ else if (zone->edge.obj) \ evas_object_hide(zone->edge.obj); \ } \ else { \ if (NEED_EDGE(ed)) { if (zone->edge.obj) evas_object_show(zone->edge.obj); } \ else if (zone->edge.obj) \ evas_object_hide(zone->edge.obj); \ } \ } while (0) CHECK_EDGE(l, E_ZONE_EDGE_LEFT, left); CHECK_EDGE(r, E_ZONE_EDGE_RIGHT, right); CHECK_EDGE(t, E_ZONE_EDGE_TOP, top); CHECK_EDGE(b, E_ZONE_EDGE_BOTTOM, bottom); #define CHECK_CORNER(v1, v2, ed, obj1, obj2) \ if ((!v1) && (!v2)) { \ if (NEED_EDGE(ed)) { \ if (zone->corner.obj1) evas_object_show(zone->corner.obj1); \ if (zone->corner.obj2) evas_object_show(zone->corner.obj2); \ } \ else { \ if (zone->corner.obj1) evas_object_hide(zone->corner.obj1); \ if (zone->corner.obj2) evas_object_hide(zone->corner.obj2); \ } \ } \ else { \ if (NEED_FLIP_EDGE(ed)) { \ if (zone->corner.obj1) evas_object_show(zone->corner.obj1); \ if (zone->corner.obj2) evas_object_show(zone->corner.obj2); \ } \ else { \ if (zone->corner.obj1) evas_object_hide(zone->corner.obj1); \ if (zone->corner.obj2) evas_object_hide(zone->corner.obj2); \ } \ } CHECK_CORNER(l, t, E_ZONE_EDGE_TOP_LEFT, left_top, top_left); CHECK_CORNER(r, t, E_ZONE_EDGE_TOP_RIGHT, right_top, top_right); CHECK_CORNER(l, b, E_ZONE_EDGE_BOTTOM_LEFT, left_bottom, bottom_left); CHECK_CORNER(r, b, E_ZONE_EDGE_BOTTOM_RIGHT, right_bottom, bottom_right); } E_API Eina_Bool e_zone_exists_direction(E_Zone *zone, E_Zone_Edge edge) { Eina_List *l; E_Zone *z2; EINA_LIST_FOREACH(e_comp->zones, l, z2) { if (zone == z2) continue; switch (edge) { case E_ZONE_EDGE_TOP_LEFT: if (((E_SPANS_COMMON(0, zone->x + zone->w, z2->x, z2->w)) && (z2->y < zone->y)) || ((E_SPANS_COMMON(0, zone->y + zone->h, z2->y, z2->h)) && (z2->x < zone->x))) return EINA_TRUE; break; case E_ZONE_EDGE_TOP: if ((E_SPANS_COMMON(zone->x, zone->w, z2->x, z2->w)) && (z2->y < zone->y)) return EINA_TRUE; break; case E_ZONE_EDGE_TOP_RIGHT: if (((E_SPANS_COMMON(zone->x, 99999, z2->x, z2->w)) && (z2->y < zone->y)) || ((E_SPANS_COMMON(0, zone->y + zone->h, z2->y, z2->h)) && (z2->x >= (zone->x + zone->w)))) return EINA_TRUE; break; case E_ZONE_EDGE_LEFT: if ((E_SPANS_COMMON(zone->y, zone->h, z2->y, z2->h)) && (z2->x < zone->x)) return EINA_TRUE; break; case E_ZONE_EDGE_RIGHT: if ((E_SPANS_COMMON(zone->y, zone->h, z2->y, z2->h)) && (z2->x >= (zone->x + zone->w))) return EINA_TRUE; break; case E_ZONE_EDGE_BOTTOM_LEFT: if (((E_SPANS_COMMON(0, zone->x + zone->w, z2->x, z2->w)) && (z2->y >= (zone->y + zone->h))) || ((E_SPANS_COMMON(zone->y, 99999, z2->y, z2->h)) && (z2->x < zone->x))) return EINA_TRUE; break; case E_ZONE_EDGE_BOTTOM: if ((E_SPANS_COMMON(zone->x, zone->w, z2->x, z2->w)) && (z2->y >= (zone->y + zone->h))) return EINA_TRUE; break; case E_ZONE_EDGE_BOTTOM_RIGHT: if (((E_SPANS_COMMON(zone->x, 99999, z2->x, z2->w)) && (z2->y >= (zone->y + zone->h))) || ((E_SPANS_COMMON(zone->y, 99999, z2->y, z2->h)) && (z2->x < zone->x))) return EINA_TRUE; break; default: break; } } return EINA_FALSE; } E_API void e_zone_edge_flip_eval(E_Zone *zone) { Eina_Bool lf, rf, tf, bf; lf = rf = tf = bf = EINA_TRUE; if (zone->desk_x_count <= 1) lf = rf = EINA_FALSE; else if (!e_config->desk_flip_wrap) { if (zone->desk_x_current == 0) lf = EINA_FALSE; if (zone->desk_x_current == (zone->desk_x_count - 1)) rf = EINA_FALSE; } if (zone->desk_y_count <= 1) tf = bf = EINA_FALSE; else if (!e_config->desk_flip_wrap) { if (zone->desk_y_current == 0) tf = EINA_FALSE; if (zone->desk_y_current == (zone->desk_y_count - 1)) bf = EINA_FALSE; } e_zone_edges_desk_flip_capable(zone, lf, rf, tf, bf); } E_API void e_zone_edge_new(E_Zone_Edge edge) { const Eina_List *l; E_Zone *zone; int cw, ch; if (edge == E_ZONE_EDGE_NONE) return; EINA_LIST_FOREACH(e_comp->zones, l, zone) { // don't allow bindings on edges that are on the boundary // between zones if (e_zone_exists_direction(zone, edge)) continue; cw = zone->w * E_ZONE_CORNER_RATIO; ch = zone->h * E_ZONE_CORNER_RATIO; switch (edge) { #define EDGE_NEW(MEMBER, X, Y, W, H) do { \ if (!zone->MEMBER) \ { \ zone->MEMBER = evas_object_rectangle_add(e_comp->evas); \ evas_object_name_set(zone->MEMBER, #MEMBER); \ evas_object_move(zone->MEMBER, (X), (Y)); \ evas_object_resize(zone->MEMBER, (W), (H)); \ evas_object_repeat_events_set(zone->MEMBER, 1); \ evas_object_data_set(zone->MEMBER, "comp_repeat", (void*)1); \ evas_object_color_set(zone->MEMBER, 0, 0, 0, 0); \ evas_object_event_callback_add(zone->MEMBER, EVAS_CALLBACK_MOUSE_MOVE, _e_zone_cb_mouse_move, zone); \ evas_object_event_callback_add(zone->MEMBER, EVAS_CALLBACK_MOUSE_IN, _e_zone_cb_mouse_in, zone); \ evas_object_event_callback_add(zone->MEMBER, EVAS_CALLBACK_MOUSE_OUT, _e_zone_cb_mouse_out, zone); \ evas_object_event_callback_add(zone->MEMBER, EVAS_CALLBACK_MOUSE_DOWN, _e_zone_cb_mouse_down, zone); \ evas_object_event_callback_add(zone->MEMBER, EVAS_CALLBACK_MOUSE_UP, _e_zone_cb_mouse_up, zone); \ evas_object_show(zone->MEMBER); \ } \ } while (0) case E_ZONE_EDGE_LEFT: EDGE_NEW(edge.left, zone->x, zone->y + ch, 1, zone->h - 2 * ch); break; case E_ZONE_EDGE_RIGHT: EDGE_NEW(edge.right, zone->x + zone->w - 1, zone->y + ch, 1, zone->h - 2 * ch); break; case E_ZONE_EDGE_TOP: EDGE_NEW(edge.top, zone->x + 1 + cw, zone->y, zone->w - 2 * cw - 2, 1); break; case E_ZONE_EDGE_BOTTOM: EDGE_NEW(edge.bottom, zone->x + 1 + cw, zone->y + zone->h - 1, zone->w - 2 - 2 * cw, 1); break; case E_ZONE_EDGE_TOP_LEFT: EDGE_NEW(corner.left_top, zone->x, zone->y, 1, ch); EDGE_NEW(corner.top_left, zone->x + 1, zone->y, cw, 1); break; case E_ZONE_EDGE_TOP_RIGHT: EDGE_NEW(corner.top_right, zone->x + zone->w - cw - 2, zone->y, cw, 1); EDGE_NEW(corner.right_top, zone->x + zone->w - 1, zone->y, 1, ch); break; case E_ZONE_EDGE_BOTTOM_RIGHT: EDGE_NEW(corner.right_bottom, zone->x + zone->w - 1, zone->y + zone->h - ch, 1, ch); EDGE_NEW(corner.bottom_right, zone->x + zone->w - cw - 2, zone->y + zone->h - 1, cw, 1); break; case E_ZONE_EDGE_BOTTOM_LEFT: EDGE_NEW(corner.bottom_left, zone->x + 1, zone->y + zone->h - 1, cw, 1); EDGE_NEW(corner.left_bottom, zone->x, zone->y + zone->h - ch, 1, ch); break; default: continue; } if (e_config->fullscreen_flip) e_zone_edge_win_layer_set(zone, E_LAYER_CLIENT_EDGE_FULLSCREEN); else e_zone_edge_win_layer_set(zone, E_LAYER_CLIENT_EDGE); } } E_API void e_zone_edge_free(E_Zone_Edge edge) { const Eina_List *l; E_Zone *zone; if (edge == E_ZONE_EDGE_NONE) return; EINA_LIST_FOREACH(e_comp->zones, l, zone) { if (zone->flip.switching == edge) zone->flip.switching = E_ZONE_EDGE_NONE; switch (edge) { case E_ZONE_EDGE_NONE: /* noop */ break; case E_ZONE_EDGE_LEFT: E_FREE_FUNC(zone->edge.left, evas_object_del); break; case E_ZONE_EDGE_RIGHT: E_FREE_FUNC(zone->edge.right, evas_object_del); break; case E_ZONE_EDGE_TOP: E_FREE_FUNC(zone->edge.top, evas_object_del); break; case E_ZONE_EDGE_BOTTOM: E_FREE_FUNC(zone->edge.bottom, evas_object_del); break; case E_ZONE_EDGE_TOP_LEFT: E_FREE_FUNC(zone->corner.left_top, evas_object_del); E_FREE_FUNC(zone->corner.top_left, evas_object_del); break; case E_ZONE_EDGE_TOP_RIGHT: E_FREE_FUNC(zone->corner.top_right, evas_object_del); E_FREE_FUNC(zone->corner.right_top, evas_object_del); break; case E_ZONE_EDGE_BOTTOM_RIGHT: E_FREE_FUNC(zone->corner.right_bottom, evas_object_del); E_FREE_FUNC(zone->corner.bottom_right, evas_object_del); break; case E_ZONE_EDGE_BOTTOM_LEFT: E_FREE_FUNC(zone->corner.bottom_left, evas_object_del); E_FREE_FUNC(zone->corner.left_bottom, evas_object_del); break; } } } E_API void e_zone_edge_win_layer_set(E_Zone *zone, E_Layer layer) { #define EDGE_STACK(EDGE) do { \ if (zone->EDGE) \ { \ evas_object_layer_set(zone->EDGE, layer); \ evas_object_stack_below(zone->EDGE, e_comp->layers[e_comp_canvas_layer_map(layer)].obj); \ } \ } while (0) EDGE_STACK(corner.left_bottom); EDGE_STACK(corner.left_top); EDGE_STACK(corner.top_left); EDGE_STACK(corner.top_right); EDGE_STACK(corner.right_top); EDGE_STACK(corner.right_bottom); EDGE_STACK(corner.bottom_right); EDGE_STACK(corner.bottom_left); EDGE_STACK(edge.left); EDGE_STACK(edge.right); EDGE_STACK(edge.top); EDGE_STACK(edge.bottom); } E_API void e_zone_fade_handle(E_Zone *zone, int out, double tim) { EINA_SAFETY_ON_NULL_RETURN(zone); if (out == 1) { if ((e_backlight_exists()) && (!e_comp_config_get()->nofade)) { e_backlight_update(); zone->bloff = EINA_TRUE; zone->bl = e_backlight_level_get(zone); e_backlight_level_set(zone, 0.0, tim); } } else { if ((e_backlight_exists()) && (!e_comp_config_get()->nofade)) { zone->bloff = EINA_FALSE; e_backlight_update(); if (e_backlight_mode_get(zone) != E_BACKLIGHT_MODE_NORMAL) e_backlight_mode_set(zone, E_BACKLIGHT_MODE_NORMAL); else e_backlight_level_set(zone, e_config->backlight.normal, tim); } } } static void _e_zone_useful_geometry_calc(const E_Zone *zone, int dx, int dy, int *x, int *y, int *w, int *h) { E_Desk *desk; E_Zone_Obstacle *obs; Eina_Tiler *tiler; int zx, zy, zw, zh; Eina_Iterator *it; Eina_Rectangle geom = { 0 } , *rect; int size = 0; zx = zone->x; zy = zone->y; zw = zone->w; zh = zone->h; tiler = eina_tiler_new(zw, zh); eina_tiler_tile_size_set(tiler, 1, 1); eina_tiler_rect_add(tiler, &(Eina_Rectangle){0, 0, zw, zh}); EINA_INLIST_FOREACH(zone->obstacles, obs) { if (!E_INTERSECTS(obs->x, obs->y, obs->w, obs->h, zx, zy, zw, zh)) continue; if (obs->vertical) eina_tiler_rect_del(tiler, &(Eina_Rectangle){obs->x - zx, 0, obs->w, zh}); else eina_tiler_rect_del(tiler, &(Eina_Rectangle){0, obs->y - zy, zw, obs->h}); } desk = e_desk_at_xy_get(zone, dx, dy); if (desk) { EINA_INLIST_FOREACH(desk->obstacles, obs) { if (!E_INTERSECTS(obs->x, obs->y, obs->w, obs->h, zx, zy, zw, zh)) continue; if (obs->vertical) eina_tiler_rect_del(tiler, &(Eina_Rectangle){obs->x - zx, 0, obs->w, zh}); else eina_tiler_rect_del(tiler, &(Eina_Rectangle){0, obs->y - zy, zw, obs->h}); } } it = eina_tiler_iterator_new(tiler); EINA_ITERATOR_FOREACH(it, rect) { if (rect->w * rect->h < size) continue; size = rect->w * rect->h; geom = *rect; } eina_iterator_free(it); eina_tiler_free(tiler); if (x) *x = geom.x + zx; if (y) *y = geom.y + zy; if (w) *w = geom.w; if (h) *h = geom.h; } /** * Get (or calculate) the useful (or free, without any shelves) area. */ E_API Eina_Bool e_zone_useful_geometry_get(E_Zone *zone, int *x, int *y, int *w, int *h) { int zx, zy, zw, zh; E_OBJECT_CHECK_RETURN(zone, EINA_FALSE); E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE); if (zone->useful_geometry_dirty) { _e_zone_useful_geometry_calc(zone, zone->desk_x_current, zone->desk_y_current, &zx, &zy, &zw, &zh); memcpy(&zone->useful_geometry[0], &zone->useful_geometry[1], sizeof(Eina_Rectangle)); zone->useful_geometry[1].x = zx; zone->useful_geometry[1].y = zy; zone->useful_geometry[1].w = zw; zone->useful_geometry[1].h = zh; zone->useful_geometry_changed = !!memcmp(&zone->useful_geometry[0], &zone->useful_geometry[1], sizeof(Eina_Rectangle)); } zone->useful_geometry_dirty = 0; if (x) *x = zone->useful_geometry[1].x; if (y) *y = zone->useful_geometry[1].y; if (w) *w = zone->useful_geometry[1].w; if (h) *h = zone->useful_geometry[1].h; return zone->useful_geometry_changed; } E_API void e_zone_desk_useful_geometry_get(const E_Zone *zone, const E_Desk *desk, int *x, int *y, int *w, int *h) { E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); E_OBJECT_CHECK(desk); E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE); if (desk->zone != zone) CRI("zone/desk mismatch!"); _e_zone_useful_geometry_calc(zone, desk->x, desk->y, x, y, w, h); } /** * Mark as dirty so e_zone_useful_geometry_get() will need to recalculate. * * Call this function when shelves are added or important properties changed. */ E_API void e_zone_useful_geometry_dirty(E_Zone *zone) { E_Event_Zone_Move_Resize *ev; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); /* ignore if pending event already exists */ if (zone->useful_geometry_dirty) return; ev = E_NEW(E_Event_Zone_Move_Resize, 1); ev->zone = zone; e_object_ref(E_OBJECT(ev->zone)); ecore_event_add(E_EVENT_ZONE_USEFUL_GEOMETRY_CHANGED, ev, _e_zone_event_generic_free, NULL); zone->useful_geometry_dirty = 1; } E_API E_Zone_Obstacle * e_zone_obstacle_add(E_Zone *zone, E_Desk *desk, Eina_Rectangle *geom, Eina_Bool vertical) { E_Zone_Obstacle *obs; E_OBJECT_CHECK_RETURN(zone, NULL); E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, NULL); if (desk) { E_OBJECT_CHECK_RETURN(desk, NULL); E_OBJECT_TYPE_CHECK_RETURN(desk, E_DESK_TYPE, NULL); if (desk->zone != zone) { ERR("zone != desk->zone"); return NULL; } } obs = E_OBJECT_ALLOC(E_Zone_Obstacle, E_ZONE_OBSTACLE_TYPE, _e_zone_obstacle_free); obs->x = geom->x, obs->y = geom->y; obs->w = geom->w, obs->h = geom->h; obs->owner = E_OBJECT(desk) ?: E_OBJECT(zone); obs->vertical = !!vertical; if (desk) { desk->obstacles = eina_inlist_append(desk->obstacles, EINA_INLIST_GET(obs)); if (desk->visible) e_zone_useful_geometry_dirty(desk->zone); } else { zone->obstacles = eina_inlist_append(zone->obstacles, EINA_INLIST_GET(obs)); e_zone_useful_geometry_dirty(zone); } return obs; } E_API void e_zone_obstacle_modify(E_Zone_Obstacle *obs, Eina_Rectangle *geom, Eina_Bool vertical) { E_Zone *zone; E_Desk *desk; E_OBJECT_CHECK(obs); E_OBJECT_TYPE_CHECK(obs, E_ZONE_OBSTACLE_TYPE); EINA_SAFETY_ON_NULL_RETURN(geom); if ((obs->x == geom->x) && (obs->y == geom->y) && (obs->w == geom->w) && (obs->h == geom->h)) return; obs->x = geom->x, obs->y = geom->y; obs->w = geom->w, obs->h = geom->h; obs->vertical = !!vertical; if (obs->owner->type == E_DESK_TYPE) { desk = (void *)obs->owner; if (desk->visible) e_zone_useful_geometry_dirty(desk->zone); } else { zone = (void *)obs->owner; e_zone_useful_geometry_dirty(zone); } } E_API void e_zone_stow(E_Zone *zone) { E_Event_Zone_Stow *ev; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if (zone->stowed) return; ev = E_NEW(E_Event_Zone_Stow, 1); ev->zone = zone; e_object_ref(E_OBJECT(ev->zone)); ecore_event_add(E_EVENT_ZONE_STOW, ev, _e_zone_event_generic_free, NULL); zone->stowed = EINA_TRUE; } E_API void e_zone_unstow(E_Zone *zone) { E_Event_Zone_Unstow *ev; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if (!zone->stowed) return; ev = E_NEW(E_Event_Zone_Unstow, 1); ev->zone = zone; e_object_ref(E_OBJECT(ev->zone)); ecore_event_add(E_EVENT_ZONE_UNSTOW, ev, _e_zone_event_generic_free, NULL); zone->stowed = EINA_FALSE; } /* local subsystem functions */ static void _e_zone_free(E_Zone *zone) { int x, y; //printf("@@@@@@@@@@ e_zone_free: %i %i | %i %i %ix%i = %p\n", zone->num, zone->id, zone->x, zone->y, zone->w, zone->h, zone); /* Delete the edge windows if they exist */ E_FREE_FUNC(zone->edge.top, evas_object_del); E_FREE_FUNC(zone->edge.bottom, evas_object_del); E_FREE_FUNC(zone->edge.left, evas_object_del); E_FREE_FUNC(zone->edge.right, evas_object_del); E_FREE_FUNC(zone->corner.left_bottom, evas_object_del); E_FREE_FUNC(zone->corner.left_top, evas_object_del); E_FREE_FUNC(zone->corner.top_left, evas_object_del); E_FREE_FUNC(zone->corner.top_right, evas_object_del); E_FREE_FUNC(zone->corner.right_top, evas_object_del); E_FREE_FUNC(zone->corner.right_bottom, evas_object_del); E_FREE_FUNC(zone->corner.bottom_right, evas_object_del); E_FREE_FUNC(zone->corner.bottom_left, evas_object_del); /* Delete the object event callbacks */ evas_object_event_callback_del(zone->bg_event_object, EVAS_CALLBACK_MOUSE_DOWN, _e_zone_cb_bg_mouse_down); evas_object_event_callback_del(zone->bg_event_object, EVAS_CALLBACK_MOUSE_UP, _e_zone_cb_bg_mouse_up); E_FREE_FUNC(zone->cur_mouse_action, e_object_unref); /* remove handlers */ E_FREE_LIST(zone->handlers, ecore_event_handler_del); if (zone->name) eina_stringshare_del(zone->name); e_comp->zones = eina_list_remove(e_comp->zones, zone); evas_object_del(zone->bg_event_object); evas_object_del(zone->bg_clip_object); evas_object_del(zone->bg_object); if (zone->prev_bg_object) evas_object_del(zone->prev_bg_object); if (zone->transition_object) evas_object_del(zone->transition_object); evas_object_del(zone->base); evas_object_del(zone->over); if ((!stopping) && (!e_comp_config_get()->nofade)) { if (zone->bloff) { if (e_backlight_mode_get(zone) != E_BACKLIGHT_MODE_NORMAL) e_backlight_mode_set(zone, E_BACKLIGHT_MODE_NORMAL); e_backlight_level_set(zone, e_config->backlight.normal, 0.0); } } /* free desks */ for (x = 0; x < zone->desk_x_count; x++) { for (y = 0; y < zone->desk_y_count; y++) e_object_del(E_OBJECT(zone->desks[x + (y * zone->desk_x_count)])); } while (zone->obstacles) { E_Object *obs = (void*)EINA_INLIST_CONTAINER_GET(zone->obstacles, E_Zone_Obstacle); e_object_del(obs); } free(zone->desks); free(zone->randr2_id); free(zone); } static void _e_zone_cb_bg_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { E_Zone *zone; zone = data; if (e_comp_util_mouse_grabbed()) return; if (!zone->cur_mouse_action) { zone->cur_mouse_action = e_bindings_mouse_down_evas_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), event_info); if (zone->cur_mouse_action) { if ((!zone->cur_mouse_action->func.end_mouse) && (!zone->cur_mouse_action->func.end)) zone->cur_mouse_action = NULL; if (zone->cur_mouse_action) e_object_ref(E_OBJECT(zone->cur_mouse_action)); } } } static void _e_zone_cb_bg_mouse_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { E_Zone *zone; zone = data; if (zone->cur_mouse_action) { E_Binding_Event_Mouse_Button event; e_bindings_evas_event_mouse_button_convert(event_info, &event); if (zone->cur_mouse_action->func.end_mouse) zone->cur_mouse_action->func.end_mouse(E_OBJECT(zone), "", &event); else if (zone->cur_mouse_action->func.end) zone->cur_mouse_action->func.end(E_OBJECT(zone), ""); e_object_unref(E_OBJECT(zone->cur_mouse_action)); zone->cur_mouse_action = NULL; } else { E_Binding_Event_Mouse_Button event; e_bindings_ecore_event_mouse_button_convert(event_info, &event); e_bindings_mouse_up_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), &event); } } static Eina_Bool _e_zone_cb_edge_timer(void *data) { E_Zone *zone; E_Action *act; zone = data; act = e_action_find(zone->flip.bind->action); if (!act) { E_FREE(zone->flip.ev); return ECORE_CALLBACK_CANCEL; } if (act->func.go_edge) act->func.go_edge(E_OBJECT(zone), zone->flip.bind->params, zone->flip.ev); else if (act->func.go) act->func.go(E_OBJECT(zone), zone->flip.bind->params); zone->flip.bind->timer = NULL; E_FREE(zone->flip.ev); return ECORE_CALLBACK_CANCEL; } static void _e_zone_event_generic_free(void *data EINA_UNUSED, void *ev) { struct _E_Event_Zone_Generic *e; // also handes E_Event_Zone_Add, E_Event_Zone_Del, E_Event_Zone_Stow, // E_Event_Zone_Unstow, E_Event_Zone_Desk_Count_Set due to them all // having the same content e = ev; e_object_unref(E_OBJECT(e->zone)); free(e); } static void _e_zone_object_del_attach(void *o) { E_Zone *zone; E_Event_Zone_Del *ev; zone = o; if (stopping) return; ev = E_NEW(E_Event_Zone_Del, 1); ev->zone = zone; e_object_ref(E_OBJECT(ev->zone)); ecore_event_add(E_EVENT_ZONE_DEL, ev, _e_zone_event_generic_free, NULL); } static E_Zone_Edge _e_zone_detect_edge(E_Zone *zone, Evas_Object *obj) { E_Zone_Edge edge = E_ZONE_EDGE_NONE; if (obj == zone->edge.left) edge = E_ZONE_EDGE_LEFT; else if (obj == zone->edge.top) edge = E_ZONE_EDGE_TOP; else if (obj == zone->edge.right) edge = E_ZONE_EDGE_RIGHT; else if (obj == zone->edge.bottom) edge = E_ZONE_EDGE_BOTTOM; else if ((obj == zone->corner.left_top) || (obj == zone->corner.top_left)) edge = E_ZONE_EDGE_TOP_LEFT; else if ((obj == zone->corner.right_top) || (obj == zone->corner.top_right)) edge = E_ZONE_EDGE_TOP_RIGHT; else if ((obj == zone->corner.right_bottom) || (obj == zone->corner.bottom_right)) edge = E_ZONE_EDGE_BOTTOM_RIGHT; else if ((obj == zone->corner.left_bottom) || (obj == zone->corner.bottom_left)) edge = E_ZONE_EDGE_BOTTOM_LEFT; return edge; } static void _e_zone_edge_move_resize(E_Zone *zone) { int cw; int ch; cw = zone->w * E_ZONE_CORNER_RATIO; ch = zone->h * E_ZONE_CORNER_RATIO; evas_object_geometry_set(zone->corner.left_bottom, zone->x, zone->y + zone->h - ch, 1, ch); evas_object_geometry_set(zone->edge.left, zone->x, zone->y + ch, 1, zone->h - 2 * ch); evas_object_geometry_set(zone->corner.left_top, zone->x, zone->y, 1, ch); evas_object_geometry_set(zone->corner.top_left, zone->x + 1, zone->y, cw, 1); evas_object_geometry_set(zone->edge.top, zone->x + 1 + cw, zone->y, zone->w - 2 * cw - 2, 1); evas_object_geometry_set(zone->corner.top_right, zone->x + zone->w - cw - 2, zone->y, cw, 1); evas_object_geometry_set(zone->corner.right_top, zone->x + zone->w - 1, zone->y, 1, ch); evas_object_geometry_set(zone->edge.right, zone->x + zone->w - 1, zone->y + ch, 1, zone->h - 2 * ch); evas_object_geometry_set(zone->corner.right_bottom, zone->x + zone->w - 1, zone->y + zone->h - ch, 1, ch); evas_object_geometry_set(zone->corner.bottom_right, zone->x + 1, zone->y + zone->h - 1, cw, 1); evas_object_geometry_set(zone->edge.bottom, zone->x + 1 + cw, zone->y + zone->h - 1, zone->w - 2 - 2 * cw, 1); evas_object_geometry_set(zone->corner.bottom_left, zone->x + zone->w - cw - 2, zone->y + zone->h - 1, cw, 1); } static void _e_zone_obstacle_free(E_Zone_Obstacle *obs) { E_Zone *zone; E_Desk *desk; if (obs->owner->type == E_DESK_TYPE) { desk = (void *)obs->owner; desk->obstacles = eina_inlist_remove(desk->obstacles, EINA_INLIST_GET(obs)); if (desk->visible) e_zone_useful_geometry_dirty(desk->zone); } else { zone = (void *)obs->owner; zone->obstacles = eina_inlist_remove(zone->obstacles, EINA_INLIST_GET(obs)); e_zone_useful_geometry_dirty(zone); } free(obs); } E_API E_Zone * e_zone_for_id_get(const char *id) { Eina_List *l = NULL; E_Zone *zone; if (!e_comp) return NULL; EINA_LIST_FOREACH(e_comp->zones, l, zone) { if (eina_streq(zone->randr2_id, id)) return zone; } return NULL; }