Merge from TIZEN 2.3
[platform/core/uifw/e17.git] / src / bin / e_zone.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * This file is a modified version of BSD licensed file and
5  * licensed under the Flora License, Version 1.1 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://floralicense.org/license/
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an AS IS BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Please, see the COPYING file for the original copyright owner and
18  * license.
19  */
20 #include "e.h"
21
22 /* E_Zone is a child object of E_Container. There is one zone per screen
23  * in a xinerama setup. Each zone has one or more desktops.
24  */
25
26 # ifdef _F_USE_DLOG_
27 #  include "dlog.h"
28 #  undef LOG_TAG
29 #  define LOG_TAG "E17"
30 # endif
31
32 static void _e_zone_free(E_Zone *zone);
33 static void _e_zone_cb_bg_mouse_down(void        *data,
34                                      Evas        *evas,
35                                      Evas_Object *obj,
36                                      void        *event_info);
37 static void _e_zone_cb_bg_mouse_up(void        *data,
38                                    Evas        *evas,
39                                    Evas_Object *obj,
40                                    void        *event_info);
41 static void      _e_zone_event_zone_desk_count_set_free(void *data,
42                                                         void *ev);
43 static Eina_Bool _e_zone_cb_mouse_in(void *data,
44                                      int   type,
45                                      void *event);
46 static Eina_Bool _e_zone_cb_mouse_out(void *data,
47                                       int   type,
48                                       void *event);
49 static Eina_Bool _e_zone_cb_mouse_down(void *data,
50                                        int   type,
51                                        void *event);
52 static Eina_Bool _e_zone_cb_mouse_up(void *data,
53                                      int   type,
54                                      void *event);
55 static Eina_Bool _e_zone_cb_mouse_move(void *data,
56                                        int   type,
57                                        void *event);
58 static Eina_Bool _e_zone_cb_desk_after_show(void *data,
59                                             int   type,
60                                             void *event);
61 static Eina_Bool   _e_zone_cb_edge_timer(void *data);
62 static void        _e_zone_event_move_resize_free(void *data,
63                                                   void *ev);
64 static void        _e_zone_event_add_free(void *data,
65                                           void *ev);
66 static void        _e_zone_event_del_free(void *data,
67                                           void *ev);
68 static void        _e_zone_object_del_attach(void *o);
69 static E_Zone_Edge _e_zone_detect_edge(E_Zone        *zone,
70                                        Ecore_X_Window win);
71 static void        _e_zone_edge_move_resize(E_Zone *zone);
72 static void        _e_zone_border_geometry_update(E_Zone *zone);
73 #ifdef _F_ZONE_WINDOW_ROTATION_
74 static void        _e_zone_event_rotation_change_begin_free(void *data,
75                                                             void *ev);
76 static void        _e_zone_event_rotation_change_cancel_free(void *data,
77                                                              void *ev);
78 static void        _e_zone_event_rotation_change_end_free(void *data,
79                                                           void *ev);
80 #endif
81
82 EAPI int E_EVENT_ZONE_DESK_COUNT_SET = 0;
83 EAPI int E_EVENT_POINTER_WARP = 0;
84 EAPI int E_EVENT_ZONE_MOVE_RESIZE = 0;
85 EAPI int E_EVENT_ZONE_ADD = 0;
86 EAPI int E_EVENT_ZONE_DEL = 0;
87 EAPI int E_EVENT_ZONE_EDGE_IN = 0;
88 EAPI int E_EVENT_ZONE_EDGE_OUT = 0;
89 EAPI int E_EVENT_ZONE_EDGE_MOVE = 0;
90 #ifdef _F_ZONE_WINDOW_ROTATION_
91 EAPI int E_EVENT_ZONE_ROTATION_CHANGE = 0; /* deprecated */
92 EAPI int E_EVENT_ZONE_ROTATION_CHANGE_BEGIN = 0;
93 EAPI int E_EVENT_ZONE_ROTATION_CHANGE_CANCEL = 0;
94 EAPI int E_EVENT_ZONE_ROTATION_CHANGE_END = 0;
95 #endif
96
97 #define E_ZONE_FLIP_LEFT(zone)  (((e_config->desk_flip_wrap && ((zone)->desk_x_count > 1)) || ((zone)->desk_x_current > 0)) && (zone)->edge.left)
98 #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)
99 #define E_ZONE_FLIP_UP(zone)    (((e_config->desk_flip_wrap && ((zone)->desk_y_count > 1)) || ((zone)->desk_y_current > 0)) && (zone)->edge.top)
100 #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)
101
102 #define E_ZONE_CORNER_RATIO 0.025;
103
104 EINTERN int
105 e_zone_init(void)
106 {
107    E_EVENT_ZONE_DESK_COUNT_SET = ecore_event_type_new();
108    E_EVENT_POINTER_WARP = ecore_event_type_new();
109    E_EVENT_ZONE_MOVE_RESIZE = ecore_event_type_new();
110    E_EVENT_ZONE_ADD = ecore_event_type_new();
111    E_EVENT_ZONE_DEL = ecore_event_type_new();
112    E_EVENT_ZONE_EDGE_IN = ecore_event_type_new();
113    E_EVENT_ZONE_EDGE_OUT = ecore_event_type_new();
114    E_EVENT_ZONE_EDGE_MOVE = ecore_event_type_new();
115 #ifdef _F_ZONE_WINDOW_ROTATION_
116    E_EVENT_ZONE_ROTATION_CHANGE = ecore_event_type_new(); /* deprecated */
117    E_EVENT_ZONE_ROTATION_CHANGE_BEGIN = ecore_event_type_new();
118    E_EVENT_ZONE_ROTATION_CHANGE_CANCEL = ecore_event_type_new();
119    E_EVENT_ZONE_ROTATION_CHANGE_END = ecore_event_type_new();
120 #endif
121    return 1;
122 }
123
124 EINTERN int
125 e_zone_shutdown(void)
126 {
127    return 1;
128 }
129
130 EAPI void
131 e_zone_all_edge_flip_eval(void)
132 {
133    Eina_List *l, *ll, *lll;
134    E_Manager *man;
135    E_Container *con;
136    E_Zone *zone;
137
138    EINA_LIST_FOREACH(e_manager_list(), l, man)
139      {
140         EINA_LIST_FOREACH(man->containers, ll, con)
141           {
142              EINA_LIST_FOREACH(con->zones, lll, zone)
143                {
144                   e_zone_edge_flip_eval(zone);
145                }
146           }
147      }
148 }
149
150 static void
151 _e_zone_black_new(E_Zone *zone)
152 {
153    Evas_Object *o;
154    char name[256];
155
156    if (zone->black_ecore_evas) return;
157    zone->black_ecore_evas = e_canvas_new(zone->container->win,
158                                          zone->x, zone->y, 1, 1, 1, 1,
159                                          &(zone->black_win));
160    e_canvas_add(zone->black_ecore_evas);
161    ecore_evas_layer_set(zone->black_ecore_evas, 6);
162    zone->black_evas = ecore_evas_get(zone->black_ecore_evas);
163
164    o = evas_object_rectangle_add(zone->black_evas);
165    evas_object_move(o, 0, 0);
166    evas_object_resize(o, zone->w, zone->h);
167    evas_object_color_set(o, 0, 0, 0, 255);
168    evas_object_show(o);
169
170    ecore_evas_name_class_set(zone->black_ecore_evas, "E", "Black_Window");
171    snprintf(name, sizeof(name), "Enlightenment Black Zone (%d)", zone->num);
172    ecore_evas_title_set(zone->black_ecore_evas, name);
173 }
174
175 static void
176 _e_zone_black_free(E_Zone *zone)
177 {
178    if (!zone->black_ecore_evas) return;
179    e_canvas_del(zone->black_ecore_evas);
180    ecore_evas_free(zone->black_ecore_evas);
181    zone->black_ecore_evas = NULL;
182    zone->black_win = 0;
183 }
184
185 static void
186 _e_zone_black_get(E_Zone *zone)
187 {
188    zone->black_need++;
189    if (!zone->black_ecore_evas) return;
190    if (zone->black_need == 1)
191      {
192         ecore_evas_move(zone->black_ecore_evas, zone->x, zone->y);
193         ecore_evas_resize(zone->black_ecore_evas, zone->w, zone->h);
194      }
195 }
196
197 static void
198 _e_zone_black_unget(E_Zone *zone)
199 {
200    zone->black_need--;
201    if (!zone->black_ecore_evas) return;
202    if (zone->black_need == 0)
203      {
204         ecore_evas_move(zone->black_ecore_evas, zone->x, zone->y);
205         ecore_evas_resize(zone->black_ecore_evas, 1, 1);
206      }
207 }
208
209 EAPI E_Zone *
210 e_zone_new(E_Container *con,
211            int          num,
212            int          id,
213            int          x,
214            int          y,
215            int          w,
216            int          h)
217 {
218    E_Zone *zone;
219    Evas_Object *o;
220    E_Event_Zone_Add *ev;
221    char name[40];
222
223    zone = E_OBJECT_ALLOC(E_Zone, E_ZONE_TYPE, _e_zone_free);
224    if (!zone) return NULL;
225
226    zone->container = con;
227
228    zone->x = x;
229    zone->y = y;
230    zone->w = w;
231    zone->h = h;
232    zone->num = num;
233    zone->id = id;
234    e_zone_useful_geometry_dirty(zone);
235
236    //printf("@@@@@@@@@@ e_zone_new: %i %i | %i %i %ix%i = %p\n", num, id, x, y, w, h, zone);
237
238    zone->handlers =
239      eina_list_append(zone->handlers,
240                       ecore_event_handler_add(ECORE_X_EVENT_MOUSE_IN,
241                                               _e_zone_cb_mouse_in, zone));
242    zone->handlers =
243      eina_list_append(zone->handlers,
244                       ecore_event_handler_add(ECORE_X_EVENT_MOUSE_OUT,
245                                               _e_zone_cb_mouse_out, zone));
246    zone->handlers =
247      eina_list_append(zone->handlers,
248                       ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
249                                               _e_zone_cb_mouse_down, zone));
250    zone->handlers =
251      eina_list_append(zone->handlers,
252                       ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
253                                               _e_zone_cb_mouse_up, zone));
254    zone->handlers =
255      eina_list_append(zone->handlers,
256                       ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
257                                               _e_zone_cb_mouse_move, zone));
258    zone->handlers =
259      eina_list_append(zone->handlers,
260                       ecore_event_handler_add(E_EVENT_DESK_AFTER_SHOW,
261                                               _e_zone_cb_desk_after_show, zone));
262
263    snprintf(name, sizeof(name), "Zone %d", zone->num);
264    zone->name = eina_stringshare_add(name);
265
266    con->zones = eina_list_append(con->zones, zone);
267
268    o = evas_object_rectangle_add(con->bg_evas);
269    zone->bg_clip_object = o;
270    evas_object_move(o, x, y);
271    evas_object_resize(o, w, h);
272    evas_object_color_set(o, 255, 255, 255, 255);
273    evas_object_show(o);
274
275    o = evas_object_rectangle_add(con->bg_evas);
276    zone->bg_event_object = o;
277    evas_object_clip_set(o, zone->bg_clip_object);
278    evas_object_move(o, x, y);
279    evas_object_resize(o, w, h);
280    evas_object_color_set(o, 0, 0, 0, 0);
281    evas_object_repeat_events_set(o, 1);
282    evas_object_show(o);
283    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _e_zone_cb_bg_mouse_down, zone);
284    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _e_zone_cb_bg_mouse_up, zone);
285
286    /* TODO: config the ecore_evas type. */
287
288    zone->desk_x_count = 0;
289    zone->desk_y_count = 0;
290    zone->desk_x_current = 0;
291    zone->desk_y_current = 0;
292    e_zone_desk_count_set(zone, e_config->zone_desks_x_count,
293                          e_config->zone_desks_y_count);
294
295    e_object_del_attach_func_set(E_OBJECT(zone), _e_zone_object_del_attach);
296
297    _e_zone_black_new(zone);
298
299    ev = E_NEW(E_Event_Zone_Add, 1);
300    ev->zone = zone;
301    e_object_ref(E_OBJECT(ev->zone));
302    ecore_event_add(E_EVENT_ZONE_ADD, ev, _e_zone_event_add_free, NULL);
303
304    e_zone_all_edge_flip_eval();
305    return zone;
306 }
307
308 EAPI void
309 e_zone_name_set(E_Zone     *zone,
310                 const char *name)
311 {
312    E_OBJECT_CHECK(zone);
313    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
314
315    if (zone->name) eina_stringshare_del(zone->name);
316    zone->name = eina_stringshare_add(name);
317 }
318
319 EAPI void
320 e_zone_move(E_Zone *zone,
321             int     x,
322             int     y)
323 {
324    E_Event_Zone_Move_Resize *ev;
325
326    E_OBJECT_CHECK(zone);
327    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
328
329    if ((x == zone->x) && (y == zone->y)) return;
330    zone->x = x;
331    zone->y = y;
332    evas_object_move(zone->bg_object, x, y);
333    evas_object_move(zone->bg_event_object, x, y);
334    evas_object_move(zone->bg_clip_object, x, y);
335
336    ev = E_NEW(E_Event_Zone_Move_Resize, 1);
337    ev->zone = zone;
338    e_object_ref(E_OBJECT(ev->zone));
339    ecore_event_add(E_EVENT_ZONE_MOVE_RESIZE, ev, _e_zone_event_move_resize_free, NULL);
340
341    _e_zone_edge_move_resize(zone);
342    e_zone_bg_reconfigure(zone);
343    if (zone->black_need > 0)
344      {
345         ecore_evas_move(zone->black_ecore_evas, zone->x, zone->y);
346         ecore_evas_resize(zone->black_ecore_evas, zone->w, zone->h);
347      }
348    _e_zone_border_geometry_update(zone);
349 }
350
351 EAPI void
352 e_zone_resize(E_Zone *zone,
353               int     w,
354               int     h)
355 {
356    E_Event_Zone_Move_Resize *ev;
357
358    E_OBJECT_CHECK(zone);
359    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
360
361    if ((w == zone->w) && (h == zone->h)) return;
362    zone->w = w;
363    zone->h = h;
364    evas_object_resize(zone->bg_object, w, h);
365    evas_object_resize(zone->bg_event_object, w, h);
366    evas_object_resize(zone->bg_clip_object, w, h);
367
368    ev = E_NEW(E_Event_Zone_Move_Resize, 1);
369    ev->zone = zone;
370    e_object_ref(E_OBJECT(ev->zone));
371    ecore_event_add(E_EVENT_ZONE_MOVE_RESIZE, ev,
372                    _e_zone_event_move_resize_free, NULL);
373
374    _e_zone_edge_move_resize(zone);
375    e_zone_bg_reconfigure(zone);
376    if (zone->black_need > 0)
377      {
378         ecore_evas_move(zone->black_ecore_evas, zone->x, zone->y);
379         ecore_evas_resize(zone->black_ecore_evas, zone->w, zone->h);
380      }
381    _e_zone_border_geometry_update(zone);
382 }
383
384 EAPI void
385 e_zone_move_resize(E_Zone *zone,
386                    int     x,
387                    int     y,
388                    int     w,
389                    int     h)
390 {
391    E_Event_Zone_Move_Resize *ev;
392
393    E_OBJECT_CHECK(zone);
394    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
395
396    if ((x == zone->x) && (y == zone->y) && (w == zone->w) && (h == zone->h))
397      return;
398
399    zone->x = x;
400    zone->y = y;
401    zone->w = w;
402    zone->h = h;
403
404    evas_object_move(zone->bg_object, x, y);
405    evas_object_move(zone->bg_event_object, x, y);
406    evas_object_move(zone->bg_clip_object, x, y);
407    evas_object_resize(zone->bg_object, w, h);
408    evas_object_resize(zone->bg_event_object, w, h);
409    evas_object_resize(zone->bg_clip_object, w, h);
410
411    ev = E_NEW(E_Event_Zone_Move_Resize, 1);
412    ev->zone = zone;
413    e_object_ref(E_OBJECT(ev->zone));
414    ecore_event_add(E_EVENT_ZONE_MOVE_RESIZE, ev,
415                    _e_zone_event_move_resize_free, NULL);
416
417    _e_zone_edge_move_resize(zone);
418
419    e_zone_bg_reconfigure(zone);
420    if (zone->black_need > 0)
421      {
422         ecore_evas_move(zone->black_ecore_evas, zone->x, zone->y);
423         ecore_evas_resize(zone->black_ecore_evas, zone->w, zone->h);
424      }
425    _e_zone_border_geometry_update(zone);
426 }
427
428 EAPI void
429 e_zone_fullscreen_set(E_Zone *zone,
430                       int     on)
431 {
432    E_OBJECT_CHECK(zone);
433    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
434
435    if ((!zone->fullscreen) && (on))
436      {
437         _e_zone_black_get(zone);
438         ecore_evas_show(zone->black_ecore_evas);
439         e_container_window_raise(zone->container, zone->black_win, 150);
440         zone->fullscreen = 1;
441      }
442    else if ((zone->fullscreen) && (!on))
443      {
444         ecore_evas_hide(zone->black_ecore_evas);
445         zone->fullscreen = 0;
446         _e_zone_black_unget(zone);
447      }
448 }
449
450 EAPI E_Zone *
451 e_zone_current_get(E_Container *con)
452 {
453    Eina_List *l = NULL;
454    E_Zone *zone;
455
456    E_OBJECT_CHECK_RETURN(con, NULL);
457    E_OBJECT_TYPE_CHECK_RETURN(con, E_CONTAINER_TYPE, NULL);
458    if (!starting)
459      {
460         int x, y;
461
462         ecore_x_pointer_xy_get(con->win, &x, &y);
463         EINA_LIST_FOREACH(con->zones, l, zone)
464           {
465              if (E_INSIDE(x, y, zone->x, zone->y, zone->w, zone->h))
466                return zone;
467           }
468      }
469    if (!con->zones) return NULL;
470    return (E_Zone *)eina_list_data_get(con->zones);
471 }
472
473 EAPI void
474 e_zone_bg_reconfigure(E_Zone *zone)
475 {
476    E_OBJECT_CHECK(zone);
477    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
478
479    e_bg_zone_update(zone, E_BG_TRANSITION_CHANGE);
480 }
481
482 EAPI void
483 e_zone_flip_coords_handle(E_Zone *zone,
484                           int     x,
485                           int     y)
486 {
487    E_Event_Zone_Edge *zev;
488    E_Binding_Edge *binding;
489    E_Zone_Edge edge;
490    Eina_List *l;
491    E_Shelf *es;
492    int ok = 0;
493    int one_row = 1;
494    int one_col = 1;
495
496    E_OBJECT_CHECK(zone);
497    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
498
499    if (!e_config->edge_flip_dragging || zone->flip.switching) return;
500    /* if we have only 1 row we can flip up/down even if we have xinerama */
501    if (eina_list_count(zone->container->zones) > 1)
502      {
503         Eina_List *zones;
504         E_Zone *next_zone;
505         int cx, cy;
506
507         zones = zone->container->zones;
508         next_zone = (E_Zone *)eina_list_data_get(zones);
509         cx = next_zone->x;
510         cy = next_zone->y;
511         zones = eina_list_next(zones);
512         EINA_LIST_FOREACH(eina_list_next(zones), zones, next_zone)
513           {
514              if (next_zone->x != cx) one_col = 0;
515              if (next_zone->y != cy) one_row = 0;
516           }
517      }
518    if (eina_list_count(zone->container->manager->containers) > 1)
519      goto noflip;
520    if (!E_INSIDE(x, y, zone->x, zone->y, zone->w, zone->h))
521      goto noflip;
522    if ((one_row) && (y == 0))
523      edge = E_ZONE_EDGE_TOP;
524    else if ((one_col) && (x == (zone->w - 1)))
525      edge = E_ZONE_EDGE_RIGHT;
526    else if ((one_row) && (y == (zone->h - 1)))
527      edge = E_ZONE_EDGE_BOTTOM;
528    else if ((one_col) && (x == 0))
529      edge = E_ZONE_EDGE_LEFT;
530    else
531      {
532 noflip:
533         if (zone->flip.es)
534           e_shelf_toggle(zone->flip.es, 0);
535         zone->flip.es = NULL;
536         return;
537      }
538    EINA_LIST_FOREACH(e_shelf_list(), l, es)
539      {
540         if (es->zone != zone) continue;
541         switch (es->gadcon->orient)
542           {
543            case E_GADCON_ORIENT_TOP:
544            case E_GADCON_ORIENT_CORNER_TL:
545            case E_GADCON_ORIENT_CORNER_TR:
546              if (edge == E_ZONE_EDGE_TOP) ok = 1;
547              break;
548
549            case E_GADCON_ORIENT_BOTTOM:
550            case E_GADCON_ORIENT_CORNER_BL:
551            case E_GADCON_ORIENT_CORNER_BR:
552              if (edge == E_ZONE_EDGE_BOTTOM) ok = 1;
553              break;
554
555            case E_GADCON_ORIENT_LEFT:
556            case E_GADCON_ORIENT_CORNER_LT:
557            case E_GADCON_ORIENT_CORNER_LB:
558              if (edge == E_ZONE_EDGE_LEFT) ok = 1;
559              break;
560
561            case E_GADCON_ORIENT_RIGHT:
562            case E_GADCON_ORIENT_CORNER_RT:
563            case E_GADCON_ORIENT_CORNER_RB:
564              if (edge == E_ZONE_EDGE_RIGHT) ok = 1;
565              break;
566
567            default:
568              ok = 0;
569              break;
570           }
571
572         if (!ok) continue;
573         if (!E_INSIDE(x, y, es->x, es->y, es->w, es->h))
574           continue;
575
576         if (zone->flip.es)
577           e_shelf_toggle(zone->flip.es, 0);
578
579         zone->flip.es = es;
580         e_shelf_toggle(es, 1);
581      }
582    switch (edge)
583      {
584       case E_ZONE_EDGE_LEFT:
585         if (E_ZONE_FLIP_LEFT(zone)) ok = 1;
586         break;
587
588       case E_ZONE_EDGE_TOP:
589         if (E_ZONE_FLIP_UP(zone)) ok = 1;
590         break;
591
592       case E_ZONE_EDGE_RIGHT:
593         if (E_ZONE_FLIP_RIGHT(zone)) ok = 1;
594         break;
595
596       case E_ZONE_EDGE_BOTTOM:
597         if (E_ZONE_FLIP_DOWN(zone)) ok = 1;
598         break;
599
600       default:
601         ok = 0;
602         break;
603      }
604    if (!ok) return;
605    binding = e_bindings_edge_get("desk_flip_in_direction", edge, 0);
606    if (!binding) binding = e_bindings_edge_get("desk_flip_by", edge, 0);
607    if (binding && (!binding->timer))
608      {
609         zev = E_NEW(E_Event_Zone_Edge, 1);
610         zev->zone = zone;
611         zev->x = x;
612         zev->y = y;
613         zev->edge = edge;
614         zone->flip.ev = zev;
615         zone->flip.bind = binding;
616         zone->flip.switching = 1;
617         binding->timer = ecore_timer_add(((double)binding->delay), _e_zone_cb_edge_timer, zone);
618      }
619 }
620
621 EAPI void
622 e_zone_desk_count_set(E_Zone *zone,
623                       int     x_count,
624                       int     y_count)
625 {
626    E_Desk **new_desks;
627    E_Desk *desk, *new_desk;
628    E_Border *bd;
629    E_Event_Zone_Desk_Count_Set *ev;
630    E_Border_List *bl;
631    int x, y, xx, yy, moved, nx, ny;
632
633    E_OBJECT_CHECK(zone);
634    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
635
636    xx = x_count;
637    if (xx < 1) xx = 1;
638    yy = y_count;
639    if (yy < 1) yy = 1;
640
641    /* Orphaned window catcher; in case desk count gets reset */
642    moved = 0;
643    if (zone->desk_x_current >= xx) moved = 1;
644    if (zone->desk_y_current >= yy) moved = 1;
645    if (moved)
646      {
647         nx = zone->desk_x_current;
648         ny = zone->desk_y_current;
649         if (zone->desk_x_current >= xx) nx = xx - 1;
650         if (zone->desk_y_current >= yy) ny = yy - 1;
651         e_desk_show(e_desk_at_xy_get(zone, nx, ny));
652      }
653
654    new_desks = malloc(xx * yy * sizeof(E_Desk *));
655    for (x = 0; x < xx; x++)
656      {
657         for (y = 0; y < yy; y++)
658           {
659              if ((x < zone->desk_x_count) && (y < zone->desk_y_count))
660                desk = zone->desks[x + (y * zone->desk_x_count)];
661              else
662                desk = e_desk_new(zone, x, y);
663              new_desks[x + (y * xx)] = desk;
664           }
665      }
666
667    /* catch windoes that have fallen off the end if we got smaller */
668    if (xx < zone->desk_x_count)
669      {
670         for (y = 0; y < zone->desk_y_count; y++)
671           {
672              new_desk = zone->desks[xx - 1 + (y * zone->desk_x_count)];
673              for (x = xx; x < zone->desk_x_count; x++)
674                {
675                   desk = zone->desks[x + (y * zone->desk_x_count)];
676
677                   bl = e_container_border_list_first(zone->container);
678                   while ((bd = e_container_border_list_next(bl)))
679                     {
680                        if (bd->desk == desk)
681                          e_border_desk_set(bd, new_desk);
682                     }
683                   e_container_border_list_free(bl);
684                   e_object_del(E_OBJECT(desk));
685                }
686           }
687      }
688    if (yy < zone->desk_y_count)
689      {
690         for (x = 0; x < zone->desk_x_count; x++)
691           {
692              new_desk = zone->desks[x + ((yy - 1) * zone->desk_x_count)];
693              for (y = yy; y < zone->desk_y_count; y++)
694                {
695                   desk = zone->desks[x + (y * zone->desk_x_count)];
696
697                   bl = e_container_border_list_first(zone->container);
698                   while ((bd = e_container_border_list_next(bl)))
699                     {
700                        if (bd->desk == desk)
701                          e_border_desk_set(bd, new_desk);
702                     }
703                   e_container_border_list_free(bl);
704                   e_object_del(E_OBJECT(desk));
705                }
706           }
707      }
708    if (zone->desks) free(zone->desks);
709    zone->desks = new_desks;
710
711    zone->desk_x_count = xx;
712    zone->desk_y_count = yy;
713    e_config->zone_desks_x_count = xx;
714    e_config->zone_desks_y_count = yy;
715    e_config_save_queue();
716
717    /* Cannot call desk_current_get until the zone desk counts have been set
718     * or else we end up with a "white background" because desk_current_get will
719     * return NULL.
720     */
721    desk = e_desk_current_get(zone);
722    if (desk)
723      {
724         desk->visible = 0;
725         e_desk_show(desk);
726      }
727
728    e_zone_edge_flip_eval(zone);
729
730    ev = E_NEW(E_Event_Zone_Desk_Count_Set, 1);
731    if (!ev) return;
732    ev->zone = zone;
733    e_object_ref(E_OBJECT(ev->zone));
734    ecore_event_add(E_EVENT_ZONE_DESK_COUNT_SET, ev,
735                    _e_zone_event_zone_desk_count_set_free, NULL);
736 }
737
738 EAPI void
739 e_zone_desk_count_get(E_Zone *zone,
740                       int    *x_count,
741                       int    *y_count)
742 {
743    E_OBJECT_CHECK(zone);
744    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
745
746    if (x_count) *x_count = zone->desk_x_count;
747    if (y_count) *y_count = zone->desk_y_count;
748 }
749
750 EAPI void
751 e_zone_desk_flip_by(E_Zone *zone,
752                     int     dx,
753                     int     dy)
754 {
755    E_OBJECT_CHECK(zone);
756    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
757
758    dx = zone->desk_x_current + dx;
759    dy = zone->desk_y_current + dy;
760    e_zone_desk_flip_to(zone, dx, dy);
761    e_zone_edge_flip_eval(zone);
762 }
763
764 EAPI void
765 e_zone_desk_flip_to(E_Zone *zone,
766                     int     x,
767                     int     y)
768 {
769    E_Desk *desk;
770
771    E_OBJECT_CHECK(zone);
772    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
773
774    if (e_config->desk_flip_wrap)
775      {
776         x = x % zone->desk_x_count;
777         y = y % zone->desk_y_count;
778         if (x < 0) x += zone->desk_x_count;
779         if (y < 0) y += zone->desk_y_count;
780      }
781    else
782      {
783         if (x < 0) x = 0;
784         else if (x >= zone->desk_x_count)
785           x = zone->desk_x_count - 1;
786         if (y < 0) y = 0;
787         else if (y >= zone->desk_y_count)
788           y = zone->desk_y_count - 1;
789      }
790    desk = e_desk_at_xy_get(zone, x, y);
791    if (desk) e_desk_show(desk);
792    e_zone_edge_flip_eval(zone);
793 }
794
795 EAPI void
796 e_zone_desk_linear_flip_by(E_Zone *zone,
797                            int     dx)
798 {
799    E_OBJECT_CHECK(zone);
800    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
801
802    dx = zone->desk_x_current +
803      (zone->desk_y_current * zone->desk_x_count) + dx;
804    dx = dx % (zone->desk_x_count * zone->desk_y_count);
805    while (dx < 0)
806      dx += (zone->desk_x_count * zone->desk_y_count);
807    e_zone_desk_linear_flip_to(zone, dx);
808    e_zone_edge_flip_eval(zone);
809 }
810
811 EAPI void
812 e_zone_desk_linear_flip_to(E_Zone *zone,
813                            int     x)
814 {
815    int y;
816
817    E_OBJECT_CHECK(zone);
818    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
819
820    y = x / zone->desk_x_count;
821    x = x - (y * zone->desk_x_count);
822    e_zone_desk_flip_to(zone, x, y);
823    e_zone_edge_flip_eval(zone);
824 }
825
826 EAPI void
827 e_zone_edge_enable(void)
828 {
829    Eina_List *l, *ll, *lll;
830    E_Manager *man;
831    E_Container *con;
832    E_Zone *zone;
833
834    EINA_LIST_FOREACH(e_manager_list(), l, man)
835      {
836         EINA_LIST_FOREACH(man->containers, ll, con)
837           {
838              EINA_LIST_FOREACH(con->zones, lll, zone)
839                {
840                   if (zone->edge.left) ecore_x_window_show(zone->edge.left);
841                   if (zone->edge.right) ecore_x_window_show(zone->edge.right);
842                   if (zone->edge.top) ecore_x_window_show(zone->edge.top);
843                   if (zone->edge.bottom) ecore_x_window_show(zone->edge.bottom);
844                   if (zone->corner.left_top) ecore_x_window_show(zone->corner.left_top);
845                   if (zone->corner.top_left) ecore_x_window_show(zone->corner.top_left);
846                   if (zone->corner.top_right) ecore_x_window_show(zone->corner.top_right);
847                   if (zone->corner.right_top) ecore_x_window_show(zone->corner.right_top);
848                   if (zone->corner.right_bottom) ecore_x_window_show(zone->corner.right_bottom);
849                   if (zone->corner.bottom_right) ecore_x_window_show(zone->corner.bottom_right);
850                   if (zone->corner.bottom_left) ecore_x_window_show(zone->corner.bottom_left);
851                   if (zone->corner.left_bottom) ecore_x_window_show(zone->corner.left_bottom);
852                   e_zone_edge_flip_eval(zone);
853                }
854           }
855      }
856 }
857
858 EAPI void
859 e_zone_edge_disable(void)
860 {
861    Eina_List *l, *ll, *lll;
862    E_Manager *man;
863    E_Container *con;
864    E_Zone *zone;
865
866    EINA_LIST_FOREACH(e_manager_list(), l, man)
867      {
868         EINA_LIST_FOREACH(man->containers, ll, con)
869           {
870              EINA_LIST_FOREACH(con->zones, lll, zone)
871                {
872                   if (zone->edge.left) ecore_x_window_hide(zone->edge.left);
873                   if (zone->edge.right) ecore_x_window_hide(zone->edge.right);
874                   if (zone->edge.top) ecore_x_window_hide(zone->edge.top);
875                   if (zone->edge.bottom) ecore_x_window_hide(zone->edge.bottom);
876                   if (zone->corner.left_top) ecore_x_window_hide(zone->corner.left_top);
877                   if (zone->corner.top_left) ecore_x_window_hide(zone->corner.top_left);
878                   if (zone->corner.top_right) ecore_x_window_hide(zone->corner.top_right);
879                   if (zone->corner.right_top) ecore_x_window_hide(zone->corner.right_top);
880                   if (zone->corner.right_bottom) ecore_x_window_hide(zone->corner.right_bottom);
881                   if (zone->corner.bottom_right) ecore_x_window_hide(zone->corner.bottom_right);
882                   if (zone->corner.bottom_left) ecore_x_window_hide(zone->corner.bottom_left);
883                   if (zone->corner.left_bottom) ecore_x_window_hide(zone->corner.left_bottom);
884                }
885           }
886      }
887 }
888
889 EAPI void
890 e_zone_edges_desk_flip_capable(E_Zone *zone, Eina_Bool l, Eina_Bool r, Eina_Bool t, Eina_Bool b)
891 {
892 #define NEED_FLIP_EDGE(x) \
893    (e_bindings_edge_flippable_get(x) || e_bindings_edge_non_flippable_get(x))
894 #define NEED_EDGE(x) \
895    (e_bindings_edge_non_flippable_get(x))
896 #define CHECK_EDGE(v, ed, win) \
897    do { \
898       if (v) { \
899          if (NEED_FLIP_EDGE(ed)) { if (zone->edge.win) ecore_x_window_show(zone->edge.win); } \
900          else if (zone->edge.win) ecore_x_window_hide(zone->edge.win); \
901       } \
902       else { \
903          if (NEED_EDGE(ed)) { if (zone->edge.win) ecore_x_window_show(zone->edge.win); } \
904          else if (zone->edge.win) ecore_x_window_hide(zone->edge.win); \
905       } \
906    } while (0)
907
908    CHECK_EDGE(l, E_ZONE_EDGE_LEFT, left);
909    CHECK_EDGE(r, E_ZONE_EDGE_RIGHT, right);
910    CHECK_EDGE(t, E_ZONE_EDGE_TOP, top);
911    CHECK_EDGE(b, E_ZONE_EDGE_BOTTOM, bottom);
912
913 #define CHECK_CORNER(v1, v2, ed, win1, win2) \
914    if ((!v1) && (!v2)) { \
915       if (NEED_EDGE(ed)) { \
916          if (zone->corner.win1) ecore_x_window_show(zone->corner.win1); \
917          if (zone->corner.win2) ecore_x_window_show(zone->corner.win2); \
918       } \
919       else { \
920          if (zone->corner.win1) ecore_x_window_hide(zone->corner.win1); \
921          if (zone->corner.win2) ecore_x_window_hide(zone->corner.win2); \
922       } \
923    } \
924    else { \
925       if (NEED_FLIP_EDGE(ed)) { \
926          if (zone->corner.win1) ecore_x_window_show(zone->corner.win1); \
927          if (zone->corner.win2) ecore_x_window_show(zone->corner.win2); \
928       } \
929       else { \
930          if (zone->corner.win1) ecore_x_window_hide(zone->corner.win1); \
931          if (zone->corner.win2) ecore_x_window_hide(zone->corner.win2); \
932       } \
933    }
934
935    CHECK_CORNER(l, t, E_ZONE_EDGE_TOP_LEFT, left_top, top_left);
936    CHECK_CORNER(r, t, E_ZONE_EDGE_TOP_RIGHT, right_top, top_right);
937    CHECK_CORNER(l, b, E_ZONE_EDGE_BOTTOM_LEFT, left_bottom, bottom_left);
938    CHECK_CORNER(r, b, E_ZONE_EDGE_BOTTOM_RIGHT, right_bottom, bottom_right);
939 }
940
941 EAPI Eina_Bool
942 e_zone_exists_direction(E_Zone *zone, E_Zone_Edge edge)
943 {
944    Eina_List *l;
945    E_Zone *z2;
946
947    EINA_LIST_FOREACH(zone->container->zones, l, z2)
948      {
949         if (zone == z2) continue;
950
951         switch (edge)
952           {
953            case E_ZONE_EDGE_TOP_LEFT:
954              if (((E_SPANS_COMMON(0, zone->x + zone->w, z2->x, z2->w)) &&
955                   (z2->y < zone->y)) ||
956                  ((E_SPANS_COMMON(0, zone->y + zone->h, z2->y, z2->h)) &&
957                   (z2->x < zone->x)))
958                 return EINA_TRUE;
959              break;
960            case E_ZONE_EDGE_TOP:
961              if ((E_SPANS_COMMON(zone->x, zone->w, z2->x, z2->w)) &&
962                  (z2->y < zone->y))
963                 return EINA_TRUE;
964              break;
965            case E_ZONE_EDGE_TOP_RIGHT:
966              if (((E_SPANS_COMMON(zone->x, 99999, z2->x, z2->w)) &&
967                   (z2->y < zone->y)) ||
968                  ((E_SPANS_COMMON(0, zone->y + zone->h, z2->y, z2->h)) &&
969                   (z2->x >= (zone->x + zone->w))))
970                 return EINA_TRUE;
971              break;
972
973            case E_ZONE_EDGE_LEFT:
974              if ((E_SPANS_COMMON(zone->y, zone->h, z2->y, z2->h)) &&
975                  (z2->x < zone->x))
976                 return EINA_TRUE;
977              break;
978
979            case E_ZONE_EDGE_RIGHT:
980              if ((E_SPANS_COMMON(zone->y, zone->h, z2->y, z2->h)) &&
981                  (z2->x >= (zone->x + zone->w)))
982                 return EINA_TRUE;
983              break;
984
985            case E_ZONE_EDGE_BOTTOM_LEFT:
986              if (((E_SPANS_COMMON(0, zone->x + zone->w, z2->x, z2->w)) &&
987                   (z2->y >= (zone->y + zone->h))) ||
988                  ((E_SPANS_COMMON(zone->y, 99999, z2->y, z2->h)) &&
989                   (z2->x < zone->x)))
990                 return EINA_TRUE;
991              break;
992            case E_ZONE_EDGE_BOTTOM:
993              if ((E_SPANS_COMMON(zone->x, zone->w, z2->x, z2->w)) &&
994                  (z2->y >= (zone->y + zone->h)))
995                 return EINA_TRUE;
996              break;
997            case E_ZONE_EDGE_BOTTOM_RIGHT:
998              if (((E_SPANS_COMMON(zone->x, 99999, z2->x, z2->w)) &&
999                   (z2->y >= (zone->y + zone->h))) ||
1000                  ((E_SPANS_COMMON(zone->y, 99999, z2->y, z2->h)) &&
1001                   (z2->x < zone->x)))
1002                 return EINA_TRUE;
1003              break;
1004
1005            default:
1006              break;
1007           }
1008      }
1009
1010    return EINA_FALSE;
1011 }
1012
1013
1014 EAPI void
1015 e_zone_edge_flip_eval(E_Zone *zone)
1016 {
1017    Eina_Bool lf, rf, tf, bf;
1018
1019    lf = rf = tf = bf = EINA_TRUE;
1020    if (zone->desk_x_count <= 1) lf = rf = EINA_FALSE;
1021    else if (!e_config->desk_flip_wrap)
1022      {
1023         if (zone->desk_x_current == 0) lf = EINA_FALSE;
1024         if (zone->desk_x_current == (zone->desk_x_count - 1)) rf = EINA_FALSE;
1025      }
1026    if (zone->desk_y_count <= 1) tf = bf = EINA_FALSE;
1027    else if (!e_config->desk_flip_wrap)
1028      {
1029         if (zone->desk_y_current == 0) tf = EINA_FALSE;
1030         if (zone->desk_y_current == (zone->desk_y_count - 1)) bf = EINA_FALSE;
1031      }
1032    e_zone_edges_desk_flip_capable(zone, lf, rf, tf, bf);
1033 }
1034
1035 EAPI void
1036 e_zone_edge_new(E_Zone_Edge edge)
1037 {
1038    Eina_List *l, *ll, *lll;
1039    E_Manager *man;
1040    E_Container *con;
1041    E_Zone *zone;
1042    int cw, ch;
1043
1044    // configurably disallow edge bindings when we have more than 1 root
1045    // window (ie pure old multihead) since we don't know which direction
1046    // other root windows are in
1047    if ((!e_config->multiscreen_flip) && (eina_list_count(e_manager_list()) > 1)) return;
1048    EINA_LIST_FOREACH(e_manager_list(), l, man)
1049      {
1050         EINA_LIST_FOREACH(man->containers, ll, con)
1051           {
1052              EINA_LIST_FOREACH(con->zones, lll, zone)
1053                {
1054                   // don't allow bindings on edges that are on the boundary
1055                   // between zones
1056                   if (e_zone_exists_direction(zone, edge)) continue;
1057                   cw = zone->w * E_ZONE_CORNER_RATIO;
1058                   ch = zone->h * E_ZONE_CORNER_RATIO;
1059                   switch (edge)
1060                     {
1061                      case E_ZONE_EDGE_NONE:
1062                        /* noop */
1063                        break;
1064
1065                      case E_ZONE_EDGE_LEFT:
1066                        if (!zone->edge.left)
1067                          {
1068                             zone->edge.left = ecore_x_window_input_new(con->win,
1069                                                                        zone->x, zone->y + ch, 1,
1070                                                                        zone->h - 2 * ch);
1071                             ecore_x_window_show(zone->edge.left);
1072                          }
1073                        break;
1074
1075                      case E_ZONE_EDGE_RIGHT:
1076                        if (!zone->edge.right)
1077                          {
1078                             zone->edge.right = ecore_x_window_input_new(con->win,
1079                                                                         zone->x + zone->w - 1,
1080                                                                         zone->y + ch, 1, zone->h - 2 * ch);
1081                             ecore_x_window_show(zone->edge.right);
1082                          }
1083                        break;
1084
1085                      case E_ZONE_EDGE_TOP:
1086                        if (!zone->edge.top)
1087                          {
1088                             zone->edge.top = ecore_x_window_input_new(con->win,
1089                                                                       zone->x + 1 + cw, zone->y,
1090                                                                       zone->w - 2 * cw - 2, 1);
1091                             ecore_x_window_show(zone->edge.top);
1092                          }
1093                        break;
1094
1095                      case E_ZONE_EDGE_BOTTOM:
1096                        if (!zone->edge.bottom)
1097                          {
1098                             zone->edge.bottom = ecore_x_window_input_new(con->win,
1099                                                                          zone->x + 1 + cw, zone->y + zone->h - 1,
1100                                                                          zone->w - 2 - 2 * cw, 1);
1101                             ecore_x_window_show(zone->edge.bottom);
1102                          }
1103                        break;
1104
1105                      case E_ZONE_EDGE_TOP_LEFT:
1106                        if (!zone->corner.left_top)
1107                          {
1108                             zone->corner.left_top = ecore_x_window_input_new(con->win,
1109                                                                              zone->x, zone->y, 1, ch);
1110                             ecore_x_window_show(zone->corner.left_top);
1111                          }
1112                        if (!zone->corner.top_left)
1113                          {
1114                             zone->corner.top_left = ecore_x_window_input_new(con->win,
1115                                                                              zone->x + 1, zone->y, cw, 1);
1116                             ecore_x_window_show(zone->corner.top_left);
1117                          }
1118                        break;
1119
1120                      case E_ZONE_EDGE_TOP_RIGHT:
1121                        if (!zone->corner.top_right)
1122                          {
1123                             zone->corner.top_right = ecore_x_window_input_new(con->win,
1124                                                                               zone->x + zone->w - cw - 2,
1125                                                                               zone->y, cw, 1);
1126                             ecore_x_window_show(zone->corner.top_right);
1127                          }
1128                        if (!zone->corner.right_top)
1129                          {
1130                             zone->corner.right_top = ecore_x_window_input_new(con->win,
1131                                                                               zone->x + zone->w - 1,
1132                                                                               zone->y, 1, ch);
1133                             ecore_x_window_show(zone->corner.right_top);
1134                          }
1135                        break;
1136
1137                      case E_ZONE_EDGE_BOTTOM_RIGHT:
1138                        if (!zone->corner.right_bottom)
1139                          {
1140                             zone->corner.right_bottom = ecore_x_window_input_new(con->win,
1141                                                                                  zone->x + zone->w - 1,
1142                                                                                  zone->y + zone->h - ch, 1, ch);
1143                             ecore_x_window_show(zone->corner.right_bottom);
1144                          }
1145                        if (!zone->corner.bottom_right)
1146                          {
1147                             zone->corner.bottom_right = ecore_x_window_input_new(con->win,
1148                                                                                  zone->x + zone->w - cw - 2,
1149                                                                                  zone->y + zone->h - 1, cw, 1);
1150
1151                             ecore_x_window_show(zone->corner.bottom_right);
1152                          }
1153                        break;
1154
1155                      case E_ZONE_EDGE_BOTTOM_LEFT:
1156                        if (!zone->corner.bottom_left)
1157                          {
1158                             zone->corner.bottom_left = ecore_x_window_input_new(con->win,
1159                                                                                 zone->x + 1,
1160                                                                                 zone->y + zone->h - 1, cw, 1);
1161                             ecore_x_window_show(zone->corner.bottom_left);
1162                          }
1163                        if (!zone->corner.left_bottom)
1164                          {
1165                             zone->corner.left_bottom = ecore_x_window_input_new(con->win,
1166                                                                                 zone->x, zone->y + zone->h - ch,
1167                                                                                 1, ch);
1168                             ecore_x_window_show(zone->corner.left_bottom);
1169                          }
1170                        break;
1171                     }
1172                   if (e_config->fullscreen_flip)
1173                     e_zone_edge_win_layer_set(zone, 250);
1174                   else
1175                     e_zone_edge_win_layer_set(zone, 200);
1176                }
1177           }
1178      }
1179 }
1180
1181 EAPI void
1182 e_zone_edge_free(E_Zone_Edge edge)
1183 {
1184    Eina_List *l, *ll, *lll;
1185    E_Manager *man;
1186    E_Container *con;
1187    E_Zone *zone;
1188
1189    EINA_LIST_FOREACH(e_manager_list(), l, man)
1190      {
1191         EINA_LIST_FOREACH(man->containers, ll, con)
1192           {
1193              EINA_LIST_FOREACH(con->zones, lll, zone)
1194                {
1195                   switch (edge)
1196                     {
1197                      case E_ZONE_EDGE_NONE:
1198                        /* noop */
1199                        break;
1200
1201                      case E_ZONE_EDGE_LEFT:
1202                        if (zone->edge.left) ecore_x_window_free(zone->edge.left);
1203                        zone->edge.left = 0;
1204                        break;
1205
1206                      case E_ZONE_EDGE_RIGHT:
1207                        if (zone->edge.right) ecore_x_window_free(zone->edge.right);
1208                        zone->edge.right = 0;
1209                        break;
1210
1211                      case E_ZONE_EDGE_TOP:
1212                        if (zone->edge.top) ecore_x_window_free(zone->edge.top);
1213                        zone->edge.top = 0;
1214                        break;
1215
1216                      case E_ZONE_EDGE_BOTTOM:
1217                        if (zone->edge.bottom) ecore_x_window_free(zone->edge.bottom);
1218                        zone->edge.bottom = 0;
1219                        break;
1220
1221                      case E_ZONE_EDGE_TOP_LEFT:
1222                        if (zone->corner.left_top) ecore_x_window_free(zone->corner.left_top);
1223                        if (zone->corner.top_left) ecore_x_window_free(zone->corner.top_left);
1224                        zone->corner.left_top = 0;
1225                        zone->corner.top_left = 0;
1226                        break;
1227
1228                      case E_ZONE_EDGE_TOP_RIGHT:
1229                        if (zone->corner.top_right) ecore_x_window_free(zone->corner.top_right);
1230                        if (zone->corner.right_top) ecore_x_window_free(zone->corner.right_top);
1231                        zone->corner.top_right = 0;
1232                        zone->corner.right_top = 0;
1233                        break;
1234
1235                      case E_ZONE_EDGE_BOTTOM_RIGHT:
1236                        if (zone->corner.right_bottom) ecore_x_window_free(zone->corner.right_bottom);
1237                        if (zone->corner.bottom_right) ecore_x_window_free(zone->corner.bottom_right);
1238                        zone->corner.right_bottom = 0;
1239                        zone->corner.bottom_right = 0;
1240                        break;
1241
1242                      case E_ZONE_EDGE_BOTTOM_LEFT:
1243                        if (zone->corner.bottom_left) ecore_x_window_free(zone->corner.bottom_left);
1244                        if (zone->corner.left_bottom) ecore_x_window_free(zone->corner.left_bottom);
1245                        zone->corner.bottom_left = 0;
1246                        zone->corner.left_bottom = 0;
1247                        break;
1248                     }
1249                }
1250           }
1251      }
1252 }
1253
1254 EAPI void
1255 e_zone_edge_win_layer_set(E_Zone *zone,
1256                           int     layer)
1257 {
1258    if (zone->corner.left_bottom) e_container_window_raise(zone->container, zone->corner.left_bottom, layer);
1259    if (zone->corner.left_top) e_container_window_raise(zone->container, zone->corner.left_top, layer);
1260    if (zone->corner.top_left) e_container_window_raise(zone->container, zone->corner.top_left, layer);
1261    if (zone->corner.top_right) e_container_window_raise(zone->container, zone->corner.top_right, layer);
1262    if (zone->corner.right_top) e_container_window_raise(zone->container, zone->corner.right_top, layer);
1263    if (zone->corner.right_bottom) e_container_window_raise(zone->container, zone->corner.right_bottom, layer);
1264    if (zone->corner.bottom_right) e_container_window_raise(zone->container, zone->corner.bottom_right, layer);
1265    if (zone->corner.bottom_left) e_container_window_raise(zone->container, zone->corner.bottom_left, layer);
1266
1267    if (zone->edge.left) e_container_window_raise(zone->container, zone->edge.left, layer);
1268    if (zone->edge.right) e_container_window_raise(zone->container, zone->edge.right, layer);
1269    if (zone->edge.top) e_container_window_raise(zone->container, zone->edge.top, layer);
1270    if (zone->edge.bottom) e_container_window_raise(zone->container, zone->edge.bottom, layer);
1271 }
1272
1273 static void
1274 _e_zone_useful_geometry_calc(E_Zone *zone)
1275 {
1276    const E_Shelf *shelf;
1277    Eina_List *shelves;
1278    int x0, x1, yy0, yy1;
1279
1280    x0 = 0;
1281    yy0 = 0;
1282    x1 = zone->w;
1283    yy1 = zone->h;
1284    shelves = e_shelf_list_all();
1285    EINA_LIST_FREE(shelves, shelf)
1286      {
1287         E_Config_Shelf_Desk *sd;
1288         E_Gadcon_Orient orient;
1289         Eina_List *ll;
1290         int skip_shelf = 0;
1291
1292         if (shelf->zone != zone)
1293           continue;
1294
1295         if (shelf->cfg)
1296           {
1297              if (shelf->cfg->overlap)
1298                continue;
1299
1300              if (shelf->cfg->autohide)
1301                continue;
1302              orient = shelf->cfg->orient;
1303
1304              if (shelf->cfg->desk_show_mode)
1305                {
1306                   skip_shelf = 1;
1307                   EINA_LIST_FOREACH(shelf->cfg->desk_list, ll, sd)
1308                     {
1309                        if (!sd) continue;
1310                        if ((sd->x == zone->desk_x_current) && (sd->y == zone->desk_y_current))
1311                          {
1312                             skip_shelf = 0;
1313                             break;
1314                          }
1315                     }
1316                   if (skip_shelf)
1317                     continue;
1318                }
1319           }
1320         else
1321           orient = shelf->gadcon->orient;
1322
1323         switch (orient)
1324           {
1325             /* these are non-edje orientations */
1326             case E_GADCON_ORIENT_FLOAT:
1327             case E_GADCON_ORIENT_HORIZ:
1328             case E_GADCON_ORIENT_VERT:
1329               break;
1330
1331             case E_GADCON_ORIENT_TOP:
1332             case E_GADCON_ORIENT_CORNER_TL:
1333             case E_GADCON_ORIENT_CORNER_TR:
1334               if (yy0 < shelf->h)
1335                 yy0 = shelf->h;
1336               break;
1337
1338             case E_GADCON_ORIENT_BOTTOM:
1339             case E_GADCON_ORIENT_CORNER_BL:
1340             case E_GADCON_ORIENT_CORNER_BR:
1341               if (yy1 > zone->h - shelf->h)
1342                 yy1 = zone->h - shelf->h;
1343               break;
1344               break;
1345
1346             case E_GADCON_ORIENT_LEFT:
1347             case E_GADCON_ORIENT_CORNER_LT:
1348             case E_GADCON_ORIENT_CORNER_LB:
1349               if (x0 < shelf->w)
1350                 x0 = shelf->w;
1351               break;
1352
1353             case E_GADCON_ORIENT_RIGHT:
1354             case E_GADCON_ORIENT_CORNER_RT:
1355             case E_GADCON_ORIENT_CORNER_RB:
1356               if (x1 > zone->w - shelf->w)
1357                 x1 = zone->w - shelf->w;
1358               break;
1359             default:
1360               break;
1361           }
1362      }
1363
1364    zone->useful_geometry.x = zone->x + x0;
1365    zone->useful_geometry.y = zone->y + yy0;
1366    zone->useful_geometry.w = x1 - x0;
1367    zone->useful_geometry.h = yy1 - yy0;
1368    zone->useful_geometry.dirty = 0;
1369 }
1370
1371 /**
1372  * Get (or calculate) the useful (or free, without any shelves) area.
1373  */
1374 EAPI void
1375 e_zone_useful_geometry_get(E_Zone *zone,
1376                            int    *x,
1377                            int    *y,
1378                            int    *w,
1379                            int    *h)
1380 {
1381    Eina_List *l;
1382    E_Shelf *shelf;
1383
1384    E_OBJECT_CHECK(zone);
1385    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1386
1387    if (!zone->useful_geometry.dirty)
1388      {
1389         EINA_LIST_FOREACH(e_shelf_list(), l, shelf)
1390           {
1391              if (!shelf->cfg) continue;
1392              if (shelf->cfg->desk_show_mode)
1393                {
1394                   _e_zone_useful_geometry_calc(zone);
1395                   break;
1396                }
1397           }
1398      }
1399    else
1400      _e_zone_useful_geometry_calc(zone);
1401
1402    if (x) *x = zone->useful_geometry.x;
1403    if (y) *y = zone->useful_geometry.y;
1404    if (w) *w = zone->useful_geometry.w;
1405    if (h) *h = zone->useful_geometry.h;
1406 }
1407
1408 /**
1409  * Mark as dirty so e_zone_useful_geometry_get() will need to recalculate.
1410  *
1411  * Call this function when shelves are added or important properties changed.
1412  */
1413 EAPI void
1414 e_zone_useful_geometry_dirty(E_Zone *zone)
1415 {
1416    E_Event_Zone_Move_Resize *ev;
1417
1418    E_OBJECT_CHECK(zone);
1419    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1420
1421    ev = E_NEW(E_Event_Zone_Move_Resize, 1);
1422    ev->zone = zone;
1423    e_object_ref(E_OBJECT(ev->zone));
1424    ecore_event_add(E_EVENT_ZONE_MOVE_RESIZE, ev, _e_zone_event_move_resize_free, NULL);
1425
1426    zone->useful_geometry.dirty = 1;
1427    zone->useful_geometry.x = -1;
1428    zone->useful_geometry.y = -1;
1429    zone->useful_geometry.w = -1;
1430    zone->useful_geometry.h = -1;
1431 }
1432
1433 #ifdef _F_ZONE_WINDOW_ROTATION_
1434 EAPI void
1435 e_zone_rotation_set(E_Zone *zone,
1436                     int     rot)
1437 {
1438    E_Event_Zone_Rotation_Change_Begin *ev;
1439
1440    E_OBJECT_CHECK(zone);
1441    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1442
1443 #ifdef _F_USE_DLOG_
1444    SECURE_SLOGD("[ROTATION] ZONE_ROT_SET, wm_win_rotation_set:%d, wait_for_done:%d, block_count:%d, "
1445                 "curr_rot:%d, req_rot:%d",
1446                 e_config->wm_win_rotation, zone->rot.wait_for_done, zone->rot.block_count,
1447                 zone->rot.curr, rot);
1448 #endif
1449
1450    if (!e_config->wm_win_rotation) return;
1451
1452    ELBF(ELBT_ROT, 0, zone->num, "SET ROT a%d", rot);
1453
1454    if ((zone->rot.wait_for_done) ||
1455        (zone->rot.block_count > 0))
1456      {
1457         zone->rot.next = rot;
1458         zone->rot.pending = EINA_TRUE;
1459         return;
1460      }
1461    if (zone->rot.curr == rot) return;
1462
1463    zone->rot.prev = zone->rot.curr;
1464    zone->rot.curr = rot;
1465    zone->rot.wait_for_done = EINA_TRUE;
1466
1467    ev = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
1468    if (ev)
1469      {
1470         ev->zone = zone;
1471         e_object_ref(E_OBJECT(ev->zone));
1472         ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
1473                         ev, _e_zone_event_rotation_change_begin_free, NULL);
1474      }
1475
1476    ELBF(ELBT_ROT, 0, zone->num, "CHANGE ROT a%d", zone->rot.curr);
1477 }
1478
1479 EAPI int
1480 e_zone_rotation_get(E_Zone *zone)
1481 {
1482    E_OBJECT_CHECK(zone);
1483    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1484    return zone->rot.curr;
1485 }
1486
1487 EAPI Eina_Bool
1488 e_zone_rotation_block_set(E_Zone *zone, const char *name_hint, Eina_Bool set)
1489 {
1490    E_Event_Zone_Rotation_Change_Begin *ev;
1491
1492    E_OBJECT_CHECK_RETURN(zone, EINA_FALSE);
1493    E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE);
1494
1495    if (set) zone->rot.block_count++;
1496    else     zone->rot.block_count--;
1497
1498    ELBF(ELBT_ROT, 0, zone->num, "[%s ROT] count: %d, from %s",
1499         set ? "PAUSE" : "RESUME", zone->rot.block_count, name_hint);
1500
1501    if (zone->rot.block_count <= 0)
1502      {
1503         zone->rot.block_count = 0;
1504
1505 //        e_border_rotation_list_clear(zone, EINA_FALSE);
1506         if (zone->rot.pending)
1507           {
1508              zone->rot.prev = zone->rot.curr;
1509              zone->rot.curr = zone->rot.next;
1510              zone->rot.wait_for_done = EINA_TRUE;
1511              zone->rot.pending = EINA_FALSE;
1512
1513              ev = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
1514              if (ev)
1515                {
1516                   ev->zone = zone;
1517                   e_object_ref(E_OBJECT(ev->zone));
1518                   ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
1519                                   ev, _e_zone_event_rotation_change_begin_free, NULL);
1520                }
1521
1522              ELBF(ELBT_ROT, 0, zone->num, "CHANGE ROT(pending) a%d", zone->rot.curr);
1523           }
1524      }
1525
1526    return EINA_TRUE;
1527 }
1528
1529 EAPI void
1530 e_zone_rotation_update_done(E_Zone *zone)
1531 {
1532    E_Event_Zone_Rotation_Change_End *ev;
1533
1534    E_OBJECT_CHECK(zone);
1535    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1536    if (!e_config->wm_win_rotation) return;
1537
1538    ELBF(ELBT_ROT, 0, zone->num, "DONE ROT a%d", zone->rot.curr);
1539
1540    ev = E_NEW(E_Event_Zone_Rotation_Change_End, 1);
1541    if (ev)
1542      {
1543         ev->zone = zone;
1544         e_object_ref(E_OBJECT(ev->zone));
1545         ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_END,
1546                         ev, _e_zone_event_rotation_change_end_free, NULL);
1547      }
1548
1549    zone->rot.wait_for_done = EINA_FALSE;
1550    if ((zone->rot.pending) &&
1551        (zone->rot.block_count == 0))
1552      {
1553         zone->rot.prev = zone->rot.curr;
1554         zone->rot.curr = zone->rot.next;
1555         zone->rot.wait_for_done = EINA_TRUE;
1556         zone->rot.pending = EINA_FALSE;
1557
1558         E_Event_Zone_Rotation_Change_Begin *ev2;
1559         ev2 = E_NEW(E_Event_Zone_Rotation_Change_Begin, 1);
1560         if (ev2)
1561           {
1562              ev2->zone = zone;
1563              e_object_ref(E_OBJECT(ev2->zone));
1564              ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_BEGIN,
1565                              ev2, _e_zone_event_rotation_change_begin_free, NULL);
1566           }
1567
1568         ELBF(ELBT_ROT, 0, zone->num, "CHANGE ROT(pending) a%d", zone->rot.curr);
1569      }
1570 }
1571
1572 EAPI void
1573 e_zone_rotation_update_cancel(E_Zone *zone)
1574 {
1575    E_Event_Zone_Rotation_Change_Cancel *ev;
1576
1577    E_OBJECT_CHECK(zone);
1578    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
1579    if (!e_config->wm_win_rotation) return;
1580
1581    zone->rot.wait_for_done = EINA_FALSE;
1582    if (zone->rot.pending)
1583      {
1584         zone->rot.prev = zone->rot.curr;
1585         zone->rot.curr = zone->rot.next;
1586         zone->rot.pending = EINA_FALSE;
1587      }
1588
1589    ELBF(ELBT_ROT, 0, zone->num, "CANCEL ROT a%d", zone->rot.curr);
1590
1591    ev = E_NEW(E_Event_Zone_Rotation_Change_Cancel, 1);
1592    if (ev)
1593      {
1594         ev->zone = zone;
1595         e_object_ref(E_OBJECT(ev->zone));
1596         ecore_event_add(E_EVENT_ZONE_ROTATION_CHANGE_CANCEL,
1597                         ev, _e_zone_event_rotation_change_cancel_free, NULL);
1598      }
1599 }
1600 #endif
1601
1602 /* local subsystem functions */
1603 static void
1604 _e_zone_free(E_Zone *zone)
1605 {
1606    E_Container *con;
1607    int x, y;
1608
1609    //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);
1610    /* Delete the edge windows if they exist */
1611    if (zone->edge.top) ecore_x_window_free(zone->edge.top);
1612    if (zone->edge.bottom) ecore_x_window_free(zone->edge.bottom);
1613    if (zone->edge.left) ecore_x_window_free(zone->edge.left);
1614    if (zone->edge.right) ecore_x_window_free(zone->edge.right);
1615    if (zone->corner.left_bottom) ecore_x_window_free(zone->corner.left_bottom);
1616    if (zone->corner.left_top) ecore_x_window_free(zone->corner.left_top);
1617    if (zone->corner.top_left) ecore_x_window_free(zone->corner.top_left);
1618    if (zone->corner.top_right) ecore_x_window_free(zone->corner.top_right);
1619    if (zone->corner.right_top) ecore_x_window_free(zone->corner.right_top);
1620    if (zone->corner.right_bottom) ecore_x_window_free(zone->corner.right_bottom);
1621    if (zone->corner.bottom_right) ecore_x_window_free(zone->corner.bottom_right);
1622    if (zone->corner.bottom_left) ecore_x_window_free(zone->corner.bottom_left);
1623
1624    /* Delete the object event callbacks */
1625    evas_object_event_callback_del(zone->bg_event_object,
1626                                   EVAS_CALLBACK_MOUSE_DOWN,
1627                                   _e_zone_cb_bg_mouse_down);
1628    evas_object_event_callback_del(zone->bg_event_object,
1629                                   EVAS_CALLBACK_MOUSE_UP,
1630                                   _e_zone_cb_bg_mouse_up);
1631
1632    if (zone->black_ecore_evas)
1633      {
1634         e_canvas_del(zone->black_ecore_evas);
1635         ecore_evas_free(zone->black_ecore_evas);
1636         zone->black_ecore_evas = NULL;
1637      }
1638    if (zone->cur_mouse_action)
1639      {
1640         e_object_unref(E_OBJECT(zone->cur_mouse_action));
1641         zone->cur_mouse_action = NULL;
1642      }
1643
1644    /* remove handlers */
1645    E_FREE_LIST(zone->handlers, ecore_event_handler_del);
1646
1647    con = zone->container;
1648    if (zone->name) eina_stringshare_del(zone->name);
1649    con->zones = eina_list_remove(con->zones, zone);
1650    evas_object_del(zone->bg_event_object);
1651    evas_object_del(zone->bg_clip_object);
1652    evas_object_del(zone->bg_object);
1653    if (zone->prev_bg_object) evas_object_del(zone->prev_bg_object);
1654    if (zone->transition_object) evas_object_del(zone->transition_object);
1655
1656    /* free desks */
1657    for (x = 0; x < zone->desk_x_count; x++)
1658      {
1659         for (y = 0; y < zone->desk_y_count; y++)
1660           e_object_del(E_OBJECT(zone->desks[x + (y * zone->desk_x_count)]));
1661      }
1662    free(zone->desks);
1663
1664    _e_zone_black_free(zone);
1665
1666    free(zone);
1667 }
1668
1669 static void
1670 _e_zone_cb_bg_mouse_down(void            *data,
1671                          Evas *evas       __UNUSED__,
1672                          Evas_Object *obj __UNUSED__,
1673                          void *event_info __UNUSED__)
1674 {
1675    E_Zone *zone;
1676
1677    zone = data;
1678    if (e_menu_grab_window_get()) return;
1679
1680    if (!zone->cur_mouse_action)
1681      {
1682         if (ecore_event_current_type_get() == ECORE_EVENT_MOUSE_BUTTON_DOWN)
1683           {
1684              Ecore_Event_Mouse_Button *ev2;
1685
1686              ev2 = ecore_event_current_event_get();
1687              zone->cur_mouse_action =
1688                e_bindings_mouse_down_event_handle(E_BINDING_CONTEXT_ZONE,
1689                                                   E_OBJECT(zone), ev2);
1690              if (zone->cur_mouse_action)
1691                {
1692                   if ((!zone->cur_mouse_action->func.end_mouse) &&
1693                       (!zone->cur_mouse_action->func.end))
1694                     zone->cur_mouse_action = NULL;
1695                   if (zone->cur_mouse_action)
1696                     e_object_ref(E_OBJECT(zone->cur_mouse_action));
1697                }
1698           }
1699      }
1700 }
1701
1702 static void
1703 _e_zone_cb_bg_mouse_up(void            *data,
1704                        Evas *evas       __UNUSED__,
1705                        Evas_Object *obj __UNUSED__,
1706                        void *event_info __UNUSED__)
1707 {
1708    E_Zone *zone;
1709
1710    zone = data;
1711    if (zone->cur_mouse_action)
1712      {
1713         if (ecore_event_current_type_get() == ECORE_EVENT_MOUSE_BUTTON_UP)
1714           {
1715              Ecore_Event_Mouse_Button *ev2;
1716
1717              ev2 = ecore_event_current_event_get();
1718              if (zone->cur_mouse_action->func.end_mouse)
1719                zone->cur_mouse_action->func.end_mouse(E_OBJECT(zone), "", ev2);
1720              else if (zone->cur_mouse_action->func.end)
1721                zone->cur_mouse_action->func.end(E_OBJECT(zone), "");
1722           }
1723         e_object_unref(E_OBJECT(zone->cur_mouse_action));
1724         zone->cur_mouse_action = NULL;
1725      }
1726    else
1727      {
1728         if (ecore_event_current_type_get() == ECORE_EVENT_MOUSE_BUTTON_UP)
1729           {
1730              Ecore_Event_Mouse_Button *ev2;
1731
1732              ev2 = ecore_event_current_event_get();
1733              e_bindings_mouse_up_event_handle(E_BINDING_CONTEXT_ZONE,
1734                                               E_OBJECT(zone), ev2);
1735           }
1736      }
1737 }
1738
1739 static void
1740 _e_zone_event_zone_desk_count_set_free(void *data __UNUSED__,
1741                                        void      *ev)
1742 {
1743    E_Event_Zone_Desk_Count_Set *e;
1744
1745    e = ev;
1746    e_object_unref(E_OBJECT(e->zone));
1747    free(e);
1748 }
1749
1750 static Eina_Bool
1751 _e_zone_cb_mouse_in(void    *data,
1752                     int type __UNUSED__,
1753                     void    *event)
1754 {
1755    Ecore_X_Event_Mouse_In *ev;
1756    E_Event_Zone_Edge *zev;
1757    E_Zone_Edge edge;
1758    E_Zone *zone;
1759
1760    ev = event;
1761    zone = data;
1762
1763    edge = _e_zone_detect_edge(zone, ev->win);
1764    if (edge == E_ZONE_EDGE_NONE) return ECORE_CALLBACK_PASS_ON;
1765
1766    zev = E_NEW(E_Event_Zone_Edge, 1);
1767    zev->zone = zone;
1768    zev->edge = edge;
1769    zev->x = ev->root.x;
1770    zev->y = ev->root.y;
1771    zev->modifiers = ev->modifiers;
1772    ecore_event_add(E_EVENT_ZONE_EDGE_IN, zev, NULL, NULL);
1773    e_bindings_edge_in_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), zev);
1774
1775    return ECORE_CALLBACK_PASS_ON;
1776 }
1777
1778 static Eina_Bool
1779 _e_zone_cb_mouse_out(void    *data,
1780                      int type __UNUSED__,
1781                      void    *event)
1782 {
1783    Ecore_X_Event_Mouse_Out *ev;
1784    E_Event_Zone_Edge *zev;
1785    E_Zone_Edge edge;
1786    E_Zone *zone;
1787
1788    ev = event;
1789    zone = data;
1790
1791    edge = _e_zone_detect_edge(zone, ev->win);
1792    if (edge == E_ZONE_EDGE_NONE) return ECORE_CALLBACK_PASS_ON;
1793
1794    zev = E_NEW(E_Event_Zone_Edge, 1);
1795    zev->zone = zone;
1796    zev->edge = edge;
1797    zev->x = ev->root.x;
1798    zev->y = ev->root.y;
1799    zev->modifiers = ev->modifiers;
1800    ecore_event_add(E_EVENT_ZONE_EDGE_OUT, zev, NULL, NULL);
1801    e_bindings_edge_out_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), zev);
1802    return ECORE_CALLBACK_PASS_ON;
1803 }
1804
1805 static Eina_Bool
1806 _e_zone_cb_mouse_down(void    *data,
1807                       int type __UNUSED__,
1808                       void    *event)
1809 {
1810    Ecore_Event_Mouse_Button *ev;
1811    E_Event_Zone_Edge *zev;
1812    E_Zone_Edge edge;
1813    E_Zone *zone;
1814
1815    ev = event;
1816    zone = data;
1817
1818    edge = _e_zone_detect_edge(zone, ev->window);
1819    if (edge == E_ZONE_EDGE_NONE) return ECORE_CALLBACK_PASS_ON;
1820
1821    zev = E_NEW(E_Event_Zone_Edge, 1);
1822    zev->zone = zone;
1823    zev->edge = edge;
1824    zev->x = ev->root.x;
1825    zev->y = ev->root.y;
1826    zev->button = ev->buttons;
1827    zev->modifiers = ev->modifiers;
1828    ecore_event_add(E_EVENT_ZONE_EDGE_OUT, zev, NULL, NULL);
1829    e_bindings_edge_down_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), zev);
1830    return ECORE_CALLBACK_PASS_ON;
1831 }
1832
1833 static Eina_Bool
1834 _e_zone_cb_mouse_up(void    *data,
1835                     int type __UNUSED__,
1836                     void    *event)
1837 {
1838    Ecore_Event_Mouse_Button *ev;
1839    E_Event_Zone_Edge *zev;
1840    E_Zone_Edge edge;
1841    E_Zone *zone;
1842
1843    ev = event;
1844    zone = data;
1845
1846    edge = _e_zone_detect_edge(zone, ev->window);
1847    if (edge == E_ZONE_EDGE_NONE) return ECORE_CALLBACK_PASS_ON;
1848
1849    zev = E_NEW(E_Event_Zone_Edge, 1);
1850    zev->zone = zone;
1851    zev->edge = edge;
1852    zev->x = ev->root.x;
1853    zev->y = ev->root.y;
1854    zev->button = ev->buttons;
1855    zev->modifiers = ev->modifiers;
1856    ecore_event_add(E_EVENT_ZONE_EDGE_OUT, zev, NULL, NULL);
1857    e_bindings_edge_up_event_handle(E_BINDING_CONTEXT_ZONE, E_OBJECT(zone), zev);
1858    return ECORE_CALLBACK_PASS_ON;
1859 }
1860
1861 static Eina_Bool
1862 _e_zone_cb_mouse_move(void    *data,
1863                       int type __UNUSED__,
1864                       void    *event)
1865 {
1866    Ecore_Event_Mouse_Move *ev;
1867    E_Event_Zone_Edge *zev;
1868    E_Zone_Edge edge;
1869    E_Zone *zone;
1870
1871    ev = event;
1872    zone = data;
1873
1874    edge = _e_zone_detect_edge(zone, ev->window);
1875    if (edge == E_ZONE_EDGE_NONE) return ECORE_CALLBACK_PASS_ON;
1876
1877    zev = E_NEW(E_Event_Zone_Edge, 1);
1878    zev->zone = zone;
1879    zev->edge = edge;
1880    zev->x = ev->root.x;
1881    zev->y = ev->root.y;
1882    zev->modifiers = ev->modifiers;
1883    ecore_event_add(E_EVENT_ZONE_EDGE_MOVE, zev, NULL, NULL);
1884    return ECORE_CALLBACK_PASS_ON;
1885 }
1886
1887 static Eina_Bool
1888 _e_zone_cb_desk_after_show(void    *data,
1889                            int type __UNUSED__,
1890                            void    *event)
1891 {
1892    E_Event_Desk_Show *ev;
1893    E_Zone *zone;
1894
1895    ev = event;
1896    zone = data;
1897    if (ev->desk->zone != zone) return ECORE_CALLBACK_PASS_ON;
1898
1899    zone->flip.switching = 0;
1900    return ECORE_CALLBACK_PASS_ON;
1901 }
1902
1903 static Eina_Bool
1904 _e_zone_cb_edge_timer(void *data)
1905 {
1906    E_Zone *zone;
1907    E_Action *act;
1908
1909    zone = data;
1910    act = e_action_find(zone->flip.bind->action);
1911    if (!act)
1912      {
1913         E_FREE(zone->flip.ev);
1914         return ECORE_CALLBACK_CANCEL;
1915      }
1916
1917    if (act->func.go_edge)
1918      act->func.go_edge(E_OBJECT(zone), zone->flip.bind->params, zone->flip.ev);
1919    else if (act->func.go)
1920      act->func.go(E_OBJECT(zone), zone->flip.bind->params);
1921
1922    zone->flip.bind->timer = NULL;
1923
1924    E_FREE(zone->flip.ev);
1925    return ECORE_CALLBACK_CANCEL;
1926 }
1927
1928 static void
1929 _e_zone_event_move_resize_free(void *data __UNUSED__,
1930                                void      *ev)
1931 {
1932    E_Event_Zone_Move_Resize *e;
1933
1934    e = ev;
1935    e_object_unref(E_OBJECT(e->zone));
1936    free(e);
1937 }
1938
1939 static void
1940 _e_zone_event_add_free(void *data __UNUSED__,
1941                        void      *ev)
1942 {
1943    E_Event_Zone_Add *e;
1944
1945    e = ev;
1946    e_object_unref(E_OBJECT(e->zone));
1947    free(e);
1948 }
1949
1950 static void
1951 _e_zone_event_del_free(void *data __UNUSED__,
1952                        void      *ev)
1953 {
1954    E_Event_Zone_Del *e;
1955
1956    e = ev;
1957    e_object_unref(E_OBJECT(e->zone));
1958    free(e);
1959 }
1960
1961 static void
1962 _e_zone_object_del_attach(void *o)
1963 {
1964    E_Zone *zone;
1965    E_Event_Zone_Del *ev;
1966
1967    zone = o;
1968    ev = E_NEW(E_Event_Zone_Del, 1);
1969    ev->zone = zone;
1970    e_object_ref(E_OBJECT(ev->zone));
1971    ecore_event_add(E_EVENT_ZONE_DEL, ev, _e_zone_event_del_free, NULL);
1972 }
1973
1974 static E_Zone_Edge
1975 _e_zone_detect_edge(E_Zone        *zone,
1976                     Ecore_X_Window win)
1977 {
1978    E_Zone_Edge edge = E_ZONE_EDGE_NONE;
1979
1980    if (win == zone->edge.left)
1981      edge = E_ZONE_EDGE_LEFT;
1982    else if (win == zone->edge.top)
1983      edge = E_ZONE_EDGE_TOP;
1984    else if (win == zone->edge.right)
1985      edge = E_ZONE_EDGE_RIGHT;
1986    else if (win == zone->edge.bottom)
1987      edge = E_ZONE_EDGE_BOTTOM;
1988    else if ((win == zone->corner.left_top) ||
1989             (win == zone->corner.top_left))
1990      edge = E_ZONE_EDGE_TOP_LEFT;
1991    else if ((win == zone->corner.right_top) ||
1992             (win == zone->corner.top_right))
1993      edge = E_ZONE_EDGE_TOP_RIGHT;
1994    else if ((win == zone->corner.right_bottom) ||
1995             (win == zone->corner.bottom_right))
1996      edge = E_ZONE_EDGE_BOTTOM_RIGHT;
1997    else if ((win == zone->corner.left_bottom) ||
1998             (win == zone->corner.bottom_left))
1999      edge = E_ZONE_EDGE_BOTTOM_LEFT;
2000    return edge;
2001 }
2002
2003 static void
2004 _e_zone_edge_move_resize(E_Zone *zone)
2005 {
2006    int cw;
2007    int ch;
2008
2009    cw = zone->w * E_ZONE_CORNER_RATIO;
2010    ch = zone->h * E_ZONE_CORNER_RATIO;
2011
2012    if (zone->corner.left_bottom)
2013      ecore_x_window_move_resize(zone->corner.left_bottom,
2014                                 zone->x, zone->y + zone->h - ch, 1, ch);
2015    if (zone->edge.left)
2016      ecore_x_window_move_resize(zone->edge.left,
2017                                 zone->x, zone->y + ch, 1, zone->h - 2 * ch);
2018    if (zone->corner.left_top)
2019      ecore_x_window_move_resize(zone->corner.left_top,
2020                                 zone->x, zone->y, 1, ch);
2021
2022    if (zone->corner.top_left)
2023      ecore_x_window_move_resize(zone->corner.top_left,
2024                                 zone->x + 1, zone->y, cw, 1);
2025    if (zone->edge.top)
2026      ecore_x_window_move_resize(zone->edge.top,
2027                                 zone->x + 1 + cw, zone->y, zone->w - 2 * cw - 2, 1);
2028    if (zone->corner.top_right)
2029      ecore_x_window_move_resize(zone->corner.top_right,
2030                                 zone->x + zone->w - cw - 2, zone->y, cw, 1);
2031
2032    if (zone->corner.right_top)
2033      ecore_x_window_move_resize(zone->corner.right_top,
2034                                 zone->x + zone->w - 1, zone->y, 1, ch);
2035    if (zone->edge.right)
2036      ecore_x_window_move_resize(zone->edge.right,
2037                                 zone->x + zone->w - 1, zone->y + ch, 1, zone->h - 2 * ch);
2038    if (zone->corner.right_bottom)
2039      ecore_x_window_move_resize(zone->corner.right_bottom,
2040                                 zone->x + zone->w - 1, zone->y + zone->h - ch, 1, ch);
2041
2042    if (zone->corner.bottom_right)
2043      ecore_x_window_move_resize(zone->corner.bottom_right,
2044                                 zone->x + 1, zone->y + zone->h - 1, cw, 1);
2045    if (zone->edge.bottom)
2046      ecore_x_window_move_resize(zone->edge.bottom,
2047                                 zone->x + 1 + cw, zone->y + zone->h - 1, zone->w - 2 - 2 * cw, 1);
2048    if (zone->corner.bottom_left)
2049      ecore_x_window_move_resize(zone->corner.bottom_left,
2050                                 zone->x + zone->w - cw - 2, zone->y + zone->h - 1, cw, 1);
2051 }
2052
2053 static void
2054 _e_zone_border_geometry_update(E_Zone *zone)
2055 {
2056    Eina_List *borders, *l;
2057    E_Border *bd;
2058    unsigned int zgeom[4];
2059    
2060    zgeom[0] = zone->x;
2061    zgeom[1] = zone->y;
2062    zgeom[2] = zone->w;
2063    zgeom[3] = zone->h;
2064    borders = e_border_client_list();
2065    EINA_LIST_FOREACH(borders, l, bd)
2066      {
2067         if (bd->zone == zone)
2068           ecore_x_window_prop_card32_set(bd->client.win, 
2069                                          E_ATOM_ZONE_GEOMETRY, 
2070                                          zgeom, 4);
2071      }
2072 }
2073
2074 #ifdef _F_ZONE_WINDOW_ROTATION_
2075 static void
2076 _e_zone_event_rotation_change_begin_free(void *data __UNUSED__,
2077                                          void      *ev)
2078 {
2079    E_Event_Zone_Rotation_Change_Begin *e = ev;
2080    e_object_unref(E_OBJECT(e->zone));
2081    E_FREE(e);
2082 }
2083
2084 static void
2085 _e_zone_event_rotation_change_cancel_free(void *data __UNUSED__,
2086                                           void      *ev)
2087 {
2088    E_Event_Zone_Rotation_Change_Cancel *e = ev;
2089    e_object_unref(E_OBJECT(e->zone));
2090    E_FREE(e);
2091 }
2092
2093 static void
2094 _e_zone_event_rotation_change_end_free(void *data __UNUSED__,
2095                                        void      *ev)
2096 {
2097    E_Event_Zone_Rotation_Change_End *e = ev;
2098    e_object_unref(E_OBJECT(e->zone));
2099    E_FREE(e);
2100 }
2101 #endif