systray: import widget

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2008-06-14 18:12:16 +02:00
parent 477c6eb4a1
commit e5e379656a
17 changed files with 754 additions and 29 deletions

View File

@ -38,6 +38,7 @@ WIDGETS += widgets/iconbox.c
WIDGETS += widgets/progressbar.c WIDGETS += widgets/progressbar.c
WIDGETS += widgets/tasklist.c WIDGETS += widgets/tasklist.c
WIDGETS += widgets/graph.c WIDGETS += widgets/graph.c
WIDGETS += widgets/systray.c
doc_DATA += README doc_DATA += README
@ -122,6 +123,7 @@ awesome_SOURCES = \
common/version.c common/version.h \ common/version.c common/version.h \
common/util.c common/util.h \ common/util.c common/util.h \
common/xutil.c common/xutil.h \ common/xutil.c common/xutil.h \
common/xembed.c common/xembed.h \
common/configopts.h common/configopts.c \ common/configopts.h common/configopts.c \
common/xscreen.h common/xscreen.c \ common/xscreen.h common/xscreen.c \
common/draw.c common/draw.h \ common/draw.c common/draw.h \
@ -129,6 +131,7 @@ awesome_SOURCES = \
common/list.h common/refcount.h \ common/list.h common/refcount.h \
structs.h \ structs.h \
client.c client.h \ client.c client.h \
systray.c systray.h \
titlebar.c titlebar.h \ titlebar.c titlebar.h \
placement.c placement.h \ placement.c placement.h \
focus.c focus.h \ focus.c focus.h \

View File

