enlightenment-module-engage/tray.c

330 lines
8.5 KiB
C

#include <e.h>
#include "e_mod_main.h"
#include "Ecore_X.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
#define XEMBED_EMBEDDED_NOTIFY 0
static int _engage_tray_cb_msg(void *data, int type, void *event);
void _engage_tray_active_set(Engage_Bar *eb, int active);
static void _engage_tray_cb_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y);
static void _engage_tray_cb_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h);
void _engage_tray_layout(Engage_Bar *eb);
void _engage_tray_freeze(Engage_Bar *eb);
void _engage_tray_thaw(Engage_Bar *eb);
extern void _engage_bar_frame_resize(Engage_Bar *eb);
void
_engage_tray_init(Engage_Bar *eb)
{
/* FIXME - temp */
eb->tray = malloc(sizeof(Engage_Tray));
eb->tray->icons = 0;
eb->tray->w = 1;
eb->tray->h = 1;
eb->tray->wins = NULL;
eb->tray->tray = evas_object_rectangle_add(eb->evas);
eb->tray->msg_handler = NULL;
eb->tray->dst_handler = NULL;
eb->tray->win = 0;
evas_object_resize(eb->tray->tray, eb->tray->w, eb->tray->h);
evas_object_color_set(eb->tray->tray, 180, 0, 0, 255);
evas_object_show(eb->tray->tray);
_engage_tray_thaw(eb);
edje_object_part_swallow(eb->bar_object, "tray", eb->tray->tray);
_engage_tray_active_set(eb, eb->conf->tray);
}
void
_engage_tray_shutdown(Engage_Bar *eb)
{
_engage_tray_freeze(eb);
edje_object_part_unswallow(eb->bar_object, eb->tray->tray);
_engage_tray_active_set(eb, 0);
evas_list_free(eb->tray->wins);
evas_object_del(eb->tray->tray);
free(eb->tray);
eb->tray = NULL;
}
void
_engage_tray_active_set(Engage_Bar *eb, int active)
{
Ecore_X_Window win;
Display *display;
Window root;
char buf[32];
Atom selection_atom;
Evas_Coord x, y, w, h;
Ecore_X_Time time;
win = 0;
if (active)
{
win = eb->con->bg_win;
time = ecore_x_current_time_get();
eb->tray->select_time = time;
}
else
{
time = eb->tray->select_time;
}
display = ecore_x_display_get();
root = RootWindow (display, DefaultScreen(display));
snprintf(buf, sizeof(buf), "_NET_SYSTEM_TRAY_S%d", DefaultScreen(display));
selection_atom = ecore_x_atom_get(buf);
XSetSelectionOwner (display, selection_atom, win, time);
if (active &&
XGetSelectionOwner (display, selection_atom) == eb->con->bg_win)
{
printf("am a system tray :) :)\n");
ecore_x_client_message32_send(root, ecore_x_atom_get("MANAGER"),
ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
CurrentTime, selection_atom, win, 0, 0);
evas_object_geometry_get(eb->tray->tray, &x, &y, &w, &h);
if (w < 1) w = 1;
if (h < 1) h = 1;
eb->tray->win = ecore_x_window_new(eb->con->bg_win, x, y, w, h);
ecore_x_window_container_manage(eb->tray->win);
ecore_x_window_background_color_set(eb->tray->win, 0xcccc, 0xcccc, 0xcccc);
eb->tray->msg_handler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _engage_tray_cb_msg, eb);
eb->tray->dst_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, _engage_tray_cb_msg, eb);
}
else
{
if (eb->tray->msg_handler)
ecore_event_handler_del(eb->tray->msg_handler);
if (eb->tray->dst_handler)
ecore_event_handler_del(eb->tray->dst_handler);
if (eb->tray->win)
ecore_x_window_del(eb->tray->win);
}
}
void
_engage_tray_freeze(Engage_Bar *eb)
{
if (!eb->tray)
return;
evas_object_intercept_move_callback_del(eb->tray->tray, _engage_tray_cb_move);
evas_object_intercept_resize_callback_del(eb->tray->tray, _engage_tray_cb_resize);
}
void
_engage_tray_thaw(Engage_Bar *eb)
{
if (!eb->tray)
return;
evas_object_intercept_move_callback_add(eb->tray->tray, _engage_tray_cb_move, eb);
evas_object_intercept_resize_callback_add(eb->tray->tray, _engage_tray_cb_resize, eb);
}
static void
_engage_tray_add(Engage_Bar *eb, Ecore_X_Window win)
{
if (!eb->conf->tray)
return;
if (evas_list_find(eb->tray->wins, (void *)win))
return;
ecore_x_window_show(eb->tray->win);
/* we want to insert at the end, so as not to move all icons on each add */
eb->tray->wins = evas_list_append(eb->tray->wins, (void *)win);
eb->tray->icons++;
ecore_x_window_resize(win, 24, 24);
ecore_x_window_reparent(win, eb->tray->win, 0, 0);
_engage_tray_layout(eb);
_engage_bar_frame_resize(eb);
ecore_x_window_show(win);
}
static void
_engage_tray_remove(Engage_Bar *eb, Ecore_X_Window win) {
if (!eb->conf->tray)
return;
if (!win)
return;
if (!evas_list_find(eb->tray->wins, (void *)win)) /* if was not found */
return;
eb->tray->wins = evas_list_remove(eb->tray->wins, (void *)win);
eb->tray->icons--;
_engage_tray_layout(eb);
_engage_bar_frame_resize(eb);
if (eb->tray->icons == 0)
ecore_x_window_hide(eb->tray->win);
}
static int
_engage_tray_cb_msg(void *data, int type, void *event)
{
Ecore_X_Event_Client_Message *ev;
Ecore_X_Event_Window_Destroy *dst;
Engage_Bar *eb;
eb = data;
if (!eb->conf->tray)
return 1;
if (type == ECORE_X_EVENT_CLIENT_MESSAGE) {
ev = event;
if (ev->message_type == ecore_x_atom_get("_NET_SYSTEM_TRAY_OPCODE")) {
_engage_tray_add(eb, (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], ecore_x_atom_get("_XEMBED"),
ECORE_X_EVENT_MASK_NONE, CurrentTime,
XEMBED_EMBEDDED_NOTIFY, 0, eb->con->bg_win, /*proto*/1);
} else if (ev->message_type == ecore_x_atom_get("_NET_SYSTEM_TRAY_MESSAGE_DATA")) {
printf("got message\n");
}
} else if (type == ECORE_X_EVENT_WINDOW_DESTROY) {
dst = event;
_engage_tray_remove(eb, (Ecore_X_Window) dst->win);
}
return 1;
}
static void
_engage_tray_cb_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
{
Engage_Bar *eb;
eb = data;
evas_object_move(o, x, y);
if (eb->conf->tray)
ecore_x_window_move(eb->tray->win, (int) x, (int) y);
}
static void
_engage_tray_cb_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
{
Engage_Bar *eb;
eb = data;
evas_object_resize(o, w, h);
_engage_tray_layout(eb);
}
void
_engage_tray_layout(Engage_Bar *eb)
{
Evas_Coord w, h, c, d;
int x, y;
Evas_List *wins;
E_Gadman_Edge edge;
if (!eb->gmc || !eb->conf || !eb->tray)
return;
edge = e_gadman_client_edge_get(eb->gmc);
if (!eb->conf->tray)
{
int w, h;
if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_TOP)
{
w = 0;
h = eb->conf->iconsize;
}
else
{
w = eb->conf->iconsize;
h = 0;
}
edje_object_part_unswallow(eb->bar_object, eb->tray->tray);
evas_object_resize(eb->tray->tray, w, h);
edje_extern_object_min_size_set(eb->tray->tray, w, h);
edje_extern_object_max_size_set(eb->tray->tray, w, h);
edje_object_part_swallow(eb->bar_object, "tray", eb->tray->tray);
return;
}
h = eb->conf->iconsize;
if (h < 24)
h = 24;
c = (h - (h % 24)) / 24;
w = (eb->tray->icons / c);
if ((eb->tray->icons % c) != 0)
w++;
w *= 24;
_engage_tray_freeze(eb);
edje_object_part_unswallow(eb->bar_object, eb->tray->tray);
if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_TOP) {
evas_object_resize(eb->tray->tray, w, h);
ecore_x_window_resize(eb->tray->win, (int) w, (int) h);
edje_extern_object_min_size_set(eb->tray->tray, w, h);
edje_extern_object_max_size_set(eb->tray->tray, w, h);
} else {
evas_object_resize(eb->tray->tray, h, w);
ecore_x_window_resize(eb->tray->win, (int) h, (int) w);
edje_extern_object_min_size_set(eb->tray->tray, h, w);
edje_extern_object_max_size_set(eb->tray->tray, h, w);
}
_engage_tray_thaw(eb);
edje_object_part_swallow(eb->bar_object, "tray", eb->tray->tray);
x = 0;
if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_RIGHT)
y = h - 24;
else
y = 0;
d = 0;
for (wins = eb->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 += 24;
if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_RIGHT)
y = h - 24;
else
y = 0;
} else
if (edge == E_GADMAN_EDGE_BOTTOM || edge == E_GADMAN_EDGE_RIGHT)
y -= 24;
else
y += 24;
}
}