forked from enlightenment/enlightenment
471 lines
11 KiB
C
471 lines
11 KiB
C
#include "e.h"
|
|
#include "e_winilist.h"
|
|
|
|
/* internal calls */
|
|
typedef struct _Data Data;
|
|
typedef struct _Special Special;
|
|
|
|
struct _Data
|
|
{
|
|
Evas_Object *o_frame;
|
|
Evas_Object *o_ilist;
|
|
struct {
|
|
void (*func) (void *data, E_Border *bd);
|
|
void *data;
|
|
} select;
|
|
struct {
|
|
Eina_List *prepend;
|
|
Eina_List *append;
|
|
unsigned char changed : 1;
|
|
} special;
|
|
struct {
|
|
Evas_Coord w, h;
|
|
} optimal_size;
|
|
Eina_List *borders;
|
|
Eina_List *labels;
|
|
};
|
|
|
|
struct _Special
|
|
{
|
|
Evas_Object *icon;
|
|
const char *label;
|
|
void (*func) (void *data1, void *data2);
|
|
void *data1;
|
|
void *data2;
|
|
};
|
|
|
|
static void _cb_item_sel(void *data, void *data2);
|
|
static void _cb_special_sel(void *data, void *data2);
|
|
|
|
static void _cb_object_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
|
|
static void _cb_object_resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
|
|
|
|
static void _refill(Data *d);
|
|
|
|
static int _cb_border_add(void *data, int ev_type, void *ev);
|
|
static int _cb_border_remove(void *data, int ev_type, void *ev);
|
|
static int _cb_border_show(void *data, int ev_type, void *ev);
|
|
static int _cb_border_hide(void *data, int ev_type, void *ev);
|
|
static int _cb_border_property(void *data, int ev_type, void *ev);
|
|
static int _cb_desk_show(void *data, int ev_type, void *event);
|
|
|
|
/* state */
|
|
static Eina_List *handlers = NULL;
|
|
static Eina_List *winilists = NULL;
|
|
|
|
/* called from the module core */
|
|
EAPI int
|
|
e_winilist_init(void)
|
|
{
|
|
handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_ADD, _cb_border_add, NULL));
|
|
handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_REMOVE, _cb_border_remove, NULL));
|
|
handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_SHOW, _cb_border_show, NULL));
|
|
handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_HIDE, _cb_border_hide, NULL));
|
|
handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_PROPERTY, _cb_border_property, NULL));
|
|
handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_DESK_SHOW, _cb_desk_show, NULL));
|
|
return 1;
|
|
}
|
|
|
|
EAPI int
|
|
e_winilist_shutdown(void)
|
|
{
|
|
Ecore_Event_Handler *handle;
|
|
|
|
EINA_LIST_FREE(handlers, handle)
|
|
ecore_event_handler_del(handle);
|
|
return 1;
|
|
}
|
|
|
|
EAPI Evas_Object *
|
|
e_winilist_add(Evas *e)
|
|
{
|
|
Data *d;
|
|
|
|
d = E_NEW(Data, 1);
|
|
d->o_frame = e_scrollframe_add(e);
|
|
d->o_ilist = e_ilist_add(e);
|
|
evas_object_data_set(d->o_frame, "..[winilist]", d);
|
|
e_ilist_selector_set(d->o_ilist, 1);
|
|
|
|
e_scrollframe_child_set(d->o_frame, d->o_ilist);
|
|
evas_object_show(d->o_ilist);
|
|
|
|
winilists = eina_list_append(winilists, d);
|
|
evas_object_event_callback_add(d->o_frame, EVAS_CALLBACK_DEL, _cb_object_del, NULL);
|
|
evas_object_event_callback_add(d->o_frame, EVAS_CALLBACK_RESIZE, _cb_object_resize, NULL);
|
|
|
|
_refill(d);
|
|
|
|
return d->o_frame;
|
|
}
|
|
|
|
EAPI void
|
|
e_winilist_border_select_callback_set(Evas_Object *obj, void (*func) (void *data, E_Border *bd), void *data)
|
|
{
|
|
Data *d;
|
|
|
|
d = evas_object_data_get(obj, "..[winilist]");
|
|
if (!d) return;
|
|
d->select.func = func;
|
|
d->select.data = data;
|
|
}
|
|
|
|
EAPI void
|
|
e_winilist_special_append(Evas_Object *obj, Evas_Object *icon, const char *label, void (*func) (void *data1, void *data2), void *data1, void *data2)
|
|
{
|
|
Data *d;
|
|
|
|
d = evas_object_data_get(obj, "..[winilist]");
|
|
if (!d) return;
|
|
{
|
|
Special *s;
|
|
|
|
s = E_NEW(Special, 1);
|
|
d->special.prepend = eina_list_prepend(d->special.prepend, s);
|
|
s->icon = icon;
|
|
if (label) s->label = eina_stringshare_add(label);
|
|
s->func = func;
|
|
s->data1 = data1;
|
|
s->data2 = data2;
|
|
d->special.changed = 1;
|
|
}
|
|
_refill(d);
|
|
}
|
|
|
|
EAPI void
|
|
e_winilist_special_prepend(Evas_Object *obj, Evas_Object *icon, const char *label, void (*func) (void *data1, void *data2), void *data1, void *data2)
|
|
{
|
|
Data *d;
|
|
|
|
d = evas_object_data_get(obj, "..[winilist]");
|
|
if (!d) return;
|
|
{
|
|
Special *s;
|
|
|
|
s = E_NEW(Special, 1);
|
|
d->special.append = eina_list_append(d->special.append, s);
|
|
s->icon = icon;
|
|
if (label) s->label = eina_stringshare_add(label);
|
|
s->func = func;
|
|
s->data1 = data1;
|
|
s->data2 = data2;
|
|
d->special.changed = 1;
|
|
}
|
|
_refill(d);
|
|
}
|
|
|
|
EAPI void
|
|
e_winilist_optimial_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
|
|
{
|
|
Data *d;
|
|
|
|
if (w) *w = 0;
|
|
if (h) *h = 0;
|
|
d = evas_object_data_get(obj, "..[winilist]");
|
|
if (!d) return;
|
|
if (w) *w = d->optimal_size.w;
|
|
if (h) *h = d->optimal_size.h;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
/* internal calls */
|
|
static void
|
|
_cb_item_sel(void *data, void *data2)
|
|
{
|
|
Data *d;
|
|
|
|
d = data;
|
|
if (d->select.func)
|
|
{
|
|
d->select.func(d->select.data, data2);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_cb_special_sel(void *data, void *data2)
|
|
{
|
|
Special *s;
|
|
|
|
s = data;
|
|
if (s->func)
|
|
{
|
|
s->func(s->data1, s->data2);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_cb_object_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
|
|
{
|
|
Data *d;
|
|
|
|
d = evas_object_data_get(obj, "..[winilist]");
|
|
if (!d) return;
|
|
evas_object_del(d->o_ilist);
|
|
winilists = eina_list_remove(winilists, d);
|
|
|
|
while (d->borders)
|
|
{
|
|
e_object_unref(E_OBJECT(d->borders->data));
|
|
d->borders = eina_list_remove_list(d->borders, d->borders);
|
|
}
|
|
while (d->labels)
|
|
{
|
|
eina_stringshare_del(d->labels->data);
|
|
d->labels = eina_list_remove_list(d->labels, d->labels);
|
|
}
|
|
|
|
while (d->special.prepend)
|
|
{
|
|
Special *s;
|
|
|
|
s = d->special.prepend->data;
|
|
if (s->icon)
|
|
{
|
|
evas_object_del(s->icon);
|
|
s->icon = NULL;
|
|
}
|
|
if (s->label)
|
|
{
|
|
eina_stringshare_del(s->label);
|
|
s->label = NULL;
|
|
}
|
|
free(s);
|
|
d->special.prepend = eina_list_remove_list(d->special.prepend, d->special.prepend);
|
|
}
|
|
while (d->special.append)
|
|
{
|
|
Special *s;
|
|
|
|
s = d->special.append->data;
|
|
if (s->icon)
|
|
{
|
|
evas_object_del(s->icon);
|
|
s->icon = NULL;
|
|
}
|
|
if (s->label)
|
|
{
|
|
eina_stringshare_del(s->label);
|
|
s->label = NULL;
|
|
}
|
|
free(s);
|
|
d->special.append = eina_list_remove_list(d->special.append, d->special.append);
|
|
}
|
|
|
|
free(d);
|
|
}
|
|
|
|
static void
|
|
_cb_object_resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
|
|
{
|
|
Data *d;
|
|
Evas_Coord lw, lh, vw, vh;
|
|
|
|
d = evas_object_data_get(obj, "..[winilist]");
|
|
if (!d) return;
|
|
e_ilist_size_min_get(d->o_ilist, &lw, &lh);
|
|
if (lh < (120 * e_scale)) lh = 120 * e_scale;
|
|
printf("%i\n", lh);
|
|
e_scrollframe_child_viewport_size_get(d->o_frame, &vw, &vh);
|
|
evas_object_resize(d->o_ilist, vw, lh);
|
|
}
|
|
|
|
static void
|
|
_refill(Data *d)
|
|
{
|
|
Evas_Coord w, h, lw, lh, vw, vh;
|
|
Eina_List *borders, *l, *l2, *l3;
|
|
|
|
borders = e_border_client_list();
|
|
if (!d->special.changed)
|
|
{
|
|
int changed = 0;
|
|
|
|
if ((borders) && (d->borders))
|
|
{
|
|
Eina_List *tmp = NULL;
|
|
|
|
changed = 0;
|
|
for (l = borders; l; l = l->next)
|
|
{
|
|
E_Border *bd;
|
|
|
|
bd = l->data;
|
|
if (e_object_is_del(E_OBJECT(bd))) continue;
|
|
if ((!bd->client.icccm.accepts_focus) &&
|
|
(!bd->client.icccm.take_focus)) continue;
|
|
if (bd->client.netwm.state.skip_taskbar) continue;
|
|
if (bd->user_skip_winlist) continue;
|
|
if ((!bd->sticky) &&
|
|
(bd->desk != e_desk_current_get(bd->zone))) continue;
|
|
tmp = eina_list_append(tmp, bd);
|
|
}
|
|
if (!(tmp && d->borders))
|
|
{
|
|
changed = 1;
|
|
}
|
|
else
|
|
{
|
|
if (eina_list_count(tmp) !=
|
|
eina_list_count(d->borders))
|
|
{
|
|
changed = 1;
|
|
}
|
|
else
|
|
{
|
|
for (l = tmp, l2 = d->borders, l3 = d->labels;
|
|
l && l2 && l3;
|
|
l = l->next, l2 = l2->next, l3 = l3->next)
|
|
{
|
|
E_Border *bd, *bd2;
|
|
const char *title;
|
|
|
|
bd = l->data;
|
|
bd2 = l2->data;
|
|
if (bd != bd2)
|
|
{
|
|
changed = 1;
|
|
break;
|
|
}
|
|
|
|
title = "???";
|
|
if (bd->client.netwm.name) title = bd->client.netwm.name;
|
|
else if (bd->client.icccm.title) title = bd->client.icccm.title;
|
|
if (strcmp(title, l3->data))
|
|
{
|
|
changed = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (tmp) eina_list_free(tmp);
|
|
}
|
|
else
|
|
changed = 1;
|
|
if (!changed) return;
|
|
}
|
|
d->special.changed = 0;
|
|
while (d->borders)
|
|
{
|
|
e_object_unref(E_OBJECT(d->borders->data));
|
|
d->borders = eina_list_remove_list(d->borders, d->borders);
|
|
}
|
|
while (d->labels)
|
|
{
|
|
eina_stringshare_del(d->labels->data);
|
|
d->labels = eina_list_remove_list(d->labels, d->labels);
|
|
}
|
|
|
|
e_ilist_freeze(d->o_ilist);
|
|
e_ilist_clear(d->o_ilist);
|
|
for (l = d->special.prepend; l; l = l->next)
|
|
{
|
|
Special *s;
|
|
|
|
s = l->data;
|
|
e_ilist_append(d->o_ilist, s->icon, NULL, s->label, 0, _cb_special_sel, NULL,
|
|
s, NULL);
|
|
}
|
|
for (l = borders; l; l = l->next)
|
|
{
|
|
E_Border *bd;
|
|
const char *title;
|
|
|
|
bd = l->data;
|
|
if (e_object_is_del(E_OBJECT(bd))) continue;
|
|
if ((!bd->client.icccm.accepts_focus) &&
|
|
(!bd->client.icccm.take_focus)) continue;
|
|
if (bd->client.netwm.state.skip_taskbar) continue;
|
|
if (bd->user_skip_winlist) continue;
|
|
if ((!bd->sticky) &&
|
|
(bd->desk != e_desk_current_get(bd->zone))) continue;
|
|
|
|
title = "???";
|
|
if (bd->client.netwm.name) title = bd->client.netwm.name;
|
|
else if (bd->client.icccm.title) title = bd->client.icccm.title;
|
|
e_object_ref(E_OBJECT(bd));
|
|
d->borders = eina_list_append(d->borders, bd);
|
|
d->labels = eina_list_append(d->labels, eina_stringshare_add(title));
|
|
e_ilist_append(d->o_ilist, NULL/*icon*/, NULL, title, 0,
|
|
_cb_item_sel,
|
|
NULL, d, bd);
|
|
}
|
|
for (l = d->special.append; l; l = l->next)
|
|
{
|
|
Special *s;
|
|
|
|
s = l->data;
|
|
e_ilist_append(d->o_ilist, s->icon, NULL, s->label, 0, _cb_special_sel, NULL,
|
|
s, NULL);
|
|
}
|
|
|
|
e_ilist_thaw(d->o_ilist);
|
|
|
|
/* FIXME: figure out optimal size */
|
|
e_ilist_size_min_get(d->o_ilist, &lw, &lh);
|
|
if (lh < (120 * e_scale)) lh = 120 * e_scale;
|
|
printf("%i\n", lh);
|
|
e_scrollframe_child_viewport_size_get(d->o_frame, &vw, &vh);
|
|
evas_object_geometry_get(d->o_frame, NULL, NULL, &w, &h);
|
|
evas_object_resize(d->o_ilist, vw, lh);
|
|
|
|
d->optimal_size.w = lw + (w - vw);
|
|
d->optimal_size.h = lh + (h - vh);
|
|
}
|
|
|
|
static int
|
|
_cb_border_add(void *data, int ev_type, void *event)
|
|
{
|
|
Eina_List *l;
|
|
|
|
for (l = winilists; l; l = l->next) _refill(l->data);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_cb_border_remove(void *data, int ev_type, void *event)
|
|
{
|
|
Eina_List *l;
|
|
|
|
for (l = winilists; l; l = l->next) _refill(l->data);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_cb_border_show(void *data, int ev_type, void *event)
|
|
{
|
|
Eina_List *l;
|
|
|
|
for (l = winilists; l; l = l->next) _refill(l->data);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_cb_border_hide(void *data, int ev_type, void *event)
|
|
{
|
|
Eina_List *l;
|
|
|
|
for (l = winilists; l; l = l->next) _refill(l->data);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_cb_border_property(void *data, int ev_type, void *event)
|
|
{
|
|
Eina_List *l;
|
|
|
|
for (l = winilists; l; l = l->next) _refill(l->data);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_cb_desk_show(void *data, int ev_type, void *event)
|
|
{
|
|
Eina_List *l;
|
|
|
|
for (l = winilists; l; l = l->next) _refill(l->data);
|
|
return 1;
|
|
}
|
|
|