@ -55,6 +55,7 @@
#include "tag.h" #include "tag.h"
#include "dbus.h" #include "dbus.h"
#include "statusbar.h" #include "statusbar.h"
#include "systray.h"
#include "common/socket.h" #include "common/socket.h"
#include "common/version.h" #include "common/version.h"
#include "common/configopts.h" #include "common/configopts.h"
@ -85,6 +86,7 @@ scan()
xcb_get_geometry_cookie_t **geom_wins = NULL; xcb_get_geometry_cookie_t **geom_wins = NULL;
xcb_get_window_attributes_reply_t *attr_r; xcb_get_window_attributes_reply_t *attr_r;
xcb_get_geometry_reply_t *geom_r; xcb_get_geometry_reply_t *geom_r;
xembed_info_t eminfo;
for(screen = 0; screen < screen_max; screen++) for(screen = 0; screen < screen_max; screen++)
{ {
@ -105,8 +107,7 @@ scan()
if(!tree_r) if(!tree_r)
continue; continue;
/* Get the tree of the children Windows of the current root /* Get the tree of the children windows of the current root window */
* Window */
if(!(wins = xcb_query_tree_children(tree_r))) if(!(wins = xcb_query_tree_children(tree_r)))
eprint("E: cannot get tree children"); eprint("E: cannot get tree children");
tree_c_len = xcb_query_tree_children_length(tree_r); tree_c_len = xcb_query_tree_children_length(tree_r);
@ -153,6 +154,9 @@ scan()
real_screen = screen_get_bycoord(globalconf.screens_info, screen, real_screen = screen_get_bycoord(globalconf.screens_info, screen,
geom_r->x, geom_r->y); geom_r->x, geom_r->y);
if(xembed_info_get(globalconf.connection, wins[i], &eminfo))
systray_request_handle(wins[i], screen, &eminfo);
else
client_manage(wins[i], geom_r, real_screen); client_manage(wins[i], geom_r, real_screen);
p_delete(&geom_r); p_delete(&geom_r);

View File

@ -52,6 +52,7 @@ The current list of available widget is:
- taglist - taglist
- tasklist - tasklist
- textbox - textbox
- systray
Each widget as its own set of properties, described below, that can bet modified with the set() Each widget as its own set of properties, described below, that can bet modified with the set()
method. method.

View File

@ -97,6 +97,9 @@ mymenubox = widget.new({ type = "textbox", name = "mytextbox", align = "left" })
myiconbox = widget.new({ type = "iconbox", name = "myiconbox", align = "left" }) myiconbox = widget.new({ type = "iconbox", name = "myiconbox", align = "left" })
myiconbox:set("image", "@iconsdir@/awesome16.png") myiconbox:set("image", "@iconsdir@/awesome16.png")
-- Create a systray
mysystray = widget.new({ type = "systray", name = "mysystray", align = "right" })
-- Create an iconbox widget which will contains an icon indicating which layout we're using. -- Create an iconbox widget which will contains an icon indicating which layout we're using.
-- We need one layoutbox per screen. -- We need one layoutbox per screen.
mylayoutbox = {} mylayoutbox = {}
@ -110,18 +113,20 @@ for s = 1, screen.count() do
end end
-- Create a statusbar for each screen and add it -- Create a statusbar for each screen and add it
mystatusbar = {}
for s = 1, screen.count() do for s = 1, screen.count() do
mystatusbar = statusbar.new({ position = "top", name = "mystatusbar" .. s, mystatusbar[s] = statusbar.new({ position = "top", name = "mystatusbar" .. s,
fg = fg_normal, bg = bg_normal }) fg = fg_normal, bg = bg_normal })
-- Add widgets to the statusbar - order matters -- Add widgets to the statusbar - order matters
mystatusbar:widget_add(mytaglist) mystatusbar[s]:widget_add(mytaglist)
mystatusbar:widget_add(myiconbox) mystatusbar[s]:widget_add(myiconbox)
mystatusbar:widget_add(mytasklist) mystatusbar[s]:widget_add(mytasklist)
mystatusbar:widget_add(mymenubox) mystatusbar[s]:widget_add(mymenubox)
mystatusbar:widget_add(mytextbox) mystatusbar[s]:widget_add(mytextbox)
mystatusbar:widget_add(mylayoutbox[s]) mystatusbar[s]:widget_add(mylayoutbox[s])
mystatusbar:add(s) mystatusbar[s]:add(s)
end end
mystatusbar[screen.count()]:widget_add(mysystray)
-- }}} -- }}}
-- {{{ Mouse bindings -- {{{ Mouse bindings

164
common/xembed.c Normal file
View File

@ -0,0 +1,164 @@
/*
* common/xembed.c - XEMBED functions
*
* Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
* Copyright © 2004 Matthew Reppert
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "common/xembed.h"
#include "common/xutil.h"
#include "common/util.h"
/** Have the embedder end XEMBED protocol communication with a child.
* \param connection The X connection.
* \param child The window to unembed.
* \param root The root window to reparent to.
*/
static inline void
xembed_window_unembed(xcb_connection_t *connection, xcb_window_t child, xcb_window_t root)
{
xcb_unmap_window(connection, child);
xcb_reparent_window(connection, child, root, 0, 0);
}
/** Indicate to an embedded window that it has lost focus.
* \param c The X connection.
* \param client The client to send message to.
*/
static inline void
xembed_focus_out (xcb_connection_t *c, xcb_window_t client)
{
xembed_message_send(c, client, XEMBED_FOCUS_OUT, 0, 0, 0);
}
/** Send an XEMBED message to a window.
* \param connection Connection to the X server.
* \param towin Destination window
* \param message The message.
* \param d1 Element 3 of message.
* \param d2 Element 4 of message.
* \param d3 Element 5 of message.
*/
void
xembed_message_send(xcb_connection_t *connection, xcb_window_t towin,
long message, long d1, long d2, long d3)
{
xcb_client_message_event_t ev;
xutil_intern_atom_request_t atom_q;
xcb_atom_t atom;
/** \todo use atom cache */
atom_q = xutil_intern_atom(connection, NULL, "_XEMBED");
p_clear(&ev, 1);
ev.response_type = XCB_CLIENT_MESSAGE;
ev.window = towin;
ev.format = 32;
ev.data.data32[0] = XCB_CURRENT_TIME;
ev.data.data32[1] = message;
ev.data.data32[2] = d1;
ev.data.data32[3] = d2;
ev.data.data32[4] = d3;
atom = xutil_intern_atom_reply(connection, NULL, atom_q);
ev.type = atom;
xcb_send_event(connection, false, towin, XCB_EVENT_MASK_NO_EVENT, (char *) &ev);
}
/** Get the XEMBED info for a window.
* \param connection The X connection.
* \param win The window.
* \param info The xembed_info_t structure to fill.
*/
bool
xembed_info_get(xcb_connection_t *connection, xcb_window_t win, xembed_info_t *info)
{
xutil_intern_atom_request_t atom_q;
xcb_atom_t atom;
xcb_get_property_cookie_t prop_c;
xcb_get_property_reply_t *prop_r;
uint32_t *data;
bool ret = false;
/** \todo use atom cache */
atom_q = xutil_intern_atom(connection, NULL, "_XEMBED_INFO");
atom = xutil_intern_atom_reply(connection, NULL, atom_q);
prop_c = xcb_get_property(connection, false, win, atom, XCB_GET_PROPERTY_TYPE_ANY, 0L, 2);
prop_r = xcb_get_property_reply(connection, prop_c, NULL);
if(!prop_r || !prop_r->value_len)
goto bailout;
if(!(data = (uint32_t *) xcb_get_property_value(prop_r)))
goto bailout;
info->version = data[0];
info->flags = data[1] & XEMBED_INFO_FLAGS_ALL;
ret = true;
bailout:
p_delete(&prop_r);
return ret;
}
/** Get a XEMBED window from a xembed_window_t list.
* \param list The xembed window list.
* \param win The window to look for.
*/
xembed_window_t *
xembed_getbywin(xembed_window_t *list, xcb_window_t win)
{
xembed_window_t *n;
for(n = list; n; n = n->next)
if(win == n->win)
return n;
return NULL;
}
/** Update embedded window properties.
* \param connection The X connection.
* \param emwin The embedded window.
*/
void
xembed_property_update(xcb_connection_t *connection, xembed_window_t *emwin)
{
int flags_changed;
xembed_info_t info = { 0, 0 };
xembed_info_get(connection, emwin->win, &info);
/* test if it changed */
if(!(flags_changed = info.flags ^ emwin->info.flags))
return;
emwin->info.flags = info.flags;
if(flags_changed & XEMBED_MAPPED)
{
if(info.flags & XEMBED_MAPPED)
{
xcb_map_window(connection, emwin->win);
xembed_window_activate(connection, emwin->win);
}
else
{
xcb_unmap_window(connection, emwin->win);
xembed_window_deactivate(connection, emwin->win);
xembed_focus_out(connection, emwin->win);
}
}
}
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

144
common/xembed.h Normal file
View File

@ -0,0 +1,144 @@
/*
* common/xembed.h - XEMBED functions header
*
* Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
* Copyright © 2004 Matthew Reppert
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef AWESOME_COMMON_XEMBED_H
#define AWESOME_COMMON_XEMBED_H
#include <xcb/xcb.h>
#include <stdbool.h>
#include "common/list.h"
#include "common/util.h"
/** XEMBED information for a window.
*/
typedef struct
{
unsigned long version;
unsigned long flags;
} xembed_info_t;
typedef struct xembed_window_t xembed_window_t;
struct xembed_window_t
{
xcb_window_t win;
int phys_screen;
xembed_info_t info;
xembed_window_t *prev, *next;
};
DO_SLIST(xembed_window_t, xembed_window, p_delete)
/** The version of the XEMBED protocol that this library supports. */
#define XEMBED_VERSION 0
/** Flags for _XEMBED_INFO */
#define XEMBED_MAPPED (1 << 0)
#define XEMBED_INFO_FLAGS_ALL 1
/** XEMBED messages */
#define XEMBED_EMBEDDED_NOTIFY 0
#define XEMBED_WINDOW_ACTIVATE 1
#define XEMBED_WINDOW_DEACTIVATE 2
#define XEMBED_REQUEST_FOCUS 3
#define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_OUT 5
#define XEMBED_FOCUS_NEXT 6
#define XEMBED_FOCUS_PREV 7
/* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
#define XEMBED_MODALITY_ON 10
#define XEMBED_MODALITY_OFF 11
#define XEMBED_REGISTER_ACCELERATOR 12
#define XEMBED_UNREGISTER_ACCELERATOR 13
#define XEMBED_ACTIVATE_ACCELERATOR 14
/** Details for XEMBED_FOCUS_IN */
#define XEMBED_FOCUS_CURRENT 0
#define XEMBED_FOCUS_FIRST 1
#define XEMBED_FOCUS_LAST 2
/** Modifiers field for XEMBED_REGISTER_ACCELERATOR */
#define XEMBED_MODIFIER_SHIFT (1 << 0)
#define XEMBED_MODIFIER_CONTROL (1 << 1)
#define XEMBED_MODIFIER_ALT (1 << 2)
#define XEMBED_MODIFIER_SUPER (1 << 3)
#define XEMBED_MODIFIER_HYPER (1 << 4)
/** Flags for XEMBED_ACTIVATE_ACCELERATOR */
#define XEMBED_ACCELERATOR_OVERLOADED (1 << 0)
void xembed_message_send(xcb_connection_t *, xcb_window_t, long, long, long, long);
xembed_window_t * xembed_getbywin(xembed_window_t *, xcb_window_t);
void xembed_property_update(xcb_connection_t *, xembed_window_t *);
bool xembed_info_get(xcb_connection_t *, xcb_window_t, xembed_info_t *);
/** Indicate to an embedded window that it has focus.
* \param c The X connection.
* \param client The client.
* \param focus_type The type of focus.
*/
static inline void
xembed_focus_in (xcb_connection_t *c, xcb_window_t client, long focus_type)
{
xembed_message_send(c, client, XEMBED_FOCUS_IN, focus_type, 0, 0);
}
/** Notify a window that it has become active.
* \param c The X connection.
* \param client The window to notify.
*/
static inline void
xembed_window_activate(xcb_connection_t *c, xcb_window_t client)
{
xembed_message_send(c, client, XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
}
/** Notify a window that it has become inactive.
* \param c The X connection.
* \param client The window to notify.
*/
static inline
void xembed_window_deactivate(xcb_connection_t *c, xcb_window_t client)
{
xembed_message_send(c, client, XEMBED_WINDOW_DEACTIVATE, 0, 0, 0);
}
/** Notify a window that its embed request has been received and accepted.
* \param c The X connection.
* \param client The client to send message to.
* \param embedder The embedder window.
* \param version The version.
*/
static inline void
xembed_embedded_notify(xcb_connection_t *c,
xcb_window_t client, xcb_window_t embedder,
long version)
{
xembed_message_send(c, client, XEMBED_EMBEDDED_NOTIFY, 0, embedder, version);
}
#endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

58
event.c
View File

@ -35,6 +35,7 @@
#include "titlebar.h" #include "titlebar.h"
#include "keygrabber.h" #include "keygrabber.h"
#include "lua.h" #include "lua.h"
#include "systray.h"
#include "layouts/floating.h" #include "layouts/floating.h"
#include "common/xscreen.h" #include "common/xscreen.h"
#include "common/xutil.h" #include "common/xutil.h"
@ -313,10 +314,11 @@ event_handle_destroynotify(void *data __attribute__ ((unused)),
*/ */
int int
event_handle_enternotify(void *data __attribute__ ((unused)), event_handle_enternotify(void *data __attribute__ ((unused)),
xcb_connection_t *connection __attribute__ ((unused)), xcb_connection_t *connection,
xcb_enter_notify_event_t *ev) xcb_enter_notify_event_t *ev)
{ {
client_t *c = NULL; client_t *c;
xembed_window_t *emwin;
if(ev->mode != XCB_NOTIFY_MODE_NORMAL if(ev->mode != XCB_NOTIFY_MODE_NORMAL
|| (ev->root_x == globalconf.pointer_x || (ev->root_x == globalconf.pointer_x
@ -327,7 +329,7 @@ event_handle_enternotify(void *data __attribute__ ((unused)),
|| (c = client_getbywin(ev->event))) || (c = client_getbywin(ev->event)))
{ {
window_grabbuttons(c->win, c->phys_screen, c->buttons); window_grabbuttons(c->win, c->phys_screen, c->buttons);
/* the idea behind saving pointer_x and pointer_y is Bob Marley powered /* The idea behind saving pointer_x and pointer_y is Bob Marley powered.
* this will allow us top drop some EnterNotify events and thus not giving * this will allow us top drop some EnterNotify events and thus not giving
* focus to windows appering under the cursor without a cursor move */ * focus to windows appering under the cursor without a cursor move */
globalconf.pointer_x = ev->root_x; globalconf.pointer_x = ev->root_x;
@ -336,6 +338,10 @@ event_handle_enternotify(void *data __attribute__ ((unused)),
luaA_client_userdata_new(c); luaA_client_userdata_new(c);
luaA_dofunction(globalconf.L, globalconf.hooks.mouseover, 1); luaA_dofunction(globalconf.L, globalconf.hooks.mouseover, 1);
} }
else if((emwin = xembed_getbywin(globalconf.embedded, ev->event)))
xcb_ungrab_button(globalconf.connection, XCB_BUTTON_INDEX_ANY,
xcb_aux_get_screen(connection, emwin->phys_screen)->root,
ANY_MODIFIER);
else else
window_root_grabbuttons(); window_root_grabbuttons();
@ -442,7 +448,12 @@ event_handle_maprequest(void *data __attribute__ ((unused)),
if(wa_r->override_redirect) if(wa_r->override_redirect)
goto bailout; goto bailout;
if(!(c = client_getbywin(ev->window))) if(xembed_getbywin(globalconf.embedded, ev->window))
{
xcb_map_window(connection, ev->window);
xembed_window_activate(connection, ev->window);
}
else if(!(c = client_getbywin(ev->window)))
{ {
geom_c = xcb_get_geometry(connection, ev->window); geom_c = xcb_get_geometry(connection, ev->window);
@ -491,10 +502,13 @@ event_handle_propertynotify(void *data __attribute__ ((unused)),
{ {
client_t *c; client_t *c;
xcb_window_t trans; xcb_window_t trans;
xembed_window_t *emwin;
if(ev->state == XCB_PROPERTY_DELETE) if(ev->state == XCB_PROPERTY_DELETE)
return 0; /* ignore */ return 0; /* ignore */
if((c = client_getbywin(ev->window))) if((emwin = xembed_getbywin(globalconf.embedded, ev->window)))
xembed_property_update(connection, emwin);
else if((c = client_getbywin(ev->window)))
{ {
if(ev->atom == WM_TRANSIENT_FOR) if(ev->atom == WM_TRANSIENT_FOR)
{ {
@ -529,12 +543,12 @@ event_handle_unmapnotify(void *data __attribute__ ((unused)),
xcb_connection_t *connection, xcb_unmap_notify_event_t *ev) xcb_connection_t *connection, xcb_unmap_notify_event_t *ev)
{ {
client_t *c; client_t *c;
xembed_window_t *em;
int i;
/* /* event->send_event (Xlib) is quivalent to (ev->response_type &
* event->send_event (Xlib) is quivalent to (ev->response_type &
* 0x80) in XCB because the SendEvent bit is available in the * 0x80) in XCB because the SendEvent bit is available in the
* response_type field * response_type field */
*/
bool send_event = ((ev->response_type & 0x80) >> 7); bool send_event = ((ev->response_type & 0x80) >> 7);
if((c = client_getbywin(ev->window)) if((c = client_getbywin(ev->window))
@ -542,6 +556,14 @@ event_handle_unmapnotify(void *data __attribute__ ((unused)),
&& send_event && window_getstate(c->win) == XCB_WM_NORMAL_STATE) && send_event && window_getstate(c->win) == XCB_WM_NORMAL_STATE)
client_unmanage(c); client_unmanage(c);
/** \todo invalidate for all screen might be too much */
if((em = xembed_getbywin(globalconf.embedded, ev->window)))
{
xembed_window_list_detach(&globalconf.embedded, em);
for(i = 0; i < globalconf.screens_info->nscreen; i++)
widget_invalidate_cache(i, WIDGET_CACHE_EMBEDDED);
}
return 0; return 0;
} }
@ -604,11 +626,23 @@ event_handle_randr_screen_change_notify(void *data __attribute__ ((unused)),
*/ */
int int
event_handle_clientmessage(void *data __attribute__ ((unused)), event_handle_clientmessage(void *data __attribute__ ((unused)),
xcb_connection_t *connection __attribute__ ((unused)), xcb_connection_t *connection,
xcb_client_message_event_t *ev) xcb_client_message_event_t *ev)
{ {
ewmh_process_client_message(ev); xutil_intern_atom_request_t atom_xem_q, atom_systray_q;
return 0; xcb_atom_t atom_xem, atom_systray;
atom_xem_q = xutil_intern_atom(connection, &globalconf.atoms, "_XEMBED");
atom_systray_q = xutil_intern_atom(connection, &globalconf.atoms, "_NET_SYSTEM_TRAY_OPCODE");
atom_xem = xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms, atom_xem_q);
atom_systray = xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms, atom_systray_q);
if(ev->type == atom_xem)
return xembed_process_client_message(ev);
else if(ev->type == atom_systray)
return systray_process_client_message(ev);
return ewmh_process_client_message(ev);
} }
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

4
ewmh.c
View File

@ -381,7 +381,7 @@ ewmh_process_window_type_atom(client_t *c, xcb_atom_t state)
client_setfloating(c, true, LAYER_MODAL); client_setfloating(c, true, LAYER_MODAL);
} }
void int
ewmh_process_client_message(xcb_client_message_event_t *ev) ewmh_process_client_message(xcb_client_message_event_t *ev)
{ {
client_t *c; client_t *c;
@ -411,6 +411,8 @@ ewmh_process_client_message(xcb_client_message_event_t *ev)
ev->data.data32[0]); ev->data.data32[0]);
} }
} }
return 0;
} }
void void

2
ewmh.h
View File

@ -38,7 +38,7 @@ void ewmh_update_net_numbers_of_desktop(int);
void ewmh_update_net_current_desktop(int); void ewmh_update_net_current_desktop(int);
void ewmh_update_net_desktop_names(int); void ewmh_update_net_desktop_names(int);
void ewmh_update_net_active_window(int); void ewmh_update_net_active_window(int);
void ewmh_process_client_message(xcb_client_message_event_t *); int ewmh_process_client_message(xcb_client_message_event_t *);
void ewmh_check_client_hints(client_t *); void ewmh_check_client_hints(client_t *);
NetWMIcon * ewmh_get_window_icon(xcb_window_t); NetWMIcon * ewmh_get_window_icon(xcb_window_t);

View File

@ -377,6 +377,14 @@ luaA_statusbar_widget_add(lua_State *L)
widget_t **widget = luaA_checkudata(L, 2, "widget"); widget_t **widget = luaA_checkudata(L, 2, "widget");
widget_node_t *w = p_new(widget_node_t, 1); widget_node_t *w = p_new(widget_node_t, 1);
if((*widget)->type == systray_new)
{
if(globalconf.systray)
luaL_error(L, "system tray already added and only one is allowed");
else
globalconf.systray = *sb;
}
(*sb)->need_update = true; (*sb)->need_update = true;
w->widget = *widget; w->widget = *widget;
widget_node_list_append(&(*sb)->widgets, w); widget_node_list_append(&(*sb)->widgets, w);
@ -403,6 +411,8 @@ widget_remove_loop:
for(w = (*sb)->widgets; w; w = w->next) for(w = (*sb)->widgets; w; w = w->next)
if(w->widget == *widget) if(w->widget == *widget)
{ {
if(*sb == globalconf.systray && (*widget)->type == systray_new)
globalconf.systray = NULL;
widget_unref(widget); widget_unref(widget);
widget_node_list_detach(&(*sb)->widgets, w); widget_node_list_detach(&(*sb)->widgets, w);
p_delete(&w); p_delete(&w);

View File

@ -30,6 +30,7 @@
#include "common/draw.h" #include "common/draw.h"
#include "common/swindow.h" #include "common/swindow.h"
#include "common/xscreen.h" #include "common/xscreen.h"
#include "common/xembed.h"
#include "common/refcount.h" #include "common/refcount.h"
/** Stacking layout layers */ /** Stacking layout layers */
@ -63,6 +64,7 @@ typedef struct client_node_t client_node_t;
typedef struct _tag_t tag_t; typedef struct _tag_t tag_t;
typedef struct tag_client_node_t tag_client_node_t; typedef struct tag_client_node_t tag_client_node_t;
typedef area_t (FloatingPlacement)(client_t *); typedef area_t (FloatingPlacement)(client_t *);
typedef widget_t *(widget_constructor_t)(alignment_t);
typedef struct awesome_t awesome_t; typedef struct awesome_t awesome_t;
/** Widget tell status code */ /** Widget tell status code */
@ -102,6 +104,8 @@ struct widget_t
int refcount; int refcount;
/** widget_t name */ /** widget_t name */
char *name; char *name;
/** Widget type is constructor */
widget_constructor_t *type;
/** Draw function */ /** Draw function */
int (*draw)(draw_context_t *, int, widget_node_t *, int, int, void *); int (*draw)(draw_context_t *, int, widget_node_t *, int, int, void *);
/** Update function */ /** Update function */
@ -401,10 +405,14 @@ struct awesome_t
xcb_cursor_t cursor[CurLast]; xcb_cursor_t cursor[CurLast];
/** Clients list */ /** Clients list */
client_t *clients; client_t *clients;
/** Embedded windows */
xembed_window_t *embedded;
/** Path to config file */ /** Path to config file */
char *configpath; char *configpath;
/** Floating window placement algo */ /** Floating window placement algo */
FloatingPlacement *floating_placement; FloatingPlacement *floating_placement;
/** Statusbar that contains the systray */
statusbar_t *systray;
/** Selected clients history */ /** Selected clients history */
client_node_t *focus; client_node_t *focus;
/** Stack client history */ /** Stack client history */

121
systray.c Normal file
View File

@ -0,0 +1,121 @@
/*
* systray.c - systray handling
*
* Copyright © 2008 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <xcb/xcb.h>
#include <xcb/xcb_icccm.h>
#include "structs.h"
#include "systray.h"
#include "window.h"
#include "common/xembed.h"
#define SYSTEM_TRAY_REQUEST_DOCK 0 /* Begin icon docking */
extern awesome_t globalconf;
/** Handle a systray request.
* \param embed_win The window to embed.
*/
int
systray_request_handle(xcb_window_t embed_win, int phys_screen, xembed_info_t *info)
{
xembed_window_t *em;
const uint32_t select_input_val[] =
{
XCB_EVENT_MASK_STRUCTURE_NOTIFY
| XCB_EVENT_MASK_PROPERTY_CHANGE
| XCB_EVENT_MASK_ENTER_WINDOW
};
xcb_change_window_attributes(globalconf.connection, embed_win, XCB_CW_EVENT_MASK,
select_input_val);
window_setstate(embed_win, XCB_WM_WITHDRAWN_STATE);
em = p_new(xembed_window_t, 1);
em->win = embed_win;
em->phys_screen = phys_screen;
if(info)
em->info = *info;
else
xembed_info_get(globalconf.connection, em->win, &em->info);
xembed_window_list_append(&globalconf.embedded, em);
xembed_embedded_notify(globalconf.connection, em->win,
globalconf.systray->sw->window,
MIN(XEMBED_VERSION, em->info.version));
if(em->info.flags & XEMBED_MAPPED)
xcb_map_window(globalconf.connection, em->win);
return 0;
}
/** Handle systray message.
* \param ev The event.
* \return 0 on no error.
*/
int
systray_process_client_message(xcb_client_message_event_t *ev)
{
int screen_nbr = 0;
xcb_get_geometry_cookie_t geom_c;
xcb_get_geometry_reply_t *geom_r;
xcb_screen_iterator_t iter;
switch(ev->data.data32[1])
{
case SYSTEM_TRAY_REQUEST_DOCK:
geom_c = xcb_get_geometry(globalconf.connection, ev->window);
if(!(geom_r = xcb_get_geometry_reply(globalconf.connection, geom_c, NULL)))
return -1;
for(iter = xcb_setup_roots_iterator(xcb_get_setup(globalconf.connection)), screen_nbr = 0;
iter.rem && iter.data->root != geom_r->root; xcb_screen_next (&iter), ++screen_nbr);
p_delete(&geom_r);
systray_request_handle(ev->data.data32[2], screen_nbr, NULL);
break;
}
return 0;
}
/** Handle xembed client message.
* \param ev The event.
* \return 0 on no error.
*/
int
xembed_process_client_message(xcb_client_message_event_t *ev)
{
switch(ev->data.data32[1])
{
case XEMBED_REQUEST_FOCUS:
xembed_focus_in(globalconf.connection, ev->window, XEMBED_FOCUS_CURRENT);
break;
}
return 0;
}
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

33
systray.h Normal file
View File

@ -0,0 +1,33 @@
/*
* systray.h - systray handlers header
*
* Copyright © 2008 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef AWESOME_SYSTRAY_H
#define AWESOME_SYSTRAY_H
#include <xcb/xcb.h>
#include "common/xembed.h"
int systray_request_handle(xcb_window_t, int, xembed_info_t *);
int systray_process_client_message(xcb_client_message_event_t *);
int xembed_process_client_message(xcb_client_message_event_t *);
#endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -453,6 +453,9 @@ luaA_titlebar_widget_add(lua_State *L)
widget_node_t *w = p_new(widget_node_t, 1); widget_node_t *w = p_new(widget_node_t, 1);
client_t *c; client_t *c;
if((*widget)->type == systray_new)
luaL_error(L, "cannot add systray widget to titlebar");
w->widget = *widget; w->widget = *widget;
widget_node_list_append(&(*tb)->widgets, w); widget_node_list_append(&(*tb)->widgets, w);
widget_ref(widget); widget_ref(widget);

View File

@ -337,6 +337,8 @@ luaA_widget_new(lua_State *L)
else else
luaL_error(L, "unkown widget type: %s", type); luaL_error(L, "unkown widget type: %s", type);
w->type = wc;
/* Set visible by default. */ /* Set visible by default. */
w->isvisible = true; w->isvisible = true;

View File

@ -28,9 +28,7 @@
#define WIDGET_CACHE_CLIENTS (1<<0) #define WIDGET_CACHE_CLIENTS (1<<0)
#define WIDGET_CACHE_LAYOUTS (1<<1) #define WIDGET_CACHE_LAYOUTS (1<<1)
#define WIDGET_CACHE_TAGS (1<<2) #define WIDGET_CACHE_TAGS (1<<2)
#define WIDGET_CACHE_ALL (WIDGET_CACHE_CLIENTS | WIDGET_CACHE_LAYOUTS | WIDGET_CACHE_TAGS) #define WIDGET_CACHE_EMBEDDED (1<<3)
typedef widget_t *(widget_constructor_t)(alignment_t);
void widget_invalidate_cache(int, int); void widget_invalidate_cache(int, int);
int widget_calculate_offset(int, int, int, int); int widget_calculate_offset(int, int, int, int);
@ -47,6 +45,7 @@ widget_constructor_t iconbox_new;
widget_constructor_t progressbar_new; widget_constructor_t progressbar_new;
widget_constructor_t graph_new; widget_constructor_t graph_new;
widget_constructor_t tasklist_new; widget_constructor_t tasklist_new;
widget_constructor_t systray_new;
#endif #endif

192
widgets/systray.c Normal file
View File

@ -0,0 +1,192 @@
/*
* systray.c - systray widget
*
* Copyright © 2008 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <xcb/xcb.h>
#include "widget.h"
#include "common/xembed.h"
extern awesome_t globalconf;
typedef struct
{
bool init;
} systray_data_t;
static bool
systray_init(void)
{
xutil_intern_atom_request_t atom_systray_q, atom_manager_q;
xcb_atom_t atom_systray;
xcb_client_message_event_t ev;
char atom_name[22];
/* Send requests */
atom_manager_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, atom_name);
snprintf(atom_name, sizeof(atom_name), "_NET_SYSTEM_TRAY_S%d", globalconf.default_screen);
atom_systray_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, atom_name);
/* Fill event */
ev.format = 32;
ev.data.data32[0] = XCB_CURRENT_TIME;
ev.data.data32[2] = globalconf.systray->sw->window;
ev.data.data32[3] = ev.data.data32[4] = 0;
ev.response_type = xutil_intern_atom_reply(globalconf.connection,
&globalconf.atoms, atom_manager_q);
ev.data.data32[1] = atom_systray = xutil_intern_atom_reply(globalconf.connection,
&globalconf.atoms,
atom_systray_q);
xcb_set_selection_owner(globalconf.connection,
globalconf.systray->sw->window,
atom_systray,
XCB_CURRENT_TIME);
return true;
}
static int
systray_draw(draw_context_t *ctx,
int screen __attribute__ ((unused)),
widget_node_t *w,
int offset, int used __attribute__ ((unused)),
void *p __attribute__ ((unused)))
{
int i = 0;
xembed_window_t *em;
uint32_t config_win_vals[6];
systray_data_t *d = w->widget->data;
if(!d->init)
d->init = systray_init();
for(em = globalconf.embedded; em; em = em->next)
i++;
if(ctx->width - used > 0)
w->area.width = MIN(i * ctx->height, ctx->width - used);
else
w->area.width = 0;
w->area.height = ctx->height;
w->area.x = widget_calculate_offset(ctx->width,
w->area.width,
offset,
w->widget->align);
w->area.y = 0;
/* width */
config_win_vals[2] = w->area.height;
/* height */
config_win_vals[3] = w->area.height;
/* sibling */
config_win_vals[4] = globalconf.systray->sw->window;
/* stack mode */
config_win_vals[5] = XCB_STACK_MODE_ABOVE;
switch(globalconf.systray->position)
{
case Left:
config_win_vals[0] = globalconf.systray->sw->geometry.x + w->area.y;
config_win_vals[1] = globalconf.systray->sw->geometry.y + globalconf.systray->sw->geometry.height
- w->area.x - config_win_vals[3];
for(em = globalconf.embedded; em; em = em->next)
if(config_win_vals[1] - config_win_vals[2] >= (uint32_t) globalconf.systray->sw->geometry.y)
{
xcb_map_window(globalconf.connection, em->win);
xcb_configure_window(globalconf.connection, em->win,
XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
| XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE,
config_win_vals);
config_win_vals[1] -= config_win_vals[3];
}
else
xcb_unmap_window(globalconf.connection, em->win);
break;
case Right:
config_win_vals[0] = globalconf.systray->sw->geometry.x - w->area.y;
config_win_vals[1] = globalconf.systray->sw->geometry.y + w->area.x;
for(em = globalconf.embedded; em; em = em->next)
if(config_win_vals[1] + config_win_vals[3] <= (uint32_t) globalconf.systray->sw->geometry.y + ctx->width)
{
xcb_map_window(globalconf.connection, em->win);
xcb_configure_window(globalconf.connection, em->win,
XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
| XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE,
config_win_vals);
config_win_vals[1] += config_win_vals[3];
}
else
xcb_unmap_window(globalconf.connection, em->win);
break;
default:
/* x */
config_win_vals[0] = globalconf.systray->sw->geometry.x + w->area.x;
/* y */
config_win_vals[1] = globalconf.systray->sw->geometry.y + w->area.y;
for(em = globalconf.embedded; em; em = em->next)
/* if(x + width < systray.x + systray.width) */
if(config_win_vals[0] + config_win_vals[2] <= (uint32_t) AREA_RIGHT(w->area) + globalconf.systray->sw->geometry.x)
{
xcb_map_window(globalconf.connection, em->win);
xcb_configure_window(globalconf.connection, em->win,
XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
| XCB_CONFIG_WINDOW_SIBLING
| XCB_CONFIG_WINDOW_STACK_MODE,
config_win_vals);
config_win_vals[0] += config_win_vals[2];
}
else
xcb_unmap_window(globalconf.connection, em->win);
break;
}
return w->area.width;
}
widget_t *
systray_new(alignment_t align)
{
widget_t *w;
w = p_new(widget_t, 1);
widget_common_new(w);
w->align = align;
w->draw = systray_draw;
w->cache_flags = WIDGET_CACHE_EMBEDDED;
w->data = p_new(systray_data_t, 1);
return w;
}
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80