fe6f0b9063fbd69e5ec8d3d52beb8b76efe50bd3
[framework/uifw/e17.git] / src / modules / everything / evry_plug_windows.c
1 #include "e.h"
2 #include "evry_api.h"
3
4 #define BORDER_SHOW             1
5 #define BORDER_HIDE             2
6 #define BORDER_FULLSCREEN       3
7 #define BORDER_TODESK           4
8 #define BORDER_CLOSE            5
9
10 typedef struct _Plugin Plugin;
11 typedef struct _Border_Item Border_Item;
12
13 struct _Plugin
14 {
15   Evry_Plugin base;
16   Eina_List *borders;
17   Eina_List *handlers;
18   const char *input;
19 };
20
21 struct _Border_Item
22 {
23   Evry_Item base;
24   E_Border *border;
25 };
26
27 #define GET_BORDER(_bd, _it) Border_Item *_bd = (Border_Item *)_it;
28
29 static const Evry_API *evry = NULL;
30 static Evry_Module *evry_module = NULL;
31 static Evry_Plugin *_plug;
32 static Eina_List *_actions = NULL;
33
34 static Evas_Object *_icon_get(Evry_Item *it, Evas *e);
35
36 /***************************************************************************/
37
38 static void
39 _border_item_free(Evry_Item *it)
40 {
41    GET_BORDER(bi, it);
42
43    e_object_unref(E_OBJECT(bi->border));
44
45    E_FREE(bi);
46 }
47
48 static int
49 _border_item_add(Plugin *p, E_Border *bd)
50 {
51    Border_Item *bi;
52    char buf[1024];
53
54    if (bd->client.netwm.state.skip_taskbar)
55      return 0;
56    if (bd->client.netwm.state.skip_pager)
57      return 0;
58
59    bi = EVRY_ITEM_NEW(Border_Item, p, e_border_name_get(bd), _icon_get, _border_item_free);
60    snprintf(buf, sizeof(buf), "%d:%d %s",
61             bd->desk->x, bd->desk->y,
62             (bd->desktop ? bd->desktop->name : ""));
63    EVRY_ITEM_DETAIL_SET(bi, buf);
64
65    bi->border = bd;
66    e_object_ref(E_OBJECT(bd));
67
68    p->borders = eina_list_append(p->borders, bi);
69
70    return 1;
71 }
72
73 static Eina_Bool
74 _cb_border_remove(void *data, __UNUSED__ int type,  void *event)
75 {
76    E_Event_Border_Remove *ev = event;
77    Border_Item *bi;
78    Eina_List *l;
79    Plugin *p = data;
80
81    EINA_LIST_FOREACH(p->borders, l, bi)
82      if (bi->border == ev->border)
83        break;
84
85    if (!bi) return ECORE_CALLBACK_PASS_ON;
86
87    p->borders = eina_list_remove(p->borders, bi);
88    p->base.items = eina_list_remove(p->base.items, bi);
89    EVRY_ITEM_FREE(bi);
90
91    EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
92
93    return ECORE_CALLBACK_PASS_ON;
94 }
95 static Eina_Bool
96 _cb_border_add(void *data, __UNUSED__ int type,  void *event)
97 {
98    E_Event_Border_Add *ev = event;
99    Plugin *p = data;
100    unsigned int min;
101
102    if (!_border_item_add(p, ev->border))
103      return ECORE_CALLBACK_PASS_ON;
104
105    EVRY_PLUGIN_ITEMS_CLEAR(p);
106
107    min = EVRY_PLUGIN(p)->config->min_query;
108
109    if ((!p->input && (min == 0)) ||
110        (p->input && (strlen(p->input) >= min)))
111      {
112         EVRY_PLUGIN_ITEMS_ADD(p, p->borders, p->input, 1, 0);
113
114         EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
115      }
116
117    return ECORE_CALLBACK_PASS_ON;
118 }
119
120 static void
121 _get_borderlist(Plugin *p)
122 {
123    E_Border *bd;
124    Eina_List *l;
125
126    p->handlers = eina_list_append
127      (p->handlers, ecore_event_handler_add
128       (E_EVENT_BORDER_REMOVE, _cb_border_remove, p));
129
130    p->handlers = eina_list_append
131      (p->handlers, ecore_event_handler_add
132       (E_EVENT_BORDER_ADD, _cb_border_add, p));
133
134    EINA_LIST_FOREACH(e_border_focus_stack_get(), l, bd)
135      _border_item_add(p, bd);
136 }
137
138 static Evry_Plugin *
139 _begin(Evry_Plugin *plugin, const Evry_Item *item __UNUSED__)
140 {
141    Plugin *p;
142    EVRY_PLUGIN_INSTANCE(p, plugin);
143
144    return EVRY_PLUGIN(p);
145 }
146
147 static void
148 _finish(Evry_Plugin *plugin)
149 {
150    Ecore_Event_Handler *h;
151    Border_Item *bi;
152
153    GET_PLUGIN(p, plugin);
154
155    IF_RELEASE(p->input);
156
157    EVRY_PLUGIN_ITEMS_CLEAR(p);
158
159    EINA_LIST_FREE(p->borders, bi)
160      EVRY_ITEM_FREE(bi);
161
162    EINA_LIST_FREE(p->handlers, h)
163      ecore_event_handler_del(h);
164
165    E_FREE(p);
166 }
167
168 static int
169 _fetch(Evry_Plugin *plugin, const char *input)
170 {
171    int len = (input ? strlen(input) : 0);
172
173    GET_PLUGIN(p, plugin);
174
175    EVRY_PLUGIN_ITEMS_CLEAR(p);
176
177    if (len >= plugin->config->min_query)
178      {
179         IF_RELEASE(p->input);
180
181         if (input)
182           p->input = eina_stringshare_add(input);
183
184         if (!p->handlers)
185           _get_borderlist(p);
186
187         EVRY_PLUGIN_ITEMS_ADD(p, p->borders, input, 1, 0);
188      }
189
190    return !!(p->base.items);
191 }
192
193 static Evas_Object *
194 _icon_get(Evry_Item *it, Evas *e)
195 {
196    GET_BORDER(bi, it);
197
198    Evas_Object *o = NULL;
199    E_Border *bd = bi->border;
200
201    if (bd->internal)
202      {
203         o = edje_object_add(e);
204         if (!bd->internal_icon)
205           e_util_edje_icon_set(o, "enlightenment/e");
206         else if (!bd->internal_icon_key)
207           {
208              char *ext;
209              ext = strrchr(bd->internal_icon, '.');
210              if ((ext) && ((!strcmp(ext, ".edj"))))
211                {
212                   if (!edje_object_file_set(o, bd->internal_icon, "icon"))
213                     e_util_edje_icon_set(o, "enlightenment/e");
214                }
215              else if (ext)
216                {
217                   evas_object_del(o);
218                   o = e_icon_add(e);
219                   e_icon_file_set(o, bd->internal_icon);
220                }
221              else
222                {
223                   if (!e_util_edje_icon_set(o, bd->internal_icon))
224                     e_util_edje_icon_set(o, "enlightenment/e");
225                }
226           }
227         else
228           {
229              edje_object_file_set(o, bd->internal_icon,
230                                   bd->internal_icon_key);
231           }
232         return o;
233      }
234
235    if (!o && bd->desktop)
236      o = e_util_desktop_icon_add(bd->desktop, 128, e);
237
238    if (!o && bd->client.netwm.icons)
239      {
240         int i, size, tmp, found = 0;
241         o = e_icon_add(e);
242
243         size = bd->client.netwm.icons[0].width;
244
245         for (i = 1; i < bd->client.netwm.num_icons; i++)
246           {
247              if ((tmp = bd->client.netwm.icons[i].width) > size)
248                {
249                   size = tmp;
250                   found = i;
251                }
252           }
253
254         e_icon_data_set(o, bd->client.netwm.icons[found].data,
255                         bd->client.netwm.icons[found].width,
256                         bd->client.netwm.icons[found].height);
257         e_icon_alpha_set(o, 1);
258         return o;
259      }
260
261    if (!o)
262      o = e_border_icon_add(bd, e);
263
264    return o;
265 }
266
267
268 /***************************************************************************/
269
270 static int
271 _check_border(Evry_Action *act, const Evry_Item *it)
272 {
273    GET_BORDER(bi, it);
274
275    int action = EVRY_ITEM_DATA_INT_GET(act);
276    E_Border *bd = bi->border;
277    E_Zone *zone = e_util_zone_current_get(e_manager_current_get());
278
279    if (!bd)
280      {
281         ERR("no border");
282         return 0;
283      }
284
285    switch (action)
286      {
287       case BORDER_CLOSE:
288          if (bd->lock_close)
289            return 0;
290          break;
291
292       case BORDER_SHOW:
293          if (bd->lock_focus_in)
294            return 0;
295          break;
296
297       case BORDER_HIDE:
298          if (bd->lock_user_iconify)
299            return 0;
300          break;
301
302       case BORDER_FULLSCREEN:
303          if (!bd->lock_user_fullscreen)
304            return 0;
305          break;
306
307       case BORDER_TODESK:
308          if (bd->desk == (e_desk_current_get(zone)))
309            return 0;
310          break;
311      }
312
313    return 1;
314 }
315
316 static int
317 _act_border(Evry_Action *act)
318 {
319    GET_BORDER(bi, act->it1.item);
320
321    int action = EVRY_ITEM_DATA_INT_GET(act);
322    E_Border *bd = bi->border;
323    E_Zone *zone = e_util_zone_current_get(e_manager_current_get());
324    int focus = 0;
325
326    if (!bd)
327      {
328         ERR("no border");
329         return 0;
330      }
331
332    switch (action)
333      {
334       case BORDER_CLOSE:
335         e_border_act_close_begin(bd);
336         break;
337
338       case BORDER_SHOW:
339          if (bd->desk != (e_desk_current_get(zone)))
340            e_desk_show(bd->desk);
341          focus = 1;
342          break;
343
344       case BORDER_HIDE:
345          e_border_iconify(bd);
346          break;
347
348       case BORDER_FULLSCREEN:
349          if (!bd->fullscreen)
350            e_border_fullscreen(bd, E_FULLSCREEN_RESIZE);
351          else
352            e_border_unfullscreen(bd);
353          break;
354
355       case BORDER_TODESK:
356          if (bd->desk != (e_desk_current_get(zone)))
357            e_border_desk_set(bd, e_desk_current_get(zone));
358          focus = 1;
359          break;
360       default:
361          break;
362      }
363
364    if (focus)
365      {
366         if (bd->shaded)
367           e_border_unshade(bd, E_DIRECTION_UP);
368
369         if (bd->iconic)
370           e_border_uniconify(bd);
371         else
372           e_border_raise(bd);
373
374         if (!bd->lock_focus_out)
375           {
376              e_border_focus_set(bd, 1, 1);
377              e_border_focus_latest_set(bd);
378           }
379
380         if ((e_config->focus_policy != E_FOCUS_CLICK) ||
381             (e_config->winlist_warp_at_end) ||
382             (e_config->winlist_warp_while_selecting))
383           {
384              int warp_to_x = bd->x + (bd->w / 2);
385              if (warp_to_x < (bd->zone->x + 1))
386                warp_to_x = bd->zone->x + ((bd->x + bd->w - bd->zone->x) / 2);
387              else if (warp_to_x >= (bd->zone->x + bd->zone->w - 1))
388                warp_to_x = (bd->zone->x + bd->zone->w + bd->x) / 2;
389
390              int warp_to_y = bd->y + (bd->h / 2);
391              if (warp_to_y < (bd->zone->y + 1))
392                warp_to_y = bd->zone->y + ((bd->y + bd->h - bd->zone->y) / 2);
393              else if (warp_to_y >= (bd->zone->y + bd->zone->h - 1))
394                warp_to_y = (bd->zone->y + bd->zone->h + bd->y) / 2;
395
396              ecore_x_pointer_warp(bd->zone->container->win, warp_to_x, warp_to_y);
397           }
398         /* e_border_focus_set_with_pointer(bd); */
399      }
400
401    return 1;
402 }
403
404 static int
405 _plugins_init(const Evry_API *_api)
406 {
407    Evry_Action *act;
408
409    if (evry_module->active)
410      return EINA_TRUE;
411
412    evry = _api;
413
414    if (!evry->api_version_check(EVRY_API_VERSION))
415      return EINA_FALSE;
416
417    _plug = EVRY_PLUGIN_NEW(Plugin, N_("Windows"),
418                            "preferences-system-windows",
419                            EVRY_TYPE_BORDER,
420                            _begin, _finish, _fetch, NULL);
421    _plug->transient = EINA_TRUE;
422    evry->plugin_register(_plug, EVRY_PLUGIN_SUBJECT, 2);
423
424    act = EVRY_ACTION_NEW(_("Switch to Window"),
425                          EVRY_TYPE_BORDER, 0, "go-next",
426                          _act_border, _check_border);
427    EVRY_ITEM_DATA_INT_SET(act, BORDER_SHOW);
428    evry->action_register(act, 1);
429
430    _actions = eina_list_append(_actions, act);
431
432    act = EVRY_ACTION_NEW(_("Iconify"),
433                          EVRY_TYPE_BORDER, 0, "go-down",
434                          _act_border, _check_border);
435    EVRY_ITEM_DATA_INT_SET(act, BORDER_HIDE);
436    _actions = eina_list_append(_actions, act);
437    evry->action_register(act, 2);
438
439    act = EVRY_ACTION_NEW(_("Toggle Fullscreen"),
440                          EVRY_TYPE_BORDER, 0, "view-fullscreen",
441                          _act_border, _check_border);
442    EVRY_ITEM_DATA_INT_SET(act, BORDER_FULLSCREEN);
443    _actions = eina_list_append(_actions, act);
444    evry->action_register(act, 4);
445
446    act = EVRY_ACTION_NEW(_("Close"),
447                          EVRY_TYPE_BORDER, 0, "list-remove",
448                          _act_border, _check_border);
449    EVRY_ITEM_DATA_INT_SET(act, BORDER_CLOSE);
450    _actions = eina_list_append(_actions, act);
451    evry->action_register(act, 3);
452
453    act = EVRY_ACTION_NEW(_("Send to Desktop"),
454                          EVRY_TYPE_BORDER, 0, "go-previous",
455                          _act_border, _check_border);
456    EVRY_ITEM_DATA_INT_SET(act, BORDER_TODESK);
457    _actions = eina_list_append(_actions, act);
458    evry->action_register(act, 3);
459
460    return EINA_TRUE;
461 }
462
463 static void
464 _plugins_shutdown(void)
465 {
466    Evry_Action *act;
467
468    if (!evry_module->active) return;
469
470    EVRY_PLUGIN_FREE(_plug);
471
472    EINA_LIST_FREE(_actions, act)
473      EVRY_ACTION_FREE(act);
474
475    evry_module->active = EINA_FALSE;
476 }
477
478 /***************************************************************************/
479
480 Eina_Bool
481 evry_plug_windows_init(E_Module *m)
482 {
483    EVRY_MODULE_NEW(evry_module, evry, _plugins_init, _plugins_shutdown);
484
485    return EINA_TRUE;
486 }
487
488 void
489 evry_plug_windows_shutdown(void)
490 {
491    EVRY_MODULE_FREE(evry_module);
492 }
493
494 void
495 evry_plug_windows_save(void){}