06bff4f53fe09509d18f61bee1fbb82342b3f34d
[framework/uifw/e17.git] / src / modules / illume2 / policies / illume / policy.c
1 #include "e_illume.h"
2 #include "policy.h"
3
4 /* NB: DIALOG_USES_PIXEL_BORDER is an experiment in setting dialog windows 
5  * to use the 'pixel' type border. This is done because some dialogs, 
6  * when shown, blend into other windows too much. Pixel border adds a 
7  * little distinction between the dialog window and an app window.
8  * Disable if this is not wanted */
9 #define DIALOG_USES_PIXEL_BORDER 1
10
11 /* local function prototypes */
12 static void _policy_border_set_focus(E_Border *bd);
13 static void _policy_border_move(E_Border *bd, int x, int y);
14 static void _policy_border_resize(E_Border *bd, int w, int h);
15 static void _policy_border_hide_below(E_Border *bd);
16 static void _policy_border_show_below(E_Border *bd);
17 static void _policy_zone_layout_update(E_Zone *zone);
18 static void _policy_zone_layout_indicator(E_Border *bd, E_Illume_Config_Zone *cz);
19 static void _policy_zone_layout_quickpanel(E_Border *bd);
20 static void _policy_zone_layout_softkey(E_Border *bd, E_Illume_Config_Zone *cz);
21 static void _policy_zone_layout_keyboard(E_Border *bd, E_Illume_Config_Zone *cz);
22 static void _policy_zone_layout_home_single(E_Border *bd, E_Illume_Config_Zone *cz);
23 static void _policy_zone_layout_home_dual_top(E_Border *bd, E_Illume_Config_Zone *cz);
24 static void _policy_zone_layout_home_dual_custom(E_Border *bd, E_Illume_Config_Zone *cz);
25 static void _policy_zone_layout_home_dual_left(E_Border *bd, E_Illume_Config_Zone *cz);
26 static void _policy_zone_layout_fullscreen(E_Border *bd);
27 static void _policy_zone_layout_app_single(E_Border *bd, E_Illume_Config_Zone *cz);
28 static void _policy_zone_layout_app_dual_top(E_Border *bd, E_Illume_Config_Zone *cz);
29 static void _policy_zone_layout_app_dual_custom(E_Border *bd, E_Illume_Config_Zone *cz);
30 static void _policy_zone_layout_app_dual_left(E_Border *bd, E_Illume_Config_Zone *cz);
31 static void _policy_zone_layout_dialog(E_Border *bd, E_Illume_Config_Zone *cz);
32 static void _policy_zone_layout_splash(E_Border *bd, E_Illume_Config_Zone *cz);
33 static void _policy_zone_layout_conformant_single(E_Border *bd, E_Illume_Config_Zone *cz);
34 static void _policy_zone_layout_conformant_dual_top(E_Border *bd, E_Illume_Config_Zone *cz);
35 static void _policy_zone_layout_conformant_dual_custom(E_Border *bd, E_Illume_Config_Zone *cz);
36 static void _policy_zone_layout_conformant_dual_left(E_Border *bd, E_Illume_Config_Zone *cz);
37
38 static Eina_List *_pol_focus_stack;
39
40 /* local functions */
41 static void 
42 _policy_border_set_focus(E_Border *bd) 
43 {
44    if (!bd) return;
45
46    /* if focus is locked out then get out */
47    if (bd->lock_focus_out) return;
48
49    /* make sure the border can accept or take focus */
50    if ((bd->client.icccm.accepts_focus) || (bd->client.icccm.take_focus)) 
51      {
52         /* check E's focus settings */
53         if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || 
54             ((bd->parent) && 
55              ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) || 
56               ((bd->parent->focused) && 
57                (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED))))) 
58           {
59              /* if the border was hidden due to layout, we need to unhide */
60              if (!bd->visible) e_illume_border_show(bd);
61
62              if ((bd->iconic) && (!bd->lock_user_iconify)) 
63                 e_border_uniconify(bd);
64              
65              if (!bd->lock_user_stacking) e_border_raise(bd);
66
67              /* focus the border */
68              e_border_focus_set(bd, 1, 1);
69
70              /* hide the border below this one */
71              _policy_border_hide_below(bd);
72
73              /* NB: since we skip needless border evals when container layout 
74               * is called (to save cpu cycles), we need to 
75               * signal this border that it's focused so that the edj gets 
76               * updated. 
77               * 
78               * This is potentially useless as THIS policy 
79               * makes all windows borderless anyway, but it's in here for 
80               * completeness
81              e_border_focus_latest_set(bd);
82              if (bd->bg_object) 
83                edje_object_signal_emit(bd->bg_object, "e,state,focused", "e");
84              if (bd->icon_object) 
85                edje_object_signal_emit(bd->icon_object, "e,state,focused", "e");
86              e_focus_event_focus_in(bd);
87               */
88           }
89      }
90 }
91
92 static void 
93 _policy_border_move(E_Border *bd, int x, int y) 
94 {
95    if (!bd) return;
96
97    /* NB: Qt uses a weird window type called 'VCLSalFrame' that needs to 
98     * have bd->placed set else it doesn't position correctly...
99     * this could be a result of E honoring the icccm request position, 
100     * not sure */
101
102    /* NB: Seems something similar happens with elementary windows also
103     * so for now just set bd->placed on all windows until this 
104     * gets investigated */
105    bd->placed = 1;
106    bd->x = x;
107    bd->y = y;
108    bd->changes.pos = 1;
109    bd->changed = 1;
110 }
111
112 static void 
113 _policy_border_resize(E_Border *bd, int w, int h) 
114 {
115    if (!bd) return;
116
117    bd->w = w;
118    bd->h = h;
119    bd->client.w = (bd->w - (bd->client_inset.l + bd->client_inset.r));
120    bd->client.h = (bd->h - (bd->client_inset.t + bd->client_inset.b));
121    bd->changes.size = 1;
122    bd->changed = 1;
123 }
124
125 static void 
126 _policy_border_hide_below(E_Border *bd) 
127 {
128    int pos = 0, i;
129
130 //   printf("Hide Borders Below: %s %d %d\n", 
131 //          bd->client.icccm.name, bd->x, bd->y);
132
133    if (!bd) return;
134
135    /* determine layering position */
136    if (bd->layer <= 0) pos = 0;
137    else if ((bd->layer > 0) && (bd->layer <= 50)) pos = 1;
138    else if ((bd->layer > 50) && (bd->layer <= 100)) pos = 2;
139    else if ((bd->layer > 100) && (bd->layer <= 150)) pos = 3;
140    else if ((bd->layer > 150) && (bd->layer <= 200)) pos = 4;
141    else pos = 5;
142
143    /* Find the windows below this one */
144    for (i = pos; i >= 2; i--) 
145      {
146         Eina_List *l;
147         E_Border *b;
148
149         EINA_LIST_FOREACH(bd->zone->container->layers[i].clients, l, b) 
150           {
151              /* skip if it's the same border */
152              if (b == bd) continue;
153
154              /* skip if it's not on this zone */
155              if (b->zone != bd->zone) continue;
156
157              /* skip special borders */
158              if (e_illume_border_is_indicator(b)) continue;
159              if (e_illume_border_is_softkey(b)) continue;
160              if (e_illume_border_is_keyboard(b)) continue;
161              if (e_illume_border_is_quickpanel(b)) continue;
162              if (e_illume_border_is_home(b)) continue;
163
164              if ((bd->fullscreen) || (bd->need_fullscreen)) 
165                {
166                   if (b->visible) e_illume_border_hide(b);
167                }
168              else 
169                {
170                   /* we need to check x/y position */
171                   if (E_CONTAINS(bd->x, bd->y, bd->w, bd->h, 
172                                  b->x, b->y, b->w, b->h))
173                     {
174                        if (b->visible) e_illume_border_hide(b);
175                     }
176                }
177           }
178      }
179 }
180
181 static void 
182 _policy_border_show_below(E_Border *bd) 
183 {
184    Eina_List *l;
185    E_Border *prev;
186    int pos = 0, i;
187
188 //   printf("Show Borders Below: %s %d %d\n", 
189 //          bd->client.icccm.class, bd->x, bd->y);
190
191    if (!bd) return;
192
193    if (bd->client.icccm.transient_for) 
194      {
195         if ((prev = e_border_find_by_client_window(bd->client.icccm.transient_for))) 
196           {
197              _policy_border_set_focus(prev);
198              return;
199           }
200      }
201
202    /* determine layering position */
203    if (bd->layer <= 0) pos = 0;
204    else if ((bd->layer > 0) && (bd->layer <= 50)) pos = 1;
205    else if ((bd->layer > 50) && (bd->layer <= 100)) pos = 2;
206    else if ((bd->layer > 100) && (bd->layer <= 150)) pos = 3;
207    else if ((bd->layer > 150) && (bd->layer <= 200)) pos = 4;
208    else pos = 5;
209
210    /* Find the windows below this one */
211    for (i = pos; i >= 2; i--) 
212      {
213         E_Border *b;
214
215         EINA_LIST_REVERSE_FOREACH(bd->zone->container->layers[i].clients, l, b) 
216           {
217              /* skip if it's the same border */
218              if (b == bd) continue;
219
220              /* skip if it's not on this zone */
221              if (b->zone != bd->zone) continue;
222
223              /* skip special borders */
224              if (e_illume_border_is_indicator(b)) continue;
225              if (e_illume_border_is_softkey(b)) continue;
226              if (e_illume_border_is_keyboard(b)) continue;
227              if (e_illume_border_is_quickpanel(b)) continue;
228              if (e_illume_border_is_home(b)) continue;
229
230              if ((bd->fullscreen) || (bd->need_fullscreen)) 
231                {
232                   _policy_border_set_focus(b);
233                   return;
234                }
235              else 
236                {
237                   /* need to check x/y position */
238                   if (E_CONTAINS(bd->x, bd->y, bd->w, bd->h, 
239                                  b->x, b->y, b->w, b->h))
240                     {
241                        _policy_border_set_focus(b);
242                        return;
243                     }
244                }
245           }
246      }
247
248    /* if we reach here, then there is a problem with showing a window below
249     * this one, so show previous window in stack */
250    EINA_LIST_REVERSE_FOREACH(_pol_focus_stack, l, prev) 
251      {
252         if (prev->zone != bd->zone) continue;
253         _policy_border_set_focus(prev);
254         return;
255      }
256
257    /* Fallback to focusing home if all above fails */
258    _policy_focus_home(bd->zone);
259 }
260
261 static void 
262 _policy_zone_layout_update(E_Zone *zone) 
263 {
264    Eina_List *l;
265    E_Border *bd;
266
267    if (!zone) return;
268
269    EINA_LIST_FOREACH(e_border_client_list(), l, bd) 
270      {
271         /* skip borders not on this zone */
272         if (bd->zone != zone) continue;
273
274         /* skip special windows */
275         if (e_illume_border_is_keyboard(bd)) continue;
276         if (e_illume_border_is_quickpanel(bd)) continue;
277
278         /* signal a changed pos here so layout gets updated */
279         bd->changes.pos = 1;
280         bd->changed = 1;
281      }
282 }
283
284 static void 
285 _policy_zone_layout_indicator(E_Border *bd, E_Illume_Config_Zone *cz) 
286 {
287    if ((!bd) || (!cz)) return;
288
289    /* grab minimum indicator size */
290    e_illume_border_min_get(bd, NULL, &cz->indicator.size);
291
292    /* no point in doing anything here if indicator is hidden */
293    if ((!bd->new_client) && (!bd->visible))
294       {
295          ecore_x_e_illume_indicator_geometry_set(bd->zone->black_win,
296                                                  0, 0, 0, 0);
297          return;
298       }
299
300    /* if we are dragging, then skip it for now */
301    if (bd->client.illume.drag.drag) 
302      {
303         /* when dragging indicator, we need to trigger a layout update */
304          ecore_x_e_illume_indicator_geometry_set(bd->zone->black_win,
305                                                  0, 0, 0, 0);
306         _policy_zone_layout_update(bd->zone);
307         return;
308      }
309
310 //   printf("\tLayout Indicator: %d\n", bd->zone->id);
311
312    /* lock indicator window from dragging if we need to */
313    if ((cz->mode.dual == 1) && (cz->mode.side == 0)) 
314      ecore_x_e_illume_drag_locked_set(bd->client.win, 0);
315    else 
316      ecore_x_e_illume_drag_locked_set(bd->client.win, 1);
317
318    /* make sure it's the required width & height */
319    if ((bd->w != bd->zone->w) || (bd->h != cz->indicator.size))
320      _policy_border_resize(bd, bd->zone->w, cz->indicator.size);
321
322    /* are we in single mode ? */
323    if (!cz->mode.dual) 
324      {
325         /* move to 0, 0 (relative to zone) if needed */
326         if ((bd->x != bd->zone->x) || (bd->y != bd->zone->y)) 
327           {
328              _policy_border_move(bd, bd->zone->x, bd->zone->y);
329              ecore_x_e_illume_quickpanel_position_update_send(bd->client.win);
330           }
331      }
332    else 
333      {
334         /* dual app mode top */
335         if (cz->mode.side == 0) 
336           {
337              /* top mode...indicator is draggable so just set X.
338               * in this case, the indicator itself should be responsible for 
339               * sending the quickpanel position update message when it is 
340               * finished dragging */
341              if (bd->x != bd->zone->x) 
342                _policy_border_move(bd, bd->zone->x, bd->y);
343           }
344         else 
345           {
346              /* move to 0, 0 (relative to zone) if needed */
347              if ((bd->x != bd->zone->x) || (bd->y != bd->zone->y)) 
348                {
349                   _policy_border_move(bd, bd->zone->x, bd->zone->y);
350                   ecore_x_e_illume_quickpanel_position_update_send(bd->client.win);
351                }
352           }
353      }
354    ecore_x_e_illume_indicator_geometry_set(bd->zone->black_win,
355                                            bd->x, bd->y,
356                                            bd->w, bd->h);
357
358    /* set layer if needed */
359    if (bd->layer != POL_INDICATOR_LAYER) 
360      e_border_layer_set(bd, POL_INDICATOR_LAYER);
361 }
362
363 static void 
364 _policy_zone_layout_quickpanel(E_Border *bd) 
365 {
366    int mh;
367
368    if (!bd) return;
369
370    /* grab minimum size */
371    e_illume_border_min_get(bd, NULL, &mh);
372
373    /* resize if needed */
374    if ((bd->w != bd->zone->w) || (bd->h != mh))
375      _policy_border_resize(bd, bd->zone->w, mh);
376
377    /* set layer if needed */
378    if (bd->layer != POL_QUICKPANEL_LAYER) 
379      e_border_layer_set(bd, POL_QUICKPANEL_LAYER);
380 }
381
382 static void 
383 _policy_zone_layout_softkey(E_Border *bd, E_Illume_Config_Zone *cz) 
384 {
385    int ny;
386
387    if (!bd) return;
388
389    /* grab minimum softkey size */
390    e_illume_border_min_get(bd, NULL, &cz->softkey.size);
391
392    /* no point in doing anything here if softkey is hidden */
393    if (!bd->visible)
394      {
395         ecore_x_e_illume_softkey_geometry_set(bd->zone->black_win,
396                                               0, 0, 0, 0);
397         return;
398      }
399
400    /* if we are dragging, then skip it for now */
401    /* NB: Disabled currently until we confirm that softkey should be draggable */
402 //   if (bd->client.illume.drag.drag) return;
403
404    /* make sure it's the required width & height */
405    if ((bd->w != bd->zone->w) || (bd->h != cz->softkey.size))
406      _policy_border_resize(bd, bd->zone->w, cz->softkey.size);
407
408    /* make sure it's in the correct position */
409    ny = ((bd->zone->y + bd->zone->h) - cz->softkey.size);
410
411    /* NB: not sure why yet, but on startup the border->y is reporting 
412     * that it is already in this position...but it's actually not. 
413     * So for now, just disable the ny check until this gets sorted out */
414 //   if ((bd->x != bd->zone->x) || (bd->y != ny))
415      _policy_border_move(bd, bd->zone->x, ny);
416    // set property for apps to find out they are
417    ecore_x_e_illume_softkey_geometry_set(bd->zone->black_win,
418                                          bd->x, bd->y,
419                                          bd->w, bd->h);
420
421    /* set layer if needed */
422    if (bd->layer != POL_SOFTKEY_LAYER) 
423      e_border_layer_set(bd, POL_SOFTKEY_LAYER);
424 }
425
426 static void 
427 _policy_zone_layout_keyboard(E_Border *bd, E_Illume_Config_Zone *cz) 
428 {
429    int ny, layer;
430
431 //   printf("\tLayout Keyboard\n");
432
433    if ((!bd) || (!cz)) return;
434
435    /* no point in adjusting size or position if it's not visible */
436    if (!bd->visible) return;
437
438    /* grab minimum keyboard size */
439    e_illume_border_min_get(bd, NULL, &cz->vkbd.size);
440
441    /* make sure it's the required width & height */
442    if ((bd->w != bd->zone->w) || (bd->h != cz->vkbd.size))
443      _policy_border_resize(bd, bd->zone->w, cz->vkbd.size);
444
445    /* make sure it's in the correct position */
446    ny = ((bd->zone->y + bd->zone->h) - cz->vkbd.size);
447    if ((bd->x != bd->zone->x) || (bd->y != ny)) 
448      _policy_border_move(bd, bd->zone->x, ny);
449
450    /* check layer according to fullscreen state */
451    if ((bd->fullscreen) || (bd->need_fullscreen)) 
452      layer = POL_FULLSCREEN_LAYER;
453    else
454      layer = POL_KEYBOARD_LAYER;
455
456    /* set layer if needed */
457    if ((int)bd->layer != layer) e_border_layer_set(bd, layer);
458 }
459
460 static void 
461 _policy_zone_layout_home_single(E_Border *bd, E_Illume_Config_Zone *cz) 
462 {
463    int ny, nh, indsz = 0, sftsz = 0;
464    E_Border *ind, *sft;
465
466    if ((!bd) || (!cz)) return;
467
468    /* no point in adjusting size or position if it's not visible */
469    if (!bd->visible) return;
470
471    printf("\tLayout Home Single: %s\n", bd->client.icccm.class);
472
473    indsz = cz->indicator.size;
474    sftsz = cz->softkey.size;
475    if ((ind = e_illume_border_indicator_get(bd->zone)))
476      {
477         if (!ind->visible) indsz = 0;
478      }
479    if ((sft = e_illume_border_softkey_get(bd->zone)))
480      {
481         if (!sft->visible) sftsz = 0;
482      }
483    /* make sure it's the required width & height */
484    if (e_illume_border_is_conformant(bd)) nh = bd->zone->h;
485    else nh = (bd->zone->h - indsz - sftsz);
486    
487    if ((bd->w != bd->zone->w) || (bd->h != nh)) 
488      _policy_border_resize(bd, bd->zone->w, nh);
489
490    /* move to correct position (relative to zone) if needed */
491    if (e_illume_border_is_conformant(bd)) ny = bd->zone->y;
492    else ny = (bd->zone->y + indsz);
493    if ((bd->x != bd->zone->x) || (bd->y != ny)) 
494      _policy_border_move(bd, bd->zone->x, ny);
495
496    /* set layer if needed */
497    if (bd->layer != POL_HOME_LAYER) e_border_layer_set(bd, POL_HOME_LAYER);
498 }
499
500 static void 
501 _policy_zone_layout_home_dual_top(E_Border *bd, E_Illume_Config_Zone *cz) 
502 {
503    E_Border *home, *ind, *sft;
504    int ny, nh, indsz = 0, sftsz = 0;
505
506    if ((!bd) || (!cz)) return;
507
508    /* no point in adjusting size or position if it's not visible */
509    if (!bd->visible) return;
510
511    indsz = cz->indicator.size;
512    sftsz = cz->softkey.size;
513    if ((ind = e_illume_border_indicator_get(bd->zone)))
514      {
515         if (!ind->visible) indsz = 0;
516      }
517    if ((sft = e_illume_border_softkey_get(bd->zone)))
518      {
519         if (!sft->visible) sftsz = 0;
520      }
521    /* set some defaults */
522    ny = (bd->zone->y + indsz);
523    nh = ((bd->zone->h - indsz - sftsz) / 2);
524
525    /* see if there are any other home windows */
526    home = e_illume_border_home_get(bd->zone);
527    if (home) 
528      {
529         if (bd != home) ny = (home->y + nh);
530      }
531
532    /* make sure it's the required width & height */
533    if ((bd->w != bd->zone->w) || (bd->h != nh)) 
534      _policy_border_resize(bd, bd->zone->w, nh);
535
536    /* move to correct position (relative to zone) if needed */
537    if ((bd->x != bd->zone->x) || (bd->y != ny)) 
538      _policy_border_move(bd, bd->zone->x, ny);
539
540    /* set layer if needed */
541    if (bd->layer != POL_HOME_LAYER) e_border_layer_set(bd, POL_HOME_LAYER);
542 }
543
544 static void 
545 _policy_zone_layout_home_dual_custom(E_Border *bd, E_Illume_Config_Zone *cz) 
546 {
547    E_Border *home;
548    int iy, ny, nh;
549
550 //   printf("\tLayout Home Dual Custom: %s\n", bd->client.icccm.class);
551
552    if ((!bd) || (!cz)) return;
553
554    /* no point in adjusting size or position if it's not visible */
555    if (!bd->visible) return;
556
557    /* grab indicator position */
558    e_illume_border_indicator_pos_get(bd->zone, NULL, &iy);
559
560    /* set some defaults */
561    ny = bd->zone->y;
562    nh = iy;
563
564    /* see if there are any other home windows */
565    home = e_illume_border_home_get(bd->zone);
566    if ((home) && (bd != home))
567      {
568         ny = (iy + cz->indicator.size);
569         nh = ((bd->zone->y + bd->zone->h) - ny - cz->softkey.size);
570      }
571
572    /* make sure it's the required width & height */
573    if ((bd->w != bd->zone->w) || (bd->h != nh)) 
574      _policy_border_resize(bd, bd->zone->w, nh);
575
576    /* move to correct position (relative to zone) if needed */
577    if ((bd->x != bd->zone->x) || (bd->y != ny))
578      _policy_border_move(bd, bd->zone->x, ny);
579
580    /* set layer if needed */
581    if (bd->layer != POL_HOME_LAYER) e_border_layer_set(bd, POL_HOME_LAYER);
582 }
583
584 static void 
585 _policy_zone_layout_home_dual_left(E_Border *bd, E_Illume_Config_Zone *cz) 
586 {
587    E_Border *home;
588    int nx, nw, nh;
589
590 //   printf("\tLayout Home Dual Left: %s\n", bd->client.icccm.class);
591
592    if ((!bd) || (!cz)) return;
593
594    /* no point in adjusting size or position if it's not visible */
595    if (!bd->visible) return;
596
597    nh = (bd->zone->h - cz->indicator.size - cz->softkey.size);
598
599    /* set some defaults */
600    nx = bd->zone->x;
601    nw = (bd->zone->w / 2);
602
603    /* see if there are any other home windows */
604    home = e_illume_border_home_get(bd->zone);
605    if ((home) && (bd != home)) nx = (home->x + nw);
606
607    /* make sure it's the required width & height */
608    if ((bd->w != nw) || (bd->h != nh))
609      _policy_border_resize(bd, nw, nh);
610
611    /* move to correct position (relative to zone) if needed */
612    if ((bd->x != nx) || (bd->y != (bd->zone->y + cz->indicator.size)))
613      _policy_border_move(bd, nx, (bd->zone->y + cz->indicator.size));
614
615    /* set layer if needed */
616    if (bd->layer != POL_HOME_LAYER) e_border_layer_set(bd, POL_HOME_LAYER);
617 }
618
619 static void 
620 _policy_zone_layout_fullscreen(E_Border *bd) 
621 {
622    int kh;
623
624    printf("\tLayout Fullscreen: %s\n", bd->client.icccm.name);
625
626    if (!bd) return;
627
628    /* grab keyboard safe region */
629    e_illume_keyboard_safe_app_region_get(bd->zone, NULL, NULL, NULL, &kh);
630
631    /* make sure it's the required width & height */
632    if ((bd->w != bd->zone->w) || (bd->h != kh))
633      _policy_border_resize(bd, bd->zone->w, kh);
634
635    /* set layer if needed */
636    if (bd->layer != POL_FULLSCREEN_LAYER) 
637      e_border_layer_set(bd, POL_FULLSCREEN_LAYER);
638 }
639
640 static void 
641 _policy_zone_layout_app_single(E_Border *bd, E_Illume_Config_Zone *cz) 
642 {
643    int ky, kh, ny, nh;
644
645    if ((!bd) || (!cz)) return;
646    if ((!bd->new_client) && (!bd->visible)) return;
647
648 //   printf("\tLayout App Single: %s\n", bd->client.icccm.name);
649
650    /* grab keyboard safe region */
651    e_illume_keyboard_safe_app_region_get(bd->zone, NULL, &ky, NULL, &kh);
652
653    /* make sure it's the required width & height */
654    if (kh >= bd->zone->h)
655      nh = (kh - cz->indicator.size - cz->softkey.size);
656    else
657      nh = (kh - cz->indicator.size);
658
659    /* resize if needed */
660    if ((bd->w != bd->zone->w) || (bd->h != nh))
661      _policy_border_resize(bd, bd->zone->w, nh);
662
663    /* move to correct position (relative to zone) if needed */
664    ny = (bd->zone->y + cz->indicator.size);
665    if ((bd->x != bd->zone->x) || (bd->y != ny)) 
666      _policy_border_move(bd, bd->zone->x, ny);
667
668    /* set layer if needed */
669    if (bd->layer != POL_APP_LAYER) e_border_layer_set(bd, POL_APP_LAYER);
670 }
671
672 static void 
673 _policy_zone_layout_app_dual_top(E_Border *bd, E_Illume_Config_Zone *cz) 
674 {
675    E_Border *b;
676    int kh, ny, nh;
677
678 //   printf("\tLayout App Dual Top: %s\n", bd->client.icccm.name);
679
680    if ((!bd) || (!cz)) return;
681    if ((!bd->new_client) && (!bd->visible)) return;
682
683    /* set a default Y position */
684    ny = (bd->zone->y + cz->indicator.size);
685
686    if ((bd->focused) && 
687        (bd->client.vkbd.state > ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)) 
688      {
689         /* grab keyboard safe region */
690         e_illume_keyboard_safe_app_region_get(bd->zone, NULL, NULL, NULL, &kh);
691         nh = (kh - cz->indicator.size);
692      }
693    else 
694      {
695         /* make sure it's the required width & height */
696         nh = ((bd->zone->h - cz->indicator.size - cz->softkey.size) / 2);
697      }
698
699    /* see if there is a border already there. if so, check placement based on 
700     * virtual keyboard usage */
701    b = e_illume_border_at_xy_get(bd->zone, bd->zone->x, ny);
702    if ((b) && (b != bd))
703      {
704         /* does this border need keyboard ? */
705         if ((bd->focused) && 
706             (bd->client.vkbd.state > ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)) 
707           {
708              int h;
709
710              /* move existing border to bottom if needed */
711              h = ((bd->zone->h - cz->indicator.size - cz->softkey.size) / 2);
712              if ((b->x != b->zone->x) || (b->y != (ny + h)))
713                _policy_border_move(b, b->zone->x, (ny + h));
714
715              /* resize existing border if needed */
716              if ((b->w != b->zone->w) || (b->h != h))
717                _policy_border_resize(b, b->zone->w, h);
718           }
719         else
720           ny = b->y + nh;
721      }
722
723    /* resize if needed */
724    if ((bd->w != bd->zone->w) || (bd->h != nh))
725      _policy_border_resize(bd, bd->zone->w, nh);
726
727    /* move to correct position (relative to zone) if needed */
728    if ((bd->x != bd->zone->x) || (bd->y != ny)) 
729      _policy_border_move(bd, bd->zone->x, ny);
730
731    /* set layer if needed */
732    if (bd->layer != POL_APP_LAYER) e_border_layer_set(bd, POL_APP_LAYER);
733 }
734
735 static void 
736 _policy_zone_layout_app_dual_custom(E_Border *bd, E_Illume_Config_Zone *cz) 
737 {
738    E_Border *app;
739    int iy, ny, nh;
740
741 //   printf("\tLayout App Dual Custom: %s\n", bd->client.icccm.class);
742
743    if ((!bd) || (!cz)) return;
744    if ((!bd->new_client) && (!bd->visible)) return;
745
746    /* grab indicator position */
747    e_illume_border_indicator_pos_get(bd->zone, NULL, &iy);
748
749    /* set a default position */
750    ny = bd->zone->y;
751    nh = iy;
752
753    app = e_illume_border_at_xy_get(bd->zone, bd->zone->x, bd->zone->y);
754    if ((app) && (bd != app))
755      {
756         ny = (iy + cz->indicator.size);
757         nh = ((bd->zone->y + bd->zone->h) - ny - cz->softkey.size);
758      }
759
760    /* make sure it's the required width & height */
761    if ((bd->w != bd->zone->w) || (bd->h != nh)) 
762      _policy_border_resize(bd, bd->zone->w, nh);
763
764    /* move to correct position (relative to zone) if needed */
765    if ((bd->x != bd->zone->x) || (bd->y != ny))
766      _policy_border_move(bd, bd->zone->x, ny);
767
768    /* set layer if needed */
769    if (bd->layer != POL_APP_LAYER) e_border_layer_set(bd, POL_APP_LAYER);
770 }
771
772 static void 
773 _policy_zone_layout_app_dual_left(E_Border *bd, E_Illume_Config_Zone *cz) 
774 {
775    E_Border *b;
776    int ky, kh, nx, nw;
777
778 //   printf("\tLayout App Dual Left: %s\n", bd->client.icccm.name);
779
780    if ((!bd) || (!cz)) return;
781    if ((!bd->new_client) && (!bd->visible)) return;
782
783    /* grab keyboard safe region */
784    e_illume_keyboard_safe_app_region_get(bd->zone, NULL, &ky, NULL, &kh);
785
786    if (kh >= bd->zone->h)
787      kh = (kh - cz->indicator.size - cz->softkey.size);
788    else
789      kh = (kh - cz->indicator.size);
790
791    /* set some defaults */
792    nx = bd->zone->x;
793    nw = (bd->zone->w / 2);
794
795    /* see if there is a border already there. if so, place at right */
796    b = e_illume_border_at_xy_get(bd->zone, nx, (ky + cz->indicator.size));
797    if ((b) && (bd != b)) nx = b->x + nw;
798
799    /* resize if needed */
800    if ((bd->w != nw) || (bd->h != kh))
801      _policy_border_resize(bd, nw, kh);
802
803    /* move to correct position (relative to zone) if needed */
804    if ((bd->x != nx) || (bd->y != (ky + cz->indicator.size)))
805      _policy_border_move(bd, nx, (ky + cz->indicator.size));
806
807    /* set layer if needed */
808    if (bd->layer != POL_APP_LAYER) e_border_layer_set(bd, POL_APP_LAYER);
809 }
810
811 static void 
812 _policy_zone_layout_dialog(E_Border *bd, E_Illume_Config_Zone *cz) 
813 {
814    E_Border *parent;
815    int mw, mh, nx, ny;
816
817 //   printf("\tLayout Dialog: %s\n", bd->client.icccm.name);
818
819    /* NB: This policy ignores any ICCCM requested positions and centers the 
820     * dialog on it's parent (if it exists) or on the zone */
821
822    if ((!bd) || (!cz)) return;
823
824    mw = bd->w;
825    mh = bd->h;
826
827    /* make sure it fits in this zone */
828    if (mw > bd->zone->w) mw = bd->zone->w;
829    if (mh > bd->zone->h) mh = bd->zone->h;
830
831    /* try to get this dialog's parent if it exists */
832    parent = e_illume_border_parent_get(bd);
833
834    /* if we have no parent, or we are in dual mode, then center on zone */
835    /* NB: we check dual mode because if we are in dual mode, dialogs tend to 
836     * be too small to be useful when positioned on the parent, so center 
837     * on zone. We could check their size first here tho */
838    if ((!parent) || (cz->mode.dual == 1)) 
839      {
840         /* no parent or dual mode, center on screen */
841         nx = (bd->zone->x + ((bd->zone->w - mw) / 2));
842         ny = (bd->zone->y + ((bd->zone->h - mh) / 2));
843      }
844    else 
845      {
846         /* NB: there is an assumption here that the parent has already been 
847          * laid out on screen. This could be bad. Needs Testing */
848
849         /* make sure we are not larger than the parent window */
850         if (mw > parent->w) mw = parent->w;
851         if (mh > parent->h) mh = parent->h;
852
853         /* center on parent */
854         nx = (parent->x + ((parent->w - mw) / 2));
855         ny = (parent->y + ((parent->h - mh) / 2));
856      }
857
858    /* make sure it's the required width & height */
859    if ((bd->w != mw) || (bd->h != mh))
860      _policy_border_resize(bd, mw, mh);
861
862    /* make sure it's in the correct position */
863    if ((bd->x != nx) || (bd->y != ny)) 
864      _policy_border_move(bd, nx, ny);
865
866    /* set layer if needed */
867    if (bd->layer != POL_DIALOG_LAYER) 
868      e_border_layer_set(bd, POL_DIALOG_LAYER);
869 }
870
871 static void 
872 _policy_zone_layout_splash(E_Border *bd, E_Illume_Config_Zone *cz) 
873 {
874    E_Border *parent = NULL;
875    int mw, mh, nx, ny;
876
877    /* NB: This code is almost exactly the same as the dialog layout code 
878     * (_policy_zone_layout_dialog) except for setting a different layer */
879
880 //   printf("\tLayout Splash: %s\n", bd->client.icccm.name);
881
882    /* NB: This policy ignores any ICCCM requested positions and centers the 
883     * splash screen on it's parent (if it exists) or on the zone */
884
885    if ((!bd) || (!cz)) return;
886
887    /* no point in adjusting size or position if it's not visible */
888    if (!bd->visible) return;
889
890    /* grab minimum size */
891    e_illume_border_min_get(bd, &mw, &mh);
892
893    /* make sure it fits in this zone */
894    if (mw > bd->zone->w) mw = bd->zone->w;
895    if (mh > bd->zone->h) mh = bd->zone->h;
896
897    /* if we have no parent, or we are in dual mode, then center on zone */
898    /* NB: we check dual mode because if we are in dual mode, dialogs tend to 
899     * be too small to be useful when positioned on the parent, 
900     * so center on zone instead */
901    if ((!parent) || (cz->mode.dual == 1)) 
902      {
903         /* no parent or in dual mode, center on screen */
904         nx = (bd->zone->x + ((bd->zone->w - mw) / 2));
905         ny = (bd->zone->y + ((bd->zone->h - mh) / 2));
906      }
907    else 
908      {
909         /* NB: there is an assumption here that the parent has already been 
910          * laid out on screen. This could be bad. Needs Testing */
911
912         /* make sure we are not larger than the parent window */
913         if (mw > parent->w) mw = parent->w;
914         if (mh > parent->h) mh = parent->h;
915
916         /* center on parent */
917         nx = (parent->x + ((parent->w - mw) / 2));
918         ny = (parent->y + ((parent->h - mh) / 2));
919      }
920
921    /* make sure it's the required width & height */
922    if ((bd->w != mw) || (bd->h != mh))
923      _policy_border_resize(bd, mw, mh);
924
925    /* make sure it's in the correct position */
926    if ((bd->x != nx) || (bd->y != ny)) 
927      _policy_border_move(bd, nx, ny);
928
929    /* set layer if needed */
930    if (bd->layer != POL_SPLASH_LAYER) e_border_layer_set(bd, POL_SPLASH_LAYER);
931 }
932
933 static void 
934 _policy_zone_layout_conformant_single(E_Border *bd, E_Illume_Config_Zone *cz) 
935 {
936    if ((!bd) || (!cz)) return;
937    if ((!bd->new_client) && (!bd->visible)) return;
938
939    /* make sure it's the required width & height */
940    if ((bd->w != bd->zone->w) || (bd->h != bd->zone->h))
941      _policy_border_resize(bd, bd->zone->w, bd->zone->h);
942
943    /* move to correct position (relative to zone) if needed */
944    if ((bd->x != bd->zone->x) || (bd->y != bd->zone->y))
945      _policy_border_move(bd, bd->zone->x, bd->zone->y);
946
947    /* set layer if needed */
948    if (bd->layer != POL_CONFORMANT_LAYER) 
949      e_border_layer_set(bd, POL_CONFORMANT_LAYER);
950 }
951
952 static void 
953 _policy_zone_layout_conformant_dual_top(E_Border *bd, E_Illume_Config_Zone *cz) 
954 {
955    int nh, ny;
956
957    /* according to the docs I have, conformant windows are always on the 
958     * bottom in dual-top mode */
959    if ((!bd) || (!cz)) return;
960    if ((!bd->new_client) && (!bd->visible)) return;
961
962    /* set some defaults */
963    nh = ((bd->zone->h - cz->indicator.size - cz->softkey.size) / 2);
964    ny = (bd->zone->y + cz->indicator.size) + nh;
965    nh += cz->softkey.size;
966
967    /* make sure it's the required width & height */
968    if ((bd->w != bd->zone->w) || (bd->h != nh))
969      _policy_border_resize(bd, bd->zone->w, nh);
970
971    /* move to correct position (relative to zone) if needed */
972    if ((bd->x != bd->zone->x) || (bd->y != ny))
973      _policy_border_move(bd, bd->zone->x, ny);
974
975    /* set layer if needed */
976    if (bd->layer != POL_CONFORMANT_LAYER) 
977      e_border_layer_set(bd, POL_CONFORMANT_LAYER);
978 }
979
980 static void 
981 _policy_zone_layout_conformant_dual_custom(E_Border *bd, E_Illume_Config_Zone *cz) 
982 {
983    int iy, nh;
984
985 //   printf("\tLayout Conformant Dual Custom: %s\n", bd->client.icccm.class);
986
987    if ((!bd) || (!cz)) return;
988    if ((!bd->new_client) && (!bd->visible)) return;
989
990    /* grab indicator position */
991    e_illume_border_indicator_pos_get(bd->zone, NULL, &iy);
992
993    /* set some defaults */
994    nh = ((bd->zone->y + bd->zone->h) - iy);
995
996    /* make sure it's the required width & height */
997    if ((bd->w != bd->zone->w) || (bd->h != nh)) 
998      _policy_border_resize(bd, bd->zone->w, nh);
999
1000    /* move to correct position (relative to zone) if needed */
1001    if ((bd->x != bd->zone->x) || (bd->y != iy))
1002      _policy_border_move(bd, bd->zone->x, iy);
1003
1004    /* set layer if needed */
1005    if (bd->layer != POL_CONFORMANT_LAYER) 
1006      e_border_layer_set(bd, POL_CONFORMANT_LAYER);
1007 }
1008
1009 static void 
1010 _policy_zone_layout_conformant_dual_left(E_Border *bd, E_Illume_Config_Zone *cz) 
1011 {
1012    int nw, nx;
1013
1014    /* according to the docs I have, conformant windows are always on the 
1015     * left in dual-left mode */
1016    if ((!bd) || (!cz)) return;
1017    if ((!bd->new_client) && (!bd->visible)) return;
1018
1019    /* set some defaults */
1020    nw = (bd->zone->w / 2);
1021    nx = (bd->zone->x);
1022
1023    /* make sure it's the required width & height */
1024    if ((bd->w != nw) || (bd->h != bd->zone->h))
1025      _policy_border_resize(bd, nw, bd->zone->h);
1026
1027    /* move to correct position (relative to zone) if needed */
1028    if ((bd->x != nx) || (bd->y != bd->zone->y))
1029      _policy_border_move(bd, nx, bd->zone->y);
1030
1031    /* set layer if needed */
1032    if (bd->layer != POL_CONFORMANT_LAYER) 
1033      e_border_layer_set(bd, POL_CONFORMANT_LAYER);
1034 }
1035
1036
1037 /* policy functions */
1038 void 
1039 _policy_border_add(E_Border *bd) 
1040 {
1041 //   printf("Border added: %s\n", bd->client.icccm.class);
1042
1043    if (!bd) return;
1044
1045    /* NB: this call sets an atom on the window that specifices the zone.
1046     * the logic here is that any new windows created can access the zone 
1047     * window by a 'get' call. This is useful for elementary apps as they 
1048     * normally would not have access to the zone window. Typical use case 
1049     * is for indicator & softkey windows so that they can send messages 
1050     * that apply to their respective zone only. Example: softkey sends close 
1051     * messages (or back messages to cycle focus) that should pertain just 
1052     * to it's current zone */
1053    ecore_x_e_illume_zone_set(bd->client.win, bd->zone->black_win);
1054
1055    /* ignore stolen borders. These are typically quickpanel or keyboards */
1056    if (bd->stolen) return;
1057
1058    /* if this is a fullscreen window, than we need to hide indicator window */
1059    /* NB: we could use the e_illume_border_is_fullscreen function here 
1060     * but we save ourselves a function call this way */
1061    if ((bd->fullscreen) || (bd->need_fullscreen)) 
1062      {
1063         E_Border *ind, *sft;
1064
1065         /* try to get the Indicator on this zone */
1066         if ((ind = e_illume_border_indicator_get(bd->zone))) 
1067           {
1068              /* we have the indicator, hide it if needed */
1069              if (ind->visible) e_illume_border_hide(ind);
1070           }
1071         /* conformant - may not need softkey */
1072         if ((sft = e_illume_border_softkey_get(bd->zone)))
1073           {
1074              if (e_illume_border_is_conformant(bd)) 
1075                {
1076                   if (sft->visible) e_illume_border_hide(sft);
1077                }
1078              else 
1079                {
1080                   if (!sft->visible) e_illume_border_show(sft);
1081                }
1082           }
1083      }
1084
1085    /* Add this border to our focus stack if it can accept or take focus */
1086    if ((bd->client.icccm.accepts_focus) || (bd->client.icccm.take_focus)) 
1087      _pol_focus_stack = eina_list_append(_pol_focus_stack, bd);
1088
1089    if ((e_illume_border_is_softkey(bd)) || (e_illume_border_is_indicator(bd)))
1090      _policy_zone_layout_update(bd->zone);
1091    else 
1092      {
1093         /* set focus on new border if we can */
1094         _policy_border_set_focus(bd);
1095      }
1096 }
1097
1098 void 
1099 _policy_border_del(E_Border *bd) 
1100 {
1101 //   printf("Border deleted: %s\n", bd->client.icccm.class);
1102
1103    if (!bd) return;
1104
1105    /* if this is a fullscreen window, than we need to show indicator window */
1106    /* NB: we could use the e_illume_border_is_fullscreen function here 
1107     * but we save ourselves a function call this way */
1108    if ((bd->fullscreen) || (bd->need_fullscreen)) 
1109      {
1110         E_Border *ind;
1111
1112         /* try to get the Indicator on this zone */
1113         if ((ind = e_illume_border_indicator_get(bd->zone))) 
1114           {
1115              /* we have the indicator, show it if needed */
1116              if (!ind->visible) e_illume_border_show(ind);
1117           }
1118         _policy_zone_layout_update(bd->zone);
1119      }
1120
1121    /* remove from our focus stack */
1122    if ((bd->client.icccm.accepts_focus) || (bd->client.icccm.take_focus)) 
1123      _pol_focus_stack = eina_list_remove(_pol_focus_stack, bd);
1124
1125    if (e_illume_border_is_softkey(bd)) 
1126      {
1127         E_Illume_Config_Zone *cz;
1128
1129         /* get the config for this zone */
1130         cz = e_illume_zone_config_get(bd->zone->id);
1131         cz->softkey.size = 0;
1132         _policy_zone_layout_update(bd->zone);
1133      }
1134    else if (e_illume_border_is_indicator(bd)) 
1135      {
1136         E_Illume_Config_Zone *cz;
1137
1138         /* get the config for this zone */
1139         cz = e_illume_zone_config_get(bd->zone->id);
1140         cz->indicator.size = 0;
1141         _policy_zone_layout_update(bd->zone);
1142      }
1143    else 
1144      {
1145         /* show the border below this one */
1146         _policy_border_show_below(bd);
1147      }
1148 }
1149
1150 void 
1151 _policy_border_focus_in(E_Border *bd __UNUSED__) 
1152 {
1153    E_Border *ind;
1154
1155 //   printf("Border focus in: %s\n", bd->client.icccm.name);
1156    if ((bd->fullscreen) || (bd->need_fullscreen)) 
1157      {
1158         /* try to get the Indicator on this zone */
1159         if ((ind = e_illume_border_indicator_get(bd->zone))) 
1160           {
1161              /* we have the indicator, show it if needed */
1162              if (ind->visible) e_illume_border_hide(ind);
1163           }
1164      }
1165    else
1166      {
1167         /* try to get the Indicator on this zone */
1168         if ((ind = e_illume_border_indicator_get(bd->zone))) 
1169           {
1170              /* we have the indicator, show it if needed */
1171              if (!ind->visible) e_illume_border_show(ind);
1172           }
1173      }
1174    _policy_zone_layout_update(bd->zone);
1175 }
1176
1177 void 
1178 _policy_border_focus_out(E_Border *bd) 
1179 {
1180 //   printf("Border focus out: %s\n", bd->client.icccm.name);
1181
1182    if (!bd) return;
1183
1184    /* NB: if we got this focus_out event on a deleted border, we check if 
1185     * it is a transient (child) of another window. If it is, then we 
1186     * transfer focus back to the parent window */
1187    if (e_object_is_del(E_OBJECT(bd))) 
1188      {
1189         if (e_illume_border_is_dialog(bd)) 
1190           {
1191              E_Border *parent;
1192
1193              if ((parent = e_illume_border_parent_get(bd)))
1194                _policy_border_set_focus(parent);
1195           }
1196      }
1197 }
1198
1199 void 
1200 _policy_border_activate(E_Border *bd) 
1201 {
1202    E_Border *sft;
1203
1204 //   printf("Border Activate: %s\n", bd->client.icccm.name);
1205
1206    if (!bd) return;
1207
1208    /* NB: stolen borders may or may not need focus call...have to test */
1209    if (bd->stolen) return;
1210
1211    /* conformant windows hide the softkey */
1212    if ((sft = e_illume_border_softkey_get(bd->zone)))
1213      {
1214         if (e_illume_border_is_conformant(bd)) 
1215           {
1216              if (sft->visible) e_illume_border_hide(sft);
1217           }
1218         else 
1219           {
1220              if (!sft->visible) e_illume_border_show(sft);
1221           }
1222      }
1223
1224    /* NB: We cannot use our set_focus function here because it does, 
1225     * occasionally fall through wrt E's focus policy, so cherry pick the good 
1226     * parts and use here :) */
1227
1228    /* if the border is iconified then uniconify if allowed */
1229    if ((bd->iconic) && (!bd->lock_user_iconify)) 
1230      e_border_uniconify(bd);
1231
1232    /* set very high layer for this window as it needs attention and thus 
1233     * should show above everything */
1234    e_border_layer_set(bd, POL_ACTIVATE_LAYER);
1235
1236    /* if we can raise the border do it */
1237    if (!bd->lock_user_stacking) e_border_raise(bd);
1238
1239    /* focus the border */
1240    e_border_focus_set(bd, 1, 1);
1241
1242    /* NB: since we skip needless border evals when container layout 
1243     * is called (to save cpu cycles), we need to 
1244     * signal this border that it's focused so that the edj gets 
1245     * updated. 
1246     * 
1247     * This is potentially useless as THIS policy 
1248     * makes all windows borderless anyway, but it's in here for 
1249     * completeness
1250    e_border_focus_latest_set(bd);
1251    if (bd->bg_object) 
1252      edje_object_signal_emit(bd->bg_object, "e,state,focused", "e");
1253    if (bd->icon_object) 
1254      edje_object_signal_emit(bd->icon_object, "e,state,focused", "e");
1255    e_focus_event_focus_in(bd);
1256     */
1257 }
1258
1259 void 
1260 _policy_border_post_fetch(E_Border *bd) 
1261 {
1262 //   printf("Border post fetch\n");
1263
1264    if (!bd) return;
1265
1266    /* NB: for this policy we disable all remembers set on a border */
1267    if (bd->remember) e_remember_del(bd->remember);
1268    bd->remember = NULL;
1269
1270    /* set this border to borderless */
1271 #ifdef DIALOG_USES_PIXEL_BORDER
1272    if ((e_illume_border_is_dialog(bd)) && (e_illume_border_parent_get(bd)))
1273      eina_stringshare_replace(&bd->bordername, "pixel");
1274    else
1275      bd->borderless = 1;
1276 #else
1277    bd->borderless = 1;
1278 #endif
1279
1280    /* tell E the border has changed */
1281    bd->client.border.changed = 1;
1282 }
1283
1284 void 
1285 _policy_border_post_assign(E_Border *bd) 
1286 {
1287 //   printf("Border post assign\n");
1288
1289    if (!bd) return;
1290
1291    bd->internal_no_remember = 1;
1292
1293    /* do not allow client to change these properties */
1294    bd->lock_client_size = 1;
1295    bd->lock_client_shade = 1;
1296    bd->lock_client_maximize = 1;
1297    bd->lock_client_location = 1;
1298    bd->lock_client_stacking = 1;
1299
1300    /* do not allow the user to change these properties */
1301    bd->lock_user_location = 1;
1302    bd->lock_user_size = 1;
1303    bd->lock_user_shade = 1;
1304
1305    /* clear any centered states */
1306    /* NB: this is mainly needed for E's main config dialog */
1307    bd->client.e.state.centered = 0;
1308
1309    /* lock the border type so user/client cannot change */
1310    bd->lock_border = 1;
1311 }
1312
1313 void 
1314 _policy_border_show(E_Border *bd) 
1315 {
1316    if (!bd) return;
1317
1318    /* make sure we have a name so that we don't handle windows like E's root */
1319    if (!bd->client.icccm.name) return;
1320
1321 //   printf("Border Show: %s\n", bd->client.icccm.class);
1322
1323    /* trap for special windows so we can ignore hides below them */
1324    if (e_illume_border_is_indicator(bd)) return;
1325    if (e_illume_border_is_softkey(bd)) return;
1326    if (e_illume_border_is_quickpanel(bd)) return;
1327    if (e_illume_border_is_keyboard(bd)) return;
1328
1329    _policy_border_hide_below(bd);
1330 }
1331
1332 void 
1333 _policy_zone_layout(E_Zone *zone) 
1334 {
1335    E_Illume_Config_Zone *cz;
1336    Eina_List *l;
1337    E_Border *bd;
1338
1339    if (!zone) return;
1340
1341 //   printf("Zone Layout: %d\n", zone->id);
1342
1343    /* get the config for this zone */
1344    cz = e_illume_zone_config_get(zone->id);
1345
1346    /* loop through border list and update layout */
1347    EINA_LIST_FOREACH(e_border_client_list(), l, bd) 
1348      {
1349         /* skip borders that are being deleted */
1350         if (e_object_is_del(E_OBJECT(bd))) continue;
1351
1352         /* skip borders not on this zone */
1353         if (bd->zone != zone) continue;
1354
1355         /* only update layout for this border if it really needs it */
1356         if ((!bd->new_client) && (!bd->changes.pos) && (!bd->changes.size) && 
1357             (!bd->changes.visible) && (!bd->pending_move_resize) && 
1358             (!bd->need_shape_export) && (!bd->need_shape_merge)) continue;
1359
1360         /* are we laying out an indicator ? */
1361         if (e_illume_border_is_indicator(bd)) 
1362           _policy_zone_layout_indicator(bd, cz);
1363
1364         /* are we layout out a quickpanel ? */
1365         else if (e_illume_border_is_quickpanel(bd)) 
1366           _policy_zone_layout_quickpanel(bd);
1367
1368         /* are we laying out a softkey ? */
1369         else if (e_illume_border_is_softkey(bd)) 
1370           _policy_zone_layout_softkey(bd, cz);
1371
1372         /* are we laying out a keyboard ? */
1373         else if (e_illume_border_is_keyboard(bd)) 
1374           _policy_zone_layout_keyboard(bd, cz);
1375
1376         /* are we layout out a home window ? */
1377         else if (e_illume_border_is_home(bd)) 
1378           {
1379              if (!cz->mode.dual)
1380                _policy_zone_layout_home_single(bd, cz);
1381              else 
1382                {
1383                   /* we are in dual-mode, check orientation */
1384                   if (cz->mode.side == 0) 
1385                     {
1386                        int ty;
1387
1388                        e_illume_border_indicator_pos_get(bd->zone, NULL, &ty);
1389                        if (ty <= bd->zone->y)
1390                          _policy_zone_layout_home_dual_top(bd, cz);
1391                        else
1392                          _policy_zone_layout_home_dual_custom(bd, cz);
1393                     }
1394                   else 
1395                     _policy_zone_layout_home_dual_left(bd, cz);
1396                }
1397           }
1398
1399         /* are we laying out a fullscreen window ? */
1400         /* NB: we could use the e_illume_border_is_fullscreen function here 
1401          * but we save ourselves a function call this way. */
1402         else if ((bd->fullscreen) || (bd->need_fullscreen)) 
1403           _policy_zone_layout_fullscreen(bd);
1404
1405         /* are we laying out a splash screen ? */
1406         /* NB: we check splash before dialog so if a splash screen does not 
1407          * register as a splash, than the dialog trap should catch it */
1408         else if (e_illume_border_is_splash(bd)) 
1409           _policy_zone_layout_splash(bd, cz);
1410
1411         /* are we laying out a dialog ? */
1412         else if (e_illume_border_is_dialog(bd)) 
1413           _policy_zone_layout_dialog(bd, cz);
1414
1415         /* are we layout out a conformant window ? */
1416         else if (e_illume_border_is_conformant(bd)) 
1417           {
1418              if (!cz->mode.dual)
1419                _policy_zone_layout_conformant_single(bd, cz);
1420              else 
1421                {
1422                   /* we are in dual-mode, check orientation */
1423                   if (cz->mode.side == 0) 
1424                     {
1425                        int ty;
1426
1427                        e_illume_border_indicator_pos_get(bd->zone, NULL, &ty);
1428                        if (ty <= bd->zone->y)
1429                          _policy_zone_layout_conformant_dual_top(bd, cz);
1430                        else
1431                          _policy_zone_layout_conformant_dual_custom(bd, cz);
1432                     }
1433                   else 
1434                     _policy_zone_layout_conformant_dual_left(bd, cz);
1435                }
1436           }
1437
1438         /* must be an app */
1439         else 
1440           {
1441              /* are we in single mode ? */
1442              if (!cz->mode.dual) 
1443                _policy_zone_layout_app_single(bd, cz);
1444              else 
1445                {
1446                   /* we are in dual-mode, check orientation */
1447                   if (cz->mode.side == 0) 
1448                     {
1449                        int ty;
1450
1451                        /* grab the indicator position so we can tell if it 
1452                         * is in a custom position or not (user dragged it) */
1453                        e_illume_border_indicator_pos_get(bd->zone, NULL, &ty);
1454                        if (ty <= bd->zone->y)
1455                          _policy_zone_layout_app_dual_top(bd, cz);
1456                        else
1457                          _policy_zone_layout_app_dual_custom(bd, cz);
1458                     }
1459                   else 
1460                     _policy_zone_layout_app_dual_left(bd, cz);
1461                }
1462           }
1463      }
1464 }
1465
1466 void 
1467 _policy_zone_move_resize(E_Zone *zone) 
1468 {
1469    Eina_List *l;
1470    E_Border *bd;
1471
1472 //   printf("Zone move resize\n");
1473
1474    if (!zone) return;
1475
1476    EINA_LIST_FOREACH(e_border_client_list(), l, bd) 
1477      {
1478         /* skip borders not on this zone */
1479         if (bd->zone != zone) continue;
1480
1481         /* signal a changed pos here so layout gets updated */
1482         bd->changes.pos = 1;
1483         bd->changed = 1;
1484      }
1485 }
1486
1487 void 
1488 _policy_zone_mode_change(E_Zone *zone, Ecore_X_Atom mode) 
1489 {
1490    E_Illume_Config_Zone *cz;
1491    Eina_List *homes = NULL;
1492    E_Border *bd;
1493    int count;
1494
1495 //   printf("Zone mode change: %d\n", zone->id);
1496
1497    if (!zone) return;
1498
1499    /* get the config for this zone */
1500    cz = e_illume_zone_config_get(zone->id);
1501
1502    /* update config with new mode */
1503    if (mode == ECORE_X_ATOM_E_ILLUME_MODE_SINGLE) 
1504      cz->mode.dual = 0;
1505    else 
1506      {
1507         cz->mode.dual = 1;
1508         if (mode == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP) 
1509           cz->mode.side = 0;
1510         else if (mode == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT) 
1511           cz->mode.side = 1;
1512      }
1513    e_config_save_queue();
1514
1515    /* lock indicator window from dragging if we need to */
1516    bd = e_illume_border_indicator_get(zone);
1517    if (bd) 
1518      {
1519         /* only dual-top mode can drag */
1520         if ((cz->mode.dual == 1) && (cz->mode.side == 0))
1521           {
1522              /* only set locked if we need to */
1523              if (bd->client.illume.drag.locked != 0) 
1524                ecore_x_e_illume_drag_locked_set(bd->client.win, 0);
1525           }
1526         else
1527           {
1528              /* only set locked if we need to */
1529              if (bd->client.illume.drag.locked != 1) 
1530              ecore_x_e_illume_drag_locked_set(bd->client.win, 1);
1531           }
1532      }
1533
1534    if (!(homes = e_illume_border_home_borders_get(zone))) return;
1535
1536    count = eina_list_count(homes);
1537
1538    /* create a new home window (if needed) for dual mode */
1539    if (cz->mode.dual == 1) 
1540      {
1541         if (count < 2)
1542           ecore_x_e_illume_home_new_send(zone->black_win);
1543      }
1544    else if (cz->mode.dual == 0) 
1545      {
1546         /* if we went to single mode, delete any extra home windows */
1547         if (count >= 2) 
1548           {
1549              E_Border *home;
1550
1551              /* try to get a home window on this zone and remove it */
1552              if ((home = e_illume_border_home_get(zone)))
1553                ecore_x_e_illume_home_del_send(home->client.win);
1554           }
1555      }
1556
1557    /* Need to trigger a layout update here */
1558    _policy_zone_layout_update(zone);
1559 }
1560
1561 void 
1562 _policy_zone_close(E_Zone *zone) 
1563 {
1564    E_Border *bd;
1565
1566 //   printf("Zone close\n");
1567
1568    if (!zone) return;
1569
1570    /* make sure we have a focused border */
1571    if (!(bd = e_border_focused_get())) return;
1572
1573    /* make sure focused border is on this zone */
1574    if (bd->zone != zone) return;
1575
1576    /* close this border */
1577    e_border_act_close_begin(bd);
1578 }
1579
1580 void 
1581 _policy_drag_start(E_Border *bd) 
1582 {
1583 //   printf("Drag start\n");
1584
1585    if (!bd) return;
1586
1587    /* ignore stolen borders */
1588    if (bd->stolen) return;
1589
1590    /* set property on this border to say we are dragging */
1591    ecore_x_e_illume_drag_set(bd->client.win, 1);
1592
1593    /* set property on zone window that a drag is happening */
1594    ecore_x_e_illume_drag_set(bd->zone->black_win, 1);
1595 }
1596
1597 void 
1598 _policy_drag_end(E_Border *bd) 
1599 {
1600 //   printf("Drag end\n");
1601
1602    if (!bd) return;
1603
1604    /* ignore stolen borders */
1605    if (bd->stolen) return;
1606
1607    /* set property on this border to say we are done dragging */
1608    ecore_x_e_illume_drag_set(bd->client.win, 0);
1609
1610    /* set property on zone window that a drag is finished */
1611    ecore_x_e_illume_drag_set(bd->zone->black_win, 0);
1612 }
1613
1614 void 
1615 _policy_focus_back(E_Zone *zone) 
1616 {
1617    Eina_List *l, *fl = NULL;
1618    E_Border *bd, *fbd;
1619
1620    if (!zone) return;
1621    if (eina_list_count(_pol_focus_stack) < 1) return;
1622
1623 //   printf("Focus back\n");
1624
1625    EINA_LIST_REVERSE_FOREACH(_pol_focus_stack, l, bd) 
1626      {
1627         if (bd->zone != zone) continue;
1628         fl = eina_list_append(fl, bd);
1629      }
1630
1631    if (!(fbd = e_border_focused_get())) return;
1632    if (fbd->parent) return;
1633
1634    EINA_LIST_REVERSE_FOREACH(fl, l, bd) 
1635      {
1636         if ((fbd) && (bd == fbd))
1637           {
1638              E_Border *b;
1639
1640              if ((l->next) && (b = l->next->data)) 
1641                {
1642                   _policy_border_set_focus(b);
1643                   break;
1644                }
1645              else 
1646                {
1647                   /* we've reached the end of the list. Set focus to first */
1648                   if ((b = eina_list_nth(fl, 0))) 
1649                     {
1650                        _policy_border_set_focus(b);
1651                        break;
1652                     }
1653                }
1654           }
1655      }
1656    eina_list_free(fl);
1657 }
1658
1659 void 
1660 _policy_focus_forward(E_Zone *zone) 
1661 {
1662    Eina_List *l, *fl = NULL;
1663    E_Border *bd, *fbd;
1664
1665    if (!zone) return;
1666    if (eina_list_count(_pol_focus_stack) < 1) return;
1667
1668    //   printf("Focus forward\n");
1669
1670    EINA_LIST_FOREACH(_pol_focus_stack, l, bd) 
1671      {
1672         if (bd->zone != zone) continue;
1673         fl = eina_list_append(fl, bd);
1674      }
1675
1676    if (!(fbd = e_border_focused_get())) return;
1677    if (fbd->parent) return;
1678
1679    EINA_LIST_FOREACH(fl, l, bd) 
1680      {
1681         if ((fbd) && (bd == fbd))
1682           {
1683              E_Border *b;
1684
1685              if ((l->next) && (b = l->next->data)) 
1686                {
1687                   _policy_border_set_focus(b);
1688                   break;
1689                }
1690              else 
1691                {
1692                   /* we've reached the end of the list. Set focus to first */
1693                   if ((b = eina_list_nth(fl, 0))) 
1694                     {
1695                        _policy_border_set_focus(b);
1696                        break;
1697                     }
1698                }
1699           }
1700      }
1701    eina_list_free(fl);
1702 }
1703
1704 void 
1705 _policy_focus_home(E_Zone *zone) 
1706 {
1707    E_Border *bd;
1708
1709    if (!zone) return;
1710    if (!(bd = e_illume_border_home_get(zone))) return;
1711    _policy_border_set_focus(bd);
1712 }
1713
1714 void 
1715 _policy_property_change(Ecore_X_Event_Window_Property *event) 
1716 {
1717 //   printf("Property Change\n");
1718
1719    /* we are interested in state changes here */
1720    if (event->atom == ECORE_X_ATOM_NET_WM_STATE) 
1721      {
1722         E_Border *bd, *ind;
1723
1724         if (!(bd = e_border_find_by_client_window(event->win))) return;
1725
1726         /* not interested in stolen or invisible borders */
1727         if ((bd->stolen) || (!bd->visible)) return;
1728
1729         /* make sure the border has a name or class */
1730         /* NB: this check is here because some E borders get State Changes 
1731          * but do not have a name/class associated with them. Not entirely sure 
1732          * which ones they are, but I would guess Managers, Containers, or Zones.
1733          * At any rate, we're not interested in those types of borders */
1734         if ((!bd->client.icccm.name) || (!bd->client.icccm.class)) return;
1735
1736         /* NB: If we have reached this point, then it should be a fullscreen 
1737          * border that has toggled fullscreen on/off */
1738
1739         /* try to get the Indicator on this zone */
1740         if (!(ind = e_illume_border_indicator_get(bd->zone))) return;
1741
1742         /* if we are fullscreen, hide the indicator...else we show it */
1743         /* NB: we could use the e_illume_border_is_fullscreen function here 
1744          * but we save ourselves a function call this way */
1745         if ((bd->fullscreen) || (bd->need_fullscreen)) 
1746           {
1747              if (ind->visible)
1748                {
1749                   e_illume_border_hide(ind);
1750                   _policy_zone_layout_update(bd->zone);
1751                }
1752           }
1753         else 
1754           {
1755              if (!ind->visible)
1756                {
1757                   e_illume_border_show(ind);
1758                   _policy_zone_layout_update(bd->zone);
1759                }
1760           }
1761      }
1762    else if (event->atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY) 
1763      {
1764         Eina_List *l;
1765         E_Zone *zone;
1766         E_Border *bd;
1767         int x, y, w, h;
1768
1769         /* make sure this property changed on a zone */
1770         if (!(zone = e_util_zone_window_find(event->win))) return;
1771
1772         /* get the geometry */
1773         if (!(bd = e_illume_border_indicator_get(zone))) return;
1774         x = bd->x;
1775         y = bd->y;
1776         w = bd->w;
1777         h = bd->h;
1778
1779         /* look for conformant borders */
1780         EINA_LIST_FOREACH(e_border_client_list(), l, bd) 
1781           {
1782              if (bd->zone != zone) continue;
1783              if (!e_illume_border_is_conformant(bd)) continue;
1784              /* set indicator geometry on conformant window */
1785              /* NB: This is needed so that conformant apps get told about 
1786               * the indicator size/position...else they have no way of 
1787               * knowing that the geometry has been updated */
1788              ecore_x_e_illume_indicator_geometry_set(bd->client.win, x, y, w, h);
1789           }
1790      }
1791    else if (event->atom == ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY) 
1792      {
1793         Eina_List *l;
1794         E_Zone *zone;
1795         E_Border *bd;
1796         int x, y, w, h;
1797
1798         /* make sure this property changed on a zone */
1799         if (!(zone = e_util_zone_window_find(event->win))) return;
1800
1801         if (!(bd = e_illume_border_softkey_get(zone))) return;
1802         x = bd->x;
1803         y = bd->y;
1804         w = bd->w;
1805         h = bd->h;
1806
1807         /* look for conformant borders */
1808         EINA_LIST_FOREACH(e_border_client_list(), l, bd) 
1809           {
1810              if (bd->zone != zone) continue;
1811              if (!e_illume_border_is_conformant(bd)) continue;
1812              /* set softkey geometry on conformant window */
1813              /* NB: This is needed so that conformant apps get told about 
1814               * the softkey size/position...else they have no way of 
1815               * knowing that the geometry has been updated */
1816              ecore_x_e_illume_softkey_geometry_set(bd->client.win, x, y, w, h);
1817           }
1818      }
1819    else if (event->atom == ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY) 
1820      {
1821         Eina_List *l;
1822         E_Zone *zone;
1823         E_Illume_Keyboard *kbd;
1824         E_Border *bd;
1825         int x, y, w, h;
1826
1827         /* make sure this property changed on a zone */
1828         if (!(zone = e_util_zone_window_find(event->win))) return;
1829
1830         /* get the keyboard */
1831         if (!(kbd = e_illume_keyboard_get())) return;
1832         if (!kbd->border) return;
1833
1834         /* get the geometry */
1835         x = kbd->border->x;
1836         w = kbd->border->w;
1837         h = kbd->border->h;
1838
1839         /* adjust Y for keyboard visibility because keyboard uses fx_offset */
1840         y = 0;
1841         if (kbd->border->fx.y <= 0) y = kbd->border->y;
1842
1843         /* look for conformant borders */
1844         EINA_LIST_FOREACH(e_border_client_list(), l, bd) 
1845           {
1846              if (bd->zone != zone) continue;
1847              if (!e_illume_border_is_conformant(bd)) continue;
1848              /* set keyboard geometry on conformant window */
1849              /* NB: This is needed so that conformant apps get told about 
1850               * the keyboard size/position...else they have no way of 
1851               * knowing that the geometry has been updated */
1852              ecore_x_e_illume_keyboard_geometry_set(bd->client.win, x, y, w, h);
1853           }
1854      }
1855    else if (event->atom == ATM_ENLIGHTENMENT_SCALE)
1856      {
1857         Eina_List *ml;
1858         E_Manager *man;
1859
1860         EINA_LIST_FOREACH(e_manager_list(), ml, man) 
1861           {
1862              Eina_List *cl;
1863              E_Container *con;
1864
1865              if (event->win != man->root) continue;
1866              EINA_LIST_FOREACH(man->containers, cl, con) 
1867                {
1868                   Eina_List *zl;
1869                   E_Zone *zone;
1870
1871                   EINA_LIST_FOREACH(con->zones, zl, zone) 
1872                     _policy_zone_layout_update(zone);
1873                }
1874           }
1875      }
1876 }