enlightenment/src/modules/itray/e_mod_main.c

1309 lines
35 KiB
C

/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include "e.h"
#include "e_mod_main.h"
#include "e_mod_config.h"
#include <math.h>
#include "Ecore_X.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
/* Currently unused */
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
#define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1
/* ---------------- */
#define XEMBED_EMBEDDED_NOTIFY 0
#define TRAY_ICON_SIZE 27
/* Bug List:
*
* Changing the number of rows breaks the layout.
* It's magically fixed when the module is moved.
*
* TODO List:
*
* Make sure only one tray exists.
* Use the abovestated defines.
* Change the size of the tray icons.
* Use the shape extension for the ecore_x_window so that the "gray"
* itself is not visible, but the tray icons are.
*
* The Big Picture:
*
* Get rid of the ecore_x_window stuff.
* Make the tray survive an E restart.
*
*/
static int box_count;
static E_Config_DD *conf_edd;
static E_Config_DD *conf_box_edd;
/* const strings */
static const char *_itray_main_orientation[] =
{"left", "right", "top", "bottom"};
/* module private routines */
static ITray *_itray_new();
static void _itray_free(ITray *it);
static void _itray_config_menu_new(ITray *it);
static ITray_Box *_itray_box_new(ITray *it, E_Container *con);
static void _itray_box_free(ITray_Box *itb);
static void _itray_box_menu_new(ITray_Box *itb);
static void _itray_box_disable(ITray_Box *itb);
static void _itray_box_frame_resize(ITray_Box *itb);
static void _itray_box_edge_change(ITray_Box *itb, int edge);
static void _itray_box_update_policy(ITray_Box *itb);
static void _itray_box_cb_gmc_change(void *data, E_Gadman_Client *gmc, E_Gadman_Change change);
static void _itray_box_cb_mouse_in(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _itray_box_cb_mouse_out(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _itray_box_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _itray_box_cb_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _itray_box_cb_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _itray_box_cb_menu_configure(void *data, E_Menu *m, E_Menu_Item *mi);
static void _itray_box_cb_menu_edit(void *data, E_Menu *m, E_Menu_Item *mi);
/* Config Updated Function Protos */
static void _itray_box_cb_width_auto(void *data);
/* Tray */
static void _itray_tray_init(ITray_Box *itb);
static void _itray_tray_shutdown(ITray_Box *itb);
static int _itray_tray_cb_msg(void *data, int type, void *event);
static int _itray_tray_cb_destroy(void *data, int type, void *event);
static int _itray_tray_cb_hide(void *data, int type, void *event);
static int _itray_tray_cb_shape(void *data, int type, void *event);
static int _itray_exists(ITray_Box *itb, Ecore_X_Window win);
static void _itray_reshape(ITray_Box *itb);
static void _itray_tray_active_set();
static void _itray_tray_add(ITray_Box *itb, Ecore_X_Window win);
static void _itray_tray_remove(ITray_Box *itb, Ecore_X_Window win);
static void _itray_tray_cb_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y);
static void _itray_tray_cb_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h);
static void _itray_tray_layout(ITray_Box *itb);
/* public module routines. all modules must have these */
EAPI E_Module_Api e_modapi =
{
E_MODULE_API_VERSION,
"ITray"
};
EAPI void *
e_modapi_init(E_Module *m)
{
ITray *it;
/* actually init ibox */
it = _itray_new();
m->config_menu = it->config_menu;
return it;
}
EAPI int
e_modapi_shutdown(E_Module *m)
{
ITray *it;
if (m->config_menu)
m->config_menu = NULL;
it = m->data;
if (it)
{
if (it->config_dialog)
{
e_object_del(E_OBJECT(it->config_dialog));
it->config_dialog = NULL;
}
_itray_free(it);
}
return 1;
}
EAPI int
e_modapi_save(E_Module *m)
{
ITray *it;
it = m->data;
e_config_domain_save("module.itray", conf_edd, it->conf);
return 1;
}
EAPI int
e_modapi_info(E_Module *m)
{
char buf[4096];
snprintf(buf, sizeof(buf), "%s/module_icon.png", e_module_dir_get(m));
m->icon_file = strdup(buf);
return 1;
}
EAPI int
e_modapi_about(E_Module *m)
{
e_module_dialog_show(_("Enlightenment ITray Module"),
_("This is the ITray system tray module for Enlightenment.<br>"
"It will hold system tray icons.<br>"
"Beware that this can be buggy due to many systray providing<br>"
"applications not handling the protocol properly, and the way<br>"
"systray icons work being very limiting and hacky. Do not use<br>"
"this module unless you absolutely must, and if you do, beware<br>"
"of issues that will appear."
));
return 1;
}
EAPI int
e_modapi_config(E_Module *m)
{
ITray *e;
Evas_List *l;
e = m->data;
if (!e) return 0;
if (!e->boxes) return 0;
for (l = e->boxes; l; l = l->next)
{
ITray_Box *face;
face = l->data;
if (!face) return 0;
if (face->con == e_container_current_get(e_manager_current_get()))
{
_config_itray_module(face->con, face->itray);
break;
}
}
return 1;
}
/* module private routines */
static ITray *
_itray_new()
{
ITray *it;
Evas_List *managers, *l, *l2, *cl;
box_count = 0;
it = E_NEW(ITray, 1);
if (!it) return NULL;
conf_box_edd = E_CONFIG_DD_NEW("ITray_Config_Box", Config_Box);
#undef T
#undef D
#define T Config_Box
#define D conf_box_edd
E_CONFIG_VAL(D, T, enabled, UCHAR);
conf_edd = E_CONFIG_DD_NEW("ITray_Config", Config);
#undef T
#undef D
#define T Config
#define D conf_edd
E_CONFIG_VAL(D, T, rowsize, INT);
E_CONFIG_VAL(D, T, width, INT);
E_CONFIG_LIST(D, T, boxes, conf_box_edd);
it->conf = e_config_domain_load("module.itray", conf_edd);
if (!it->conf)
{
it->conf = E_NEW(Config, 1);
it->conf->rowsize = 1;
it->conf->width = ITRAY_WIDTH_AUTO;
}
E_CONFIG_LIMIT(it->conf->rowsize, 1, 6);
E_CONFIG_LIMIT(it->conf->width, -2, -1);
_itray_config_menu_new(it);
managers = e_manager_list();
cl = it->conf->boxes;
for (l = managers; l; l = l->next)
{
E_Manager *man;
man = l->data;
for (l2 = man->containers; l2; l2 = l2->next)
{
E_Container *con;
ITray_Box *itb;
/* Config */
con = l2->data;
itb = _itray_box_new(it, con);
if (itb)
{
E_Menu_Item *mi;
if (!cl)
{
itb->conf = E_NEW(Config_Box, 1);
itb->conf->enabled = 1;
it->conf->boxes = evas_list_append(it->conf->boxes, itb->conf);
}
else
{
itb->conf = cl->data;
cl = cl->next;
}
/* Menu */
_itray_box_menu_new(itb);
/* Add main menu to box menu */
mi = e_menu_item_new(it->config_menu);
e_menu_item_label_set(mi, con->name);
e_menu_item_submenu_set(mi, itb->menu);
/* Setup */
if (!itb->conf->enabled)
_itray_box_disable(itb);
}
}
}
return it;
}
static void
_itray_free(ITray *it)
{
E_CONFIG_DD_FREE(conf_edd);
E_CONFIG_DD_FREE(conf_box_edd);
while (it->boxes)
_itray_box_free(it->boxes->data);
e_object_del(E_OBJECT(it->config_menu));
evas_list_free(it->conf->boxes);
free(it->conf);
free(it);
}
static ITray_Box *
_itray_box_new(ITray *it, E_Container *con)
{
ITray_Box *itb;
Evas_Object *o;
E_Gadman_Policy policy;
Evas_Coord x, y, w, h;
itb = E_NEW(ITray_Box, 1);
if (!itb) return NULL;
itb->itray = it;
it->boxes = evas_list_append(it->boxes, itb);
itb->con = con;
e_object_ref(E_OBJECT(con));
itb->evas = con->bg_evas;
itb->tray = NULL;
itb->x = itb->y = itb->w = itb->h = -1;
evas_event_freeze(itb->evas);
o = edje_object_add(itb->evas);
itb->box_object = o;
e_theme_edje_object_set(o, "base/theme/modules/itray",
"modules/itray/main");
evas_object_show(o);
o = evas_object_rectangle_add(itb->evas);
itb->event_object = o;
evas_object_layer_set(o, 2);
evas_object_repeat_events_set(o, 1);
evas_object_color_set(o, 0, 0, 0, 0);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_IN, _itray_box_cb_mouse_in, itb);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_OUT, _itray_box_cb_mouse_out, itb);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _itray_box_cb_mouse_down, itb);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _itray_box_cb_mouse_up, itb);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _itray_box_cb_mouse_move, itb);
evas_object_show(o);
o = e_box_add(itb->evas);
itb->item_object = o;
_itray_tray_init(itb);
e_box_freeze(o);
edje_object_part_swallow(itb->box_object, "tray", o);
evas_object_show(o);
e_box_align_set(itb->item_object, 0.5, 0.5);
evas_object_resize(itb->box_object, 1000, 1000);
edje_object_calc_force(itb->box_object);
edje_object_part_geometry_get(itb->box_object, "tray", &x, &y, &w, &h);
itb->box_inset.l = x;
itb->box_inset.r = 1000 - (x + w);
itb->box_inset.t = y;
itb->box_inset.b = 1000 - (y + h);
e_box_thaw(itb->item_object);
itb->gmc = e_gadman_client_new(itb->con->gadman);
e_gadman_client_domain_set(itb->gmc, "module.itray", box_count++);
policy = E_GADMAN_POLICY_EDGES | E_GADMAN_POLICY_HMOVE | E_GADMAN_POLICY_VMOVE;
if (itb->itray->conf->width == ITRAY_WIDTH_FIXED)
policy |= E_GADMAN_POLICY_VSIZE;
e_gadman_client_policy_set(itb->gmc, policy);
e_gadman_client_min_size_set(itb->gmc, 8, 8);
e_gadman_client_max_size_set(itb->gmc, 3200, 3200);
e_gadman_client_auto_size_set(itb->gmc, -1, -1);
e_gadman_client_align_set(itb->gmc, 0.0, 1.0);
e_gadman_client_resize(itb->gmc, 400, 32);
e_gadman_client_change_func_set(itb->gmc, _itray_box_cb_gmc_change, itb);
e_gadman_client_edge_set(itb->gmc, E_GADMAN_EDGE_BOTTOM);
e_gadman_client_load(itb->gmc);
evas_event_thaw(itb->evas);
/* We need to resize, if the width is auto and the number
* of apps has changed since last startup */
_itray_box_frame_resize(itb);
return itb;
}
static void
_itray_box_free(ITray_Box *itb)
{
e_object_unref(E_OBJECT(itb->con));
e_object_del(E_OBJECT(itb->menu));
evas_object_del(itb->box_object);
evas_object_del(itb->item_object);
evas_object_del(itb->event_object);
if (itb->tray)
{
_itray_tray_shutdown(itb);
itb->tray = NULL;
}
e_gadman_client_save(itb->gmc);
e_object_del(E_OBJECT(itb->gmc));
itb->itray->boxes = evas_list_remove(itb->itray->boxes, itb);
free(itb->conf);
free(itb);
box_count--;
}
static void
_itray_box_menu_new(ITray_Box *itb)
{
E_Menu *mn;
E_Menu_Item *mi;
mn = e_menu_new();
itb->menu = mn;
/* Config */
mi = e_menu_item_new(mn);
e_menu_item_label_set(mi, _("Configuration"));
e_util_menu_item_edje_icon_set(mi, "enlightenment/configuration");
e_menu_item_callback_set(mi, _itray_box_cb_menu_configure, itb);
/* Edit */
mi = e_menu_item_new(mn);
e_menu_item_label_set(mi, _("Edit Mode"));
e_util_menu_item_edje_icon_set(mi, "enlightenment/gadgets");
e_menu_item_callback_set(mi, _itray_box_cb_menu_edit, itb);
}
static void
_itray_box_cb_menu_configure(void *data, E_Menu *m, E_Menu_Item *mi)
{
ITray_Box *itb;
itb = (ITray_Box *)data;
if (!itb) return;
_config_itray_module(itb->con, itb->itray);
}
static void
_itray_box_disable(ITray_Box *itb)
{
itb->conf->enabled = 0;
evas_object_hide(itb->box_object);
evas_object_hide(itb->item_object);
evas_object_hide(itb->event_object);
e_config_save_queue();
}
void
_itray_config_menu_new(ITray *it)
{
E_Menu *mn;
mn = e_menu_new();
it->config_menu = mn;
}
static void
_itray_box_frame_resize(ITray_Box *itb)
{
Evas_Coord w, h, bw, bh;
int icons_per_row;
/* Not finished loading config yet! */
if ((itb->x == -1) ||
(itb->y == -1) ||
(itb->w == -1) ||
(itb->h == -1))
return;
evas_event_freeze(itb->evas);
e_box_freeze(itb->item_object);
if (e_box_pack_count_get(itb->item_object))
e_box_min_size_get(itb->item_object, &w, &h);
else
{
if (!itb->tray)
w = h = TRAY_ICON_SIZE + itb->box_inset.l + itb->box_inset.r;
else if (!itb->tray->icons)
w = h = TRAY_ICON_SIZE + itb->box_inset.l + itb->box_inset.r;
else
{
if (itb->tray->rows > 0) itb->tray->rows = 1;
icons_per_row = (itb->tray->icons +
(itb->tray->icons % itb->tray->rows)) / itb->tray->rows;
w = (icons_per_row * TRAY_ICON_SIZE)
+ itb->box_inset.l + itb->box_inset.r;
h = (itb->tray->rows * TRAY_ICON_SIZE)
+ itb->box_inset.t + itb->box_inset.b;
}
}
edje_object_part_unswallow(itb->box_object, itb->item_object);
/* edje_extern_object_min_size_set(itb->item_object, w, h);*/
/* edje_object_part_swallow(itb->box_object, "tray", itb->item_object);*/
/* edje_object_size_min_calc(itb->box_object, &bw, &bh);*/
edje_extern_object_min_size_set(itb->item_object, 0, 0);
edje_object_part_swallow(itb->box_object, "tray", itb->item_object);
e_box_thaw(itb->item_object);
evas_event_thaw(itb->evas);
if (itb->itray->conf->width == ITRAY_WIDTH_AUTO)
{
if ((e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_LEFT) ||
(e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_RIGHT))
{
e_gadman_client_resize(itb->gmc, h, w);
}
else if ((e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_TOP) ||
(e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_BOTTOM))
{
e_gadman_client_resize(itb->gmc, w, h);
}
}
else
{
if ((e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_LEFT) ||
(e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_RIGHT))
{
/* h is the width of the box */
e_gadman_client_resize(itb->gmc, bw, itb->h);
}
else if ((e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_TOP) ||
(e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_BOTTOM))
{
/* w is the width of the box */
e_gadman_client_resize(itb->gmc, itb->w, bh);
}
}
}
static void
_itray_box_edge_change(ITray_Box *itb, int edge)
{
Evas_Coord bw, bh, tmp;
Evas_Object *o;
E_Gadman_Policy policy;
int changed;
evas_event_freeze(itb->evas);
o = itb->box_object;
edje_object_signal_emit(o, "set_orientation", _itray_main_orientation[edge]);
edje_object_message_signal_process(o);
e_box_freeze(itb->item_object);
e_box_align_set(itb->item_object, 0.5, 0.5);
policy = E_GADMAN_POLICY_EDGES | E_GADMAN_POLICY_HMOVE | E_GADMAN_POLICY_VMOVE;
if ((edge == E_GADMAN_EDGE_BOTTOM) ||
(edge == E_GADMAN_EDGE_TOP))
{
changed = (e_box_orientation_get(itb->item_object) != 1);
if (changed)
{
e_box_orientation_set(itb->item_object, 1);
if (itb->itray->conf->width == ITRAY_WIDTH_FIXED)
policy |= E_GADMAN_POLICY_HSIZE;
e_gadman_client_policy_set(itb->gmc, policy);
tmp = itb->w;
itb->w = itb->h;
itb->h = tmp;
}
}
else if ((edge == E_GADMAN_EDGE_LEFT) ||
(edge == E_GADMAN_EDGE_RIGHT))
{
changed = (e_box_orientation_get(itb->item_object) != 0);
if (changed)
{
e_box_orientation_set(itb->item_object, 0);
if (itb->itray->conf->width == ITRAY_WIDTH_FIXED)
policy |= E_GADMAN_POLICY_VSIZE;
e_gadman_client_policy_set(itb->gmc, policy);
tmp = itb->w;
itb->w = itb->h;
itb->h = tmp;
}
}
e_box_thaw(itb->item_object);
evas_event_thaw(itb->evas);
_itray_box_frame_resize(itb);
}
static void
_itray_box_update_policy(ITray_Box *itb)
{
E_Gadman_Policy policy;
policy = E_GADMAN_POLICY_EDGES | E_GADMAN_POLICY_HMOVE | E_GADMAN_POLICY_VMOVE;
if ((e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_BOTTOM) ||
(e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_TOP))
{
if (itb->itray->conf->width == ITRAY_WIDTH_FIXED)
policy |= E_GADMAN_POLICY_HSIZE;
e_gadman_client_policy_set(itb->gmc, policy);
}
else if ((e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_LEFT) ||
(e_gadman_client_edge_get(itb->gmc) == E_GADMAN_EDGE_RIGHT))
{
if (itb->itray->conf->width == ITRAY_WIDTH_FIXED)
policy |= E_GADMAN_POLICY_VSIZE;
e_gadman_client_policy_set(itb->gmc, policy);
}
}
static void
_itray_box_cb_mouse_in(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Evas_Event_Mouse_In *ev;
ITray_Box *itb;
ev = event_info;
itb = data;
}
static void
_itray_box_cb_mouse_out(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Evas_Event_Mouse_Out *ev;
ITray_Box *itb;
ev = event_info;
itb = data;
}
static void
_itray_box_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Evas_Event_Mouse_Down *ev;
ITray_Box *itb;
ev = event_info;
itb = data;
/*
if (ev->button == 3)
{
e_menu_activate_mouse(itb->menu, e_zone_current_get(itb->con),
ev->output.x, ev->output.y, 1, 1,
E_MENU_POP_DIRECTION_DOWN, ev->timestamp);
e_util_container_fake_mouse_up_later(itb->con, 3);
}
else
*/
{
Ecore_X_Window win;
int x, y, w, h, xx, yy;
Evas_List *l;
for (l = itb->tray->wins; l; l = l->next)
{
win = (Ecore_X_Window)l->data;
evas_pointer_output_xy_get(itb->evas, &xx, &yy);
evas_object_geometry_get(itb->item_object, &x, &y, NULL, NULL);
xx -= x;
yy -= y;
ecore_x_window_geometry_get(win, &x, &y, &w, &h);
if (E_CONTAINS(x, y, w, h, xx, yy, 1, 1))
{
x = xx - x;
y = yy - y;
win = ecore_x_window_at_xy_begin_get(win, x, y);
ecore_x_pointer_ungrab();
ecore_x_flush();
ecore_x_mouse_down_send(win, x, y, ev->button);
e_util_container_fake_mouse_up_later(itb->con, ev->button);
break;
}
}
}
}
static void
_itray_box_cb_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Evas_Event_Mouse_Up *ev;
ITray_Box *itb;
ev = event_info;
itb = data;
/*
if (ev->button == 3)
{
}
else
*/
{
Ecore_X_Window win;
int x, y, w, h, xx, yy;
Evas_List *l;
for (l = itb->tray->wins; l; l = l->next)
{
win = (Ecore_X_Window)l->data;
evas_pointer_output_xy_get(itb->evas, &xx, &yy);
evas_object_geometry_get(itb->item_object, &x, &y, NULL, NULL);
xx -= x;
yy -= y;
ecore_x_window_geometry_get(win, &x, &y, &w, &h);
if (E_CONTAINS(x, y, w, h, xx, yy, 1, 1))
{
x = xx - x;
y = yy - y;
win = ecore_x_window_at_xy_begin_get(win, x, y);
ecore_x_mouse_up_send(win, x, y, ev->button);
break;
}
}
}
}
static void
_itray_box_cb_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Evas_Event_Mouse_Move *ev;
ITray_Box *itb;
ev = event_info;
itb = data;
{
Ecore_X_Window win;
int x, y, w, h, xx, yy;
Evas_List *l;
for (l = itb->tray->wins; l; l = l->next)
{
win = (Ecore_X_Window)l->data;
evas_pointer_output_xy_get(itb->evas, &xx, &yy);
evas_object_geometry_get(itb->item_object, &x, &y, NULL, NULL);
xx -= x;
yy -= y;
ecore_x_window_geometry_get(win, &x, &y, &w, &h);
if (E_CONTAINS(x, y, w, h, xx, yy, 1, 1))
{
x = xx - x;
y = yy - y;
win = ecore_x_window_at_xy_begin_get(win, x, y);
ecore_x_mouse_move_send(win, x, y);
break;
}
}
}
}
static void
_itray_box_cb_gmc_change(void *data, E_Gadman_Client *gmc, E_Gadman_Change change)
{
ITray_Box *itb;
itb = data;
switch (change)
{
case E_GADMAN_CHANGE_MOVE_RESIZE:
e_gadman_client_geometry_get(itb->gmc, &itb->x, &itb->y, &itb->w, &itb->h);
edje_extern_object_min_size_set(itb->item_object, 0, 0);
edje_object_part_swallow(itb->box_object, "tray", itb->item_object);
evas_object_move(itb->box_object, itb->x, itb->y);
evas_object_resize(itb->box_object, itb->w, itb->h);
break;
case E_GADMAN_CHANGE_EDGE:
_itray_box_edge_change(itb, e_gadman_client_edge_get(itb->gmc));
break;
case E_GADMAN_CHANGE_RAISE:
case E_GADMAN_CHANGE_ZONE:
/* Ignore */
break;
}
}
static void
_itray_box_cb_width_auto(void *data)
{
ITray *it;
ITray_Box *itb;
Evas_List *l;
it = (ITray *)data;
for (l = it->boxes; l; l = l->next)
{
itb = l->data;
_itray_box_update_policy(itb);
_itray_box_frame_resize(itb);
}
}
static void
_itray_box_cb_menu_edit(void *data, E_Menu *m, E_Menu_Item *mi)
{
ITray_Box *itb;
itb = data;
e_gadman_mode_set(itb->gmc->gadman, E_GADMAN_MODE_EDIT);
}
void
_itray_box_cb_config_updated(void *data)
{
/* Call Any Needed Funcs To Let Module Handle Config Changes */
_itray_box_cb_width_auto(data);
}
void
_itray_tray_init(ITray_Box *itb)
{
Evas_Coord x, y, w, h;
Ecore_X_Window *windows;
int wnum;
/* FIXME - temp */
itb->tray = malloc(sizeof(ITray_Tray));
itb->tray->icons = 0;
itb->tray->w = 1;
itb->tray->h = 1;
itb->tray->wins = NULL;
evas_object_resize(itb->item_object, itb->tray->w, itb->tray->h);
evas_object_color_set(itb->item_object, 0, 0, 0, 0);
evas_object_intercept_move_callback_add(itb->item_object, _itray_tray_cb_move, itb);
evas_object_intercept_resize_callback_add(itb->item_object, _itray_tray_cb_resize, itb);
_itray_tray_active_set(itb, 1);
evas_object_geometry_get(itb->item_object, &x, &y, &w, &h);
itb->tray->win = ecore_x_window_new(itb->con->bg_win, x, y, w, h);
ecore_x_window_container_manage(itb->tray->win);
/* this sucks because some icons inherit the bg pixmap/color of the parent win and thus the color... and are not shaped */
ecore_x_window_background_color_set(itb->tray->win, 0xffff, 0xffff, 0xffff);
itb->tray->msg_handler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _itray_tray_cb_msg, itb);
itb->tray->dst_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, _itray_tray_cb_destroy, itb);
windows = ecore_x_window_children_get(itb->con->manager->root, &wnum);
if (windows)
{
int i;
Ecore_X_Atom atom_xmbed, atom_kde_netwm_systray, atom_kwm_dockwindow,
atom_window;
atom_window = ecore_x_atom_get("WINDOW");
atom_xmbed = ecore_x_atom_get("_XEMBED_INFO");
atom_kde_netwm_systray = ecore_x_atom_get("_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR");
atom_kwm_dockwindow = ecore_x_atom_get("KWM_DOCKWINDOW");
for (i = 0; i < wnum; i++)
{
Ecore_X_Window_Attributes att;
if (ecore_x_window_attributes_get(windows[i], &att))
{
// if (0)
// if (att.visible)
{
unsigned char *data = NULL;
int count;
if (!ecore_x_window_prop_property_get(windows[i],
atom_xmbed,
atom_xmbed, 32,
&data, &count))
data = NULL;
if (!data)
{
if (!ecore_x_window_prop_property_get(windows[i],
atom_kde_netwm_systray,
atom_xmbed, 32,
&data, &count))
data = NULL;
}
if (!data)
{
if (!ecore_x_window_prop_property_get(windows[i],
atom_kwm_dockwindow,
atom_kwm_dockwindow, 32,
&data, &count))
data = NULL;
}
if (data)
{
printf("found %x\n", windows[i]);
_itray_tray_add(itb, windows[i]);
free(data);
data = NULL;
}
}
}
}
free(windows);
}
_itray_reshape(itb);
}
void
_itray_tray_shutdown(ITray_Box *itb)
{
_itray_tray_active_set(itb, 0);
while (itb->tray->wins)
{
Ecore_X_Window win;
Ecore_X_Window_Attributes att;
win = (Ecore_X_Window)(itb->tray->wins->data);
ecore_x_window_hide(win);
ecore_x_window_reparent(win, itb->con->manager->root, 0, 0);
itb->tray->wins = evas_list_remove_list(itb->tray->wins, itb->tray->wins);
}
evas_object_del(itb->item_object);
ecore_event_handler_del(itb->tray->msg_handler);
ecore_event_handler_del(itb->tray->dst_handler);
ecore_x_window_del(itb->tray->win);
}
static void
_itray_tray_active_set(ITray_Box *itb, int active)
{
Ecore_X_Window win;
Display *display;
char buf[32];
Ecore_X_Atom selection_atom;
win = 0;
if (active)
win = itb->con->bg_win;
display = ecore_x_display_get();
snprintf(buf, sizeof(buf), "_NET_SYSTEM_TRAY_S%d", itb->con->manager->num);
selection_atom = ecore_x_atom_get(buf);
/* FIXXME: nasty xlib snippets! */
XSetSelectionOwner(display, selection_atom, win, CurrentTime);
if ((active) &&
(XGetSelectionOwner(display, selection_atom) == itb->con->bg_win))
{
printf("send message thast we own the tray now\n");
ecore_x_client_message32_send(itb->con->manager->root,
ecore_x_atom_get("MANAGER"),
ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
CurrentTime, selection_atom, win, 0, 0);
}
}
static void
_itray_tray_add(ITray_Box *itb, Ecore_X_Window win)
{
if (!win) return;
if (evas_list_find(itb->tray->wins, (void *)win))
return;
e_stolen_win_add(win);
ecore_x_window_show(itb->tray->win);
evas_object_show(itb->item_object);
/* FIXME: adding a window id AS a pointer - BAD! */
/* FIXME: need to listen for shape change events on icons */
/* FIXME: on shape change need to inherit shape */
/* properties u might find on sample windows:
*
* GDK_TIMESTAMP_PROP(GDK_TIMESTAMP_PROP) = 0x61
* _NET_WM_SYNC_REQUEST_COUNTER(CARDINAL) = 29360209
* _XEMBED_INFO(_XEMBED_INFO) = 0x1, 0x1
* WM_CLIENT_LEADER(WINDOW): window id # 0x1c00001
* _NET_WM_PID(CARDINAL) = 17802
* WM_LOCALE_NAME(STRING) = "ja_JP.UTF-8"
* WM_CLIENT_MACHINE(STRING) = "icky"
* WM_NORMAL_HINTS(WM_SIZE_HINTS):
* program specified minimum size: 24 by 24
* window gravity: NorthWest
* WM_PROTOCOLS(ATOM): protocols WM_DELETE_WINDOW, WM_TAKE_FOCUS, _NET_WM_PING, _NET_WM_SYNC_REQUEST
* WM_CLASS(STRING) = "gaim", "Gaim"
* WM_ICON_NAME(STRING) = "Gaim"
* _NET_WM_ICON_NAME(UTF8_STRING) = 0x47, 0x61, 0x69, 0x6d
* WM_NAME(STRING) = "Gaim"
* _NET_WM_NAME(UTF8_STRING) = 0x47, 0x61, 0x69, 0x6d
*---
* GDK_TIMESTAMP_PROP(GDK_TIMESTAMP_PROP) = 0x61
* _NET_WM_SYNC_REQUEST_COUNTER(CARDINAL) = 29360172
* _XEMBED_INFO(_XEMBED_INFO) = 0x1, 0x1
* WM_CLIENT_LEADER(WINDOW): window id # 0x1c00001
* _NET_WM_PID(CARDINAL) = 17841
* WM_LOCALE_NAME(STRING) = "ja_JP.UTF-8"
* WM_CLIENT_MACHINE(STRING) = "icky"
* WM_NORMAL_HINTS(WM_SIZE_HINTS):
* program specified minimum size: 16 by 16
* window gravity: NorthWest
* WM_PROTOCOLS(ATOM): protocols WM_DELETE_WINDOW, WM_TAKE_FOCUS, _NET_WM_PING, _NET_WM_SYNC_REQUEST
* WM_CLASS(STRING) = "gnomemeeting", "Gnomemeeting"
* WM_ICON_NAME(STRING) = "GnomeMeeting Tray Icon"
* _NET_WM_ICON_NAME(UTF8_STRING) = 0x47, 0x6e, 0x6f, 0x6d, 0x65, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x54, 0x72, 0x61, 0x79, 0x20, 0x49, 0x63, 0x6f, 0x6e
* WM_NAME(STRING) = "GnomeMeeting Tray Icon"
* _NET_WM_NAME(UTF8_STRING) = 0x47, 0x6e, 0x6f, 0x6d, 0x65, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x54, 0x72, 0x61, 0x79, 0x20, 0x49, 0x63, 0x6f, 0x6e
*---
* _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR(WINDOW): window id # 0x0
* KWM_DOCKWINDOW(KWM_DOCKWINDOW) = 0x0
* WM_CLIENT_LEADER(WINDOW): window id # 0x1c00006
* WM_WINDOW_ROLE(STRING) = "skypedock"
* _NET_WM_PID(CARDINAL) = 18018
* _NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
* WM_PROTOCOLS(ATOM): protocols WM_DELETE_WINDOW, WM_TAKE_FOCUS, _NET_WM_PING
* WM_NAME(STRING) = "skype"
* WM_LOCALE_NAME(STRING) = "ja_JP.UTF-8"
* WM_CLASS(STRING) = "skypedock", "Skype"
* WM_HINTS(WM_HINTS):
* Initial state is Normal State.
* bitmap id # to use for icon: 0x1c00025
* bitmap id # of mask for icon: 0x1c00026
* window id # to use for icon: 0x1c000b1
* window id # of group leader: 0x1c000b1
* WM_NORMAL_HINTS(WM_SIZE_HINTS):
* user specified size: 22 by 22
* program specified size: 22 by 22
* program specified minimum size: 22 by 22
* program specified maximum size: 22 by 22
* window gravity: NorthWest
* WM_CLIENT_MACHINE(STRING) = "icky"
*
*/
/* we want to insert at the end, so as not to move all icons on each add */
itb->tray->wins = evas_list_append(itb->tray->wins, (void *)win);
itb->tray->icons++;
ecore_x_window_client_manage(win);
ecore_x_window_resize(win, TRAY_ICON_SIZE, TRAY_ICON_SIZE);
ecore_x_window_save_set_add(win);
ecore_x_window_shape_events_select(win, 1);
ecore_x_window_reparent(win, itb->tray->win, 0, 0);
ecore_x_window_raise(itb->con->event_win);
_itray_tray_layout(itb);
_itray_box_frame_resize(itb);
ecore_x_window_show(win);
}
static void
_itray_tray_remove(ITray_Box *itb, Ecore_X_Window win)
{
if (!win)
return;
if (!evas_list_find(itb->tray->wins, (void *)win)) /* if was not found */
return;
e_stolen_win_del(win);
itb->tray->wins = evas_list_remove(itb->tray->wins, (void *)win);
itb->tray->icons--;
_itray_tray_layout(itb);
_itray_box_frame_resize(itb);
if (itb->tray->icons == 0)
{
ecore_x_window_hide(itb->tray->win);
evas_object_show(itb->item_object);
}
}
static int
_itray_tray_cb_msg(void *data, int type, void *event)
{
Ecore_X_Event_Client_Message *ev;
ITray_Box *itb;
static Ecore_X_Atom atom_opcode = 0;
static Ecore_X_Atom atom_message = 0;
static Ecore_X_Atom atom_xmbed = 0;
itb = data;
ev = event;
if (atom_opcode == 0)
atom_opcode = ecore_x_atom_get("_NET_SYSTEM_TRAY_OPCODE");
if (atom_message == 0)
atom_message = ecore_x_atom_get("_NET_SYSTEM_TRAY_MESSAGE_DATA");
if (atom_xmbed == 0)
atom_xmbed = ecore_x_atom_get("_XEMBED");
if (ev->message_type == atom_opcode)
{
if (ev->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK)
{
_itray_tray_add(itb, (Ecore_X_Window)ev->data.l[2]);
/* Should proto be set according to clients _XEMBED_INFO? */
ecore_x_client_message32_send(ev->data.l[2],
atom_xmbed,
ECORE_X_EVENT_MASK_NONE, CurrentTime,
XEMBED_EMBEDDED_NOTIFY, 0, itb->con->bg_win, /*proto*/1);
_itray_reshape(itb);
}
else if (ev->data.l[1] == SYSTEM_TRAY_BEGIN_MESSAGE)
{
printf("begin message\n");
}
else if (ev->data.l[1] == SYSTEM_TRAY_CANCEL_MESSAGE)
{
printf("cancel message\n");
}
}
else if (ev->message_type == atom_message)
{
printf("got message\n");
}
return 1;
}
static int
_itray_tray_cb_destroy(void *data, int type, void *event)
{
Ecore_X_Event_Window_Destroy *ev;
ITray_Box *itb;
int exists;
itb = data;
ev = event;
exists = _itray_exists(itb, ev->win);
_itray_tray_remove(itb, ev->win);
if (exists) _itray_reshape(itb);
return 1;
}
static int
_itray_tray_cb_hide(void *data, int type, void *event)
{
Ecore_X_Event_Window_Destroy *ev;
ITray_Box *itb;
int exists;
itb = data;
ev = event;
exists = _itray_exists(itb, ev->win);
_itray_tray_remove(itb, ev->win);
if (exists) _itray_reshape(itb);
return 1;
}
static int
_itray_tray_cb_shape(void *data, int type, void *event)
{
Ecore_X_Event_Window_Shape *ev;
ITray_Box *itb;
Evas_List *l;
itb = data;
ev = event;
if (_itray_exists(itb, ev->win)) _itray_reshape(itb);
return 1;
}
static int
_itray_exists(ITray_Box *itb, Ecore_X_Window win)
{
Evas_List *l;
for (l = itb->tray->wins; l; l = l->next)
{
Ecore_X_Window w;
w = (Ecore_X_Window)l->data;
if (w == win) return 1;
}
return 0;
}
static void
_itray_reshape(ITray_Box *itb)
{
Evas_List *l;
Ecore_X_Window twin;
int i;
printf("reshape %p win %x\n", itb, itb->tray->win);
twin = ecore_x_window_override_new(itb->tray->win, 0, 0, 100, 100);
for (i = 0, l = itb->tray->wins; l; l = l->next, i++)
{
Ecore_X_Window win;
Ecore_X_Rectangle *rects;
int num;
int x, y, w, h;
win = (Ecore_X_Window)l->data;
printf("SH%i %x\n", i, win);
ecore_x_window_geometry_get(win, &x, &y, &w, &h);
rects = ecore_x_window_shape_rectangles_get(win, &num);
if (rects)
{
printf("shaped! %i\n", num);
if (i == 0)
{
ecore_x_window_shape_window_set_xy(twin, win, x, y);
}
else
{
ecore_x_window_shape_window_add_xy(twin, win, x, y);
}
free(rects);
}
else
{
printf("not shaped!\n");
if (i == 0)
{
ecore_x_window_shape_rectangle_set(twin, x, y, w, h);
}
else
{
ecore_x_window_shape_rectangle_add(twin, x, y, w, h);
}
}
if (i > 1000) break;
}
ecore_x_window_shape_window_set(itb->tray->win, twin);
ecore_x_window_del(twin);
}
static void
_itray_tray_cb_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
{
ITray_Box *itb;
itb = data;
evas_object_move(o, x, y);
evas_object_move(itb->event_object, x, y);
ecore_x_window_move(itb->tray->win, (int) x, (int) y);
}
static void
_itray_tray_cb_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
{
ITray_Box *itb;
itb = data;
evas_object_resize(o, w, h);
evas_object_resize(itb->event_object, w, h);
_itray_tray_layout(itb);
_itray_box_frame_resize(itb);
}
static void
_itray_tray_layout(ITray_Box *itb)
{
Evas_Coord w, h, c, d;
int x, y;
Evas_List *wins;
E_Gadman_Edge edge;
if (!itb->gmc) return;
edge = e_gadman_client_edge_get(itb->gmc);
h = itb->itray->conf->rowsize * TRAY_ICON_SIZE;
if (h < TRAY_ICON_SIZE)
h = TRAY_ICON_SIZE;
c = (h - (h % TRAY_ICON_SIZE)) / TRAY_ICON_SIZE;
if (itb->tray->icons > 0 && itb->tray->icons < c + 1)
{
c = itb->tray->icons;
h = c * TRAY_ICON_SIZE;
}
w = ((itb->tray->icons + (itb->tray->icons % c)) / c) * TRAY_ICON_SIZE;
if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_TOP)
{
edje_object_part_unswallow(itb->box_object, itb->item_object);
evas_object_resize(itb->item_object, w, h);
ecore_x_window_resize(itb->tray->win, (int) w, (int) h);
edje_extern_object_min_size_set(itb->item_object, w, h);
edje_extern_object_max_size_set(itb->item_object, w, h);
edje_object_part_swallow(itb->box_object, "tray", itb->item_object);
}
else
{
edje_object_part_unswallow(itb->box_object, itb->item_object);
evas_object_resize(itb->item_object, h, w);
ecore_x_window_resize(itb->tray->win, (int) h, (int) w);
edje_extern_object_min_size_set(itb->item_object, w, h);
edje_extern_object_max_size_set(itb->item_object, w, h);
edje_object_part_swallow(itb->box_object, "tray", itb->item_object);
}
x = 0;
if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_RIGHT)
y = h - TRAY_ICON_SIZE;
else
y = 0;
d = 0;
for (wins = itb->tray->wins; wins; wins = wins->next)
{
if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_TOP)
ecore_x_window_move((Ecore_X_Window) wins->data, x, y);
else
ecore_x_window_move((Ecore_X_Window) wins->data, y, x);
d++;
if (d % c == 0)
{
x += TRAY_ICON_SIZE;
if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_RIGHT)
y = h - TRAY_ICON_SIZE;
else
y = 0;
}
else if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_RIGHT)
y -= TRAY_ICON_SIZE;
else
y += TRAY_ICON_SIZE;
}
itb->tray->rows = c;
}