Add systray
This commit is contained in:
parent
59c1200fde
commit
2004e5dddf
5
bar.h
5
bar.h
|
@ -12,8 +12,9 @@
|
||||||
*/
|
*/
|
||||||
static const BarRule barrules[] = {
|
static const BarRule barrules[] = {
|
||||||
/* monitor bar alignment widthfunc drawfunc clickfunc name */
|
/* monitor bar alignment widthfunc drawfunc clickfunc name */
|
||||||
{ -1, 0, BAR_ALIGN_RIGHT, width_tags, draw_tags, click_tags, "tags" },
|
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||||
{ 'A', 0, BAR_ALIGN_LEFT, width_status, draw_status, click_status, "status" },
|
//{ 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||||
|
{ 'A', 0, BAR_ALIGN_RIGHT, width_systray, draw_systray, click_systray, "systray" },
|
||||||
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
/* Todo: fill this with shit */
|
#include "../toggle.h"
|
||||||
#include "tags.c"
|
#include "tags.c"
|
||||||
#include "layoutindicator.c"
|
#include "layoutindicator.c"
|
||||||
#include "statusbar.c"
|
#include "statusbar.c"
|
||||||
#include "title.c"
|
#include "title.c"
|
||||||
|
#if USESYSTRAY
|
||||||
|
#include "systray.c"
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
/* Todo: fill this with shit */
|
#include "../toggle.h"
|
||||||
#include "tags.h"
|
#include "tags.h"
|
||||||
#include "layoutindicator.h"
|
#include "layoutindicator.h"
|
||||||
#include "statusbar.h"
|
#include "statusbar.h"
|
||||||
#include "title.h"
|
#include "title.h"
|
||||||
|
#if USESYSTRAY
|
||||||
|
#include "systray.h"
|
||||||
|
#endif
|
||||||
|
|
178
bar/systray.c
Normal file
178
bar/systray.c
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
static Systray *systray = NULL;
|
||||||
|
static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
|
||||||
|
|
||||||
|
int
|
||||||
|
width_systray(Bar *bar, BarWidthArg *a)
|
||||||
|
{
|
||||||
|
unsigned int w = 0;
|
||||||
|
Client *i;
|
||||||
|
if (!systray)
|
||||||
|
return 1;
|
||||||
|
if (!hidesystray)
|
||||||
|
for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next);
|
||||||
|
return w ? w + lrpad - systrayspacing : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
draw_systray(Bar *bar, BarDrawArg *a)
|
||||||
|
{
|
||||||
|
if (hidesystray) {
|
||||||
|
if (systray)
|
||||||
|
XMoveWindow(dpy, systray->win, -500, bar->by);
|
||||||
|
return a->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
XSetWindowAttributes wa;
|
||||||
|
Client *i;
|
||||||
|
unsigned int w;
|
||||||
|
|
||||||
|
if (!systray) {
|
||||||
|
/* init systray */
|
||||||
|
if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
|
||||||
|
die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
|
||||||
|
|
||||||
|
wa.override_redirect = True;
|
||||||
|
wa.event_mask = ButtonPressMask|ExposureMask;
|
||||||
|
wa.border_pixel = 0;
|
||||||
|
wa.background_pixel = 0;
|
||||||
|
wa.colormap = cmap;
|
||||||
|
systray->win = XCreateWindow(dpy, root, bar->bx + a->x + lrpad / 2, bar->by, MAX(a->w + 40, 1), bar->bh, 0, depth,
|
||||||
|
InputOutput, visual,
|
||||||
|
CWOverrideRedirect|CWBorderPixel|CWBackPixel|CWColormap|CWEventMask, &wa); // CWBackPixmap
|
||||||
|
|
||||||
|
XSelectInput(dpy, systray->win, SubstructureNotifyMask);
|
||||||
|
XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
|
||||||
|
PropModeReplace, (unsigned char *)&systrayorientation, 1);
|
||||||
|
XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32,
|
||||||
|
PropModeReplace, (unsigned char *)&visual->visualid, 1);
|
||||||
|
XChangeProperty(dpy, systray->win, netatom[NetWMWindowType], XA_ATOM, 32,
|
||||||
|
PropModeReplace, (unsigned char *)&netatom[NetWMWindowTypeDock], 1);
|
||||||
|
XMapRaised(dpy, systray->win);
|
||||||
|
XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
|
||||||
|
if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
|
||||||
|
sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
|
||||||
|
XSync(dpy, False);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "speedwm: unable to obtain system tray.\n");
|
||||||
|
free(systray);
|
||||||
|
systray = NULL;
|
||||||
|
return a->x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
systray->bar = bar;
|
||||||
|
|
||||||
|
drw_setscheme(drw, scheme[SchemeSystray]);
|
||||||
|
for (w = 0, i = systray->icons; i; i = i->next) {
|
||||||
|
wa.background_pixel = 0;
|
||||||
|
XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
|
||||||
|
XMapRaised(dpy, i->win);
|
||||||
|
i->x = w;
|
||||||
|
XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
|
||||||
|
w += i->w;
|
||||||
|
if (i->next)
|
||||||
|
w += systrayspacing;
|
||||||
|
if (i->mon != bar->mon)
|
||||||
|
i->mon = bar->mon;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMoveResizeWindow(dpy, systray->win, bar->bx + a->x + lrpad / 2, (w ? bar->by : -bar->by), MAX(w, 1), bar->bh);
|
||||||
|
return a->x + a->w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
click_systray(Bar *bar, Arg *arg, BarClickArg *a)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
removesystrayicon(Client *i)
|
||||||
|
{
|
||||||
|
Client **ii;
|
||||||
|
|
||||||
|
if (hidesystray || !i)
|
||||||
|
return;
|
||||||
|
for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
|
||||||
|
if (ii)
|
||||||
|
*ii = i->next;
|
||||||
|
free(i);
|
||||||
|
drawbarwin(systray->bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
resizerequest(XEvent *e)
|
||||||
|
{
|
||||||
|
XResizeRequestEvent *ev = &e->xresizerequest;
|
||||||
|
Client *i;
|
||||||
|
|
||||||
|
if ((i = wintosystrayicon(ev->window))) {
|
||||||
|
updatesystrayicongeom(i, ev->width, ev->height);
|
||||||
|
drawbarwin(systray->bar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
updatesystrayicongeom(Client *i, int w, int h)
|
||||||
|
{
|
||||||
|
if (i) {
|
||||||
|
i->h = bh;
|
||||||
|
if (w == h)
|
||||||
|
i->w = bh;
|
||||||
|
else if (h == bh)
|
||||||
|
i->w = w;
|
||||||
|
else
|
||||||
|
i->w = (int) ((float)bh * ((float)w / (float)h));
|
||||||
|
applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
|
||||||
|
/* force icons into the systray dimensions if they don't want to */
|
||||||
|
if (i->h > bh) {
|
||||||
|
if (i->w == i->h)
|
||||||
|
i->w = bh;
|
||||||
|
else
|
||||||
|
i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
|
||||||
|
i->h = bh;
|
||||||
|
}
|
||||||
|
if (i->w > 2*bh)
|
||||||
|
i->w = bh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
updatesystrayiconstate(Client *i, XPropertyEvent *ev)
|
||||||
|
{
|
||||||
|
long flags;
|
||||||
|
int code = 0;
|
||||||
|
|
||||||
|
if (hidesystray || !systray || !i || ev->atom != xatom[XembedInfo] ||
|
||||||
|
!(flags = getatomprop(i, xatom[XembedInfo])))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (flags & XEMBED_MAPPED && !i->tags) {
|
||||||
|
i->tags = 1;
|
||||||
|
code = XEMBED_WINDOW_ACTIVATE;
|
||||||
|
XMapRaised(dpy, i->win);
|
||||||
|
setclientstate(i, NormalState);
|
||||||
|
}
|
||||||
|
else if (!(flags & XEMBED_MAPPED) && i->tags) {
|
||||||
|
i->tags = 0;
|
||||||
|
code = XEMBED_WINDOW_DEACTIVATE;
|
||||||
|
XUnmapWindow(dpy, i->win);
|
||||||
|
setclientstate(i, WithdrawnState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
|
||||||
|
systray->win, XEMBED_EMBEDDED_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
Client *
|
||||||
|
wintosystrayicon(Window w)
|
||||||
|
{
|
||||||
|
if (!systray)
|
||||||
|
return NULL;
|
||||||
|
Client *i = NULL;
|
||||||
|
if (hidesystray || !w)
|
||||||
|
return i;
|
||||||
|
for (i = systray->icons; i && i->win != w; i = i->next);
|
||||||
|
return i;
|
||||||
|
}
|
41
bar/systray.h
Normal file
41
bar/systray.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#define SYSTEM_TRAY_REQUEST_DOCK 0
|
||||||
|
#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
|
||||||
|
|
||||||
|
/* XEMBED messages */
|
||||||
|
#define XEMBED_EMBEDDED_NOTIFY 0
|
||||||
|
#define XEMBED_WINDOW_ACTIVATE 1
|
||||||
|
#define XEMBED_FOCUS_IN 4
|
||||||
|
#define XEMBED_MODALITY_ON 10
|
||||||
|
|
||||||
|
#define XEMBED_MAPPED (1 << 0)
|
||||||
|
#define XEMBED_WINDOW_ACTIVATE 1
|
||||||
|
#define XEMBED_WINDOW_DEACTIVATE 2
|
||||||
|
|
||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 0
|
||||||
|
#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
|
||||||
|
|
||||||
|
/* enums */
|
||||||
|
enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
|
||||||
|
|
||||||
|
typedef struct Systray Systray;
|
||||||
|
struct Systray {
|
||||||
|
Window win;
|
||||||
|
Client *icons;
|
||||||
|
Bar *bar;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* bar integration */
|
||||||
|
static int width_systray(Bar *bar, BarWidthArg *a);
|
||||||
|
static int draw_systray(Bar *bar, BarDrawArg *a);
|
||||||
|
static int click_systray(Bar *bar, Arg *arg, BarClickArg *a);
|
||||||
|
|
||||||
|
/* function declarations */
|
||||||
|
static Atom getatomprop(Client *c, Atom prop);
|
||||||
|
static void removesystrayicon(Client *i);
|
||||||
|
static void resizerequest(XEvent *e);
|
||||||
|
static void updatesystrayicongeom(Client *i, int w, int h);
|
||||||
|
static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
|
||||||
|
static void togglesystray();
|
||||||
|
static Client *wintosystrayicon(Window w);
|
||||||
|
|
|
@ -22,7 +22,7 @@ speedwm.bar.hide.floating: 0 ! Hide the floating window indicator (0/
|
||||||
speedwm.bar.hide.layout: 0 ! Hide the layout indicator (0/1)
|
speedwm.bar.hide.layout: 0 ! Hide the layout indicator (0/1)
|
||||||
speedwm.bar.hide.sticky: 0 ! Hide the sticky indicator (0/1)
|
speedwm.bar.hide.sticky: 0 ! Hide the sticky indicator (0/1)
|
||||||
speedwm.bar.hide.status: 0 ! Hide the status bar (0/1)
|
speedwm.bar.hide.status: 0 ! Hide the status bar (0/1)
|
||||||
speedwm.bar.hide.systray: 1 ! Hide the systray (0/1)
|
speedwm.bar.hide.systray: 0 ! Hide the systray (0/1)
|
||||||
speedwm.bar.hide.title: 0 ! Hide the window title (0/1)
|
speedwm.bar.hide.title: 0 ! Hide the window title (0/1)
|
||||||
speedwm.bar.hide.unseltitle: 0 ! Hide the unselected window title (0/1)
|
speedwm.bar.hide.unseltitle: 0 ! Hide the unselected window title (0/1)
|
||||||
speedwm.bar.hide.icon: 0 ! Hide the window icon (0/1)
|
speedwm.bar.hide.icon: 0 ! Hide the window icon (0/1)
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
- 58 - Remove the scratchpad
|
- 58 - Remove the scratchpad
|
||||||
- 59 - Reset layout/mfact
|
- 59 - Reset layout/mfact
|
||||||
- 60 - Reset mastercount
|
- 60 - Reset mastercount
|
||||||
- 61 - Show/Hide systray
|
- 61 - Unused
|
||||||
- 62 - Hide all windows
|
- 62 - Hide all windows
|
||||||
- 63 - Show all windows
|
- 63 - Show all windows
|
||||||
- 64 - Reset mfact
|
- 64 - Reset mfact
|
||||||
|
|
|
@ -79,11 +79,6 @@ static Key keys[] = {
|
||||||
{ MODIFIER1|CONTROL|SHIFT, -1, XK_b, spawn, cmd( "speedwm-btctrl" ) },
|
{ MODIFIER1|CONTROL|SHIFT, -1, XK_b, spawn, cmd( "speedwm-btctrl" ) },
|
||||||
{ MODIFIER1|CONTROL|SHIFT, -1, XK_r, spawn, cmd( "libspeedwm --perform core_wm_restart; speedwm -s 'Loading'" ) },
|
{ MODIFIER1|CONTROL|SHIFT, -1, XK_r, spawn, cmd( "libspeedwm --perform core_wm_restart; speedwm -s 'Loading'" ) },
|
||||||
|
|
||||||
/* System tray */
|
|
||||||
#if USESYSTRAY
|
|
||||||
{ MODIFIER1, -1, XK_s, togglesystray, {0} },
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Switcher */
|
/* Switcher */
|
||||||
#if USESWITCHER
|
#if USESWITCHER
|
||||||
{ MODIFIER1, -1, XK_Tab, switcherstart, {0} },
|
{ MODIFIER1, -1, XK_Tab, switcherstart, {0} },
|
||||||
|
|
|
@ -143,7 +143,7 @@ static int hideunselectedtitle = 0; /* Hide unselected title (1)
|
||||||
static int hidestatus = 0; /* Hide status bar (1) or show (0) */
|
static int hidestatus = 0; /* Hide status bar (1) or show (0) */
|
||||||
static int hideicon = 0; /* Hide icon (1) or show (0) */
|
static int hideicon = 0; /* Hide icon (1) or show (0) */
|
||||||
static int hidetags = 0; /* Hide status bar (1) or show (0) */
|
static int hidetags = 0; /* Hide status bar (1) or show (0) */
|
||||||
static int hidesystray = 1; /* Hide systray by default (1) or show (0) */
|
static int hidesystray = 0; /* Hide systray by default (1) or show (0) */
|
||||||
static int hideemptytags = 1; /* Hide empty tags (1) or show (0) */
|
static int hideemptytags = 1; /* Hide empty tags (1) or show (0) */
|
||||||
static int hidetagpowerline = 0; /* Hide tag powerline (1) or show (0) */
|
static int hidetagpowerline = 0; /* Hide tag powerline (1) or show (0) */
|
||||||
static int hidetitlepowerline = 0; /* Hide title powerline (1) or show (0) */
|
static int hidetitlepowerline = 0; /* Hide title powerline (1) or show (0) */
|
||||||
|
|
3
signal.h
3
signal.h
|
@ -67,9 +67,6 @@ static Signal signals[] = {
|
||||||
{ 58, scratchpad_remove, {0} },
|
{ 58, scratchpad_remove, {0} },
|
||||||
{ 59, reset_layout, {0} },
|
{ 59, reset_layout, {0} },
|
||||||
{ 60, resetmastercount, {0} },
|
{ 60, resetmastercount, {0} },
|
||||||
#if USESYSTRAY
|
|
||||||
{ 61, togglesystray, {0} },
|
|
||||||
#endif
|
|
||||||
{ 62, hideall, {0} },
|
{ 62, hideall, {0} },
|
||||||
{ 63, showall, {0} },
|
{ 63, showall, {0} },
|
||||||
{ 64, reset_mfact, {0} },
|
{ 64, reset_mfact, {0} },
|
||||||
|
|
252
speedwm.c
252
speedwm.c
|
@ -104,6 +104,10 @@ enum { NetSupported, NetWMName,
|
||||||
NetWMWindowTypeDialog, NetClientList, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop,
|
NetWMWindowTypeDialog, NetClientList, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop,
|
||||||
#if USEFADE
|
#if USEFADE
|
||||||
NetWMWindowsOpacity,
|
NetWMWindowsOpacity,
|
||||||
|
#endif
|
||||||
|
#if USESYSTRAY
|
||||||
|
NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
|
||||||
|
NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz,
|
||||||
#endif
|
#endif
|
||||||
NetClientListStacking, NetClientInfo, NetLast }; /* EWMH atoms */
|
NetClientListStacking, NetClientInfo, NetLast }; /* EWMH atoms */
|
||||||
|
|
||||||
|
@ -460,10 +464,13 @@ static Atom getatomprop(Client *c, Atom prop);
|
||||||
static int getrootptr(int *x, int *y);
|
static int getrootptr(int *x, int *y);
|
||||||
static long getstate(Window w);
|
static long getstate(Window w);
|
||||||
static unsigned int getsystraywidth();
|
static unsigned int getsystraywidth();
|
||||||
//static void resizebarwin(Monitor *m);
|
|
||||||
|
|
||||||
/* systray */
|
#if USESYSTRAY
|
||||||
|
static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
|
||||||
|
#else
|
||||||
static int sendevent(Client *c, Atom proto);
|
static int sendevent(Client *c, Atom proto);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||||
static void grabbuttons(Client *c, int focused);
|
static void grabbuttons(Client *c, int focused);
|
||||||
|
@ -781,9 +788,17 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
||||||
[MapRequest] = maprequest,
|
[MapRequest] = maprequest,
|
||||||
[MotionNotify] = motionnotify,
|
[MotionNotify] = motionnotify,
|
||||||
[PropertyNotify] = propertynotify,
|
[PropertyNotify] = propertynotify,
|
||||||
|
#if USESYSTRAY
|
||||||
|
[ResizeRequest] = resizerequest,
|
||||||
|
#endif
|
||||||
[UnmapNotify] = unmapnotify
|
[UnmapNotify] = unmapnotify
|
||||||
};
|
};
|
||||||
|
#if USESYSTRAY
|
||||||
|
static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast], motifatom;
|
||||||
|
#else
|
||||||
static Atom wmatom[WMLast], netatom[NetLast], motifatom;
|
static Atom wmatom[WMLast], netatom[NetLast], motifatom;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if USEIPC
|
#if USEIPC
|
||||||
static int epoll_fd;
|
static int epoll_fd;
|
||||||
static int dpy_fd;
|
static int dpy_fd;
|
||||||
|
@ -1409,6 +1424,17 @@ cleanup(void)
|
||||||
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
||||||
while (mons)
|
while (mons)
|
||||||
cleanupmon(mons);
|
cleanupmon(mons);
|
||||||
|
#if USESYSTRAY
|
||||||
|
if (!hidesystray && systray) {
|
||||||
|
while (systray->icons)
|
||||||
|
removesystrayicon(systray->icons);
|
||||||
|
if (systray->win) {
|
||||||
|
XUnmapWindow(dpy, systray->win);
|
||||||
|
XDestroyWindow(dpy, systray->win);
|
||||||
|
}
|
||||||
|
free(systray);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < CurLast; i++)
|
for (i = 0; i < CurLast; i++)
|
||||||
drw_cur_free(drw, cursor[i]);
|
drw_cur_free(drw, cursor[i]);
|
||||||
|
@ -1454,9 +1480,50 @@ clientmessage(XEvent *e)
|
||||||
{
|
{
|
||||||
XClientMessageEvent *cme = &e->xclient;
|
XClientMessageEvent *cme = &e->xclient;
|
||||||
Client *c = wintoclient(cme->window);
|
Client *c = wintoclient(cme->window);
|
||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
XWindowAttributes wa;
|
||||||
|
XSetWindowAttributes swa;
|
||||||
|
|
||||||
|
if (!hidesystray && systray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
|
||||||
|
/* add systray icons */
|
||||||
|
if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
|
||||||
|
if (!(c = (Client *)calloc(1, sizeof(Client))))
|
||||||
|
die("fatal: could not malloc() %u bytes\n", sizeof(Client));
|
||||||
|
if (!(c->win = cme->data.l[2])) {
|
||||||
|
free(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->mon = selmon;
|
||||||
|
c->next = systray->icons;
|
||||||
|
systray->icons = c;
|
||||||
|
XGetWindowAttributes(dpy, c->win, &wa);
|
||||||
|
c->x = c->oldx = c->y = c->oldy = 0;
|
||||||
|
c->w = c->oldw = wa.width;
|
||||||
|
c->h = c->oldh = wa.height;
|
||||||
|
c->oldbw = wa.border_width;
|
||||||
|
c->bw = 0;
|
||||||
|
c->isfloating = True;
|
||||||
|
/* reuse tags field as mapped status */
|
||||||
|
c->tags = 1;
|
||||||
|
updatesizehints(c);
|
||||||
|
updatesystrayicongeom(c, wa.width, wa.height);
|
||||||
|
XAddToSaveSet(dpy, c->win);
|
||||||
|
XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
|
||||||
|
XReparentWindow(dpy, c->win, systray->win, 0, 0);
|
||||||
|
/* use parents background color */
|
||||||
|
swa.background_pixel = scheme[SchemeSystray][ColBg].pixel; /* might be a good idea to change this to SchemeBar */
|
||||||
|
XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
|
||||||
|
sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
|
||||||
|
XSync(dpy, False);
|
||||||
|
setclientstate(c, NormalState);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!c)
|
if (!c)
|
||||||
return;
|
return;
|
||||||
if (cme->message_type == netatom[NetWMState]) {
|
if (cme->message_type == netatom[NetWMState]) {
|
||||||
|
@ -1779,12 +1846,19 @@ destroynotify(XEvent *e)
|
||||||
Monitor *m;
|
Monitor *m;
|
||||||
XDestroyWindowEvent *ev = &e->xdestroywindow;
|
XDestroyWindowEvent *ev = &e->xdestroywindow;
|
||||||
|
|
||||||
if ((c = wintoclient(ev->window)))
|
if ((c = wintoclient(ev->window))) {
|
||||||
unmanage(c, 1);
|
unmanage(c, 1);
|
||||||
|
|
||||||
else if ((c = swallowingclient(ev->window)))
|
#if USESYSTRAY
|
||||||
|
} else if (!hidesystray && (c = wintosystrayicon(ev->window))) {
|
||||||
|
removesystrayicon(c);
|
||||||
|
drawbarwin(systray->bar);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} else if ((c = swallowingclient(ev->window))) {
|
||||||
unmanage(c->swallowing, 1);
|
unmanage(c->swallowing, 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* run ltmenu */
|
/* run ltmenu */
|
||||||
#if USEMOUSE
|
#if USEMOUSE
|
||||||
|
@ -2500,10 +2574,25 @@ getatomprop(Client *c, Atom prop)
|
||||||
unsigned char *p = NULL;
|
unsigned char *p = NULL;
|
||||||
Atom da, atom = None;
|
Atom da, atom = None;
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
Atom req = XA_ATOM;
|
||||||
|
if (prop == xatom[XembedInfo])
|
||||||
|
req = xatom[XembedInfo];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
|
||||||
|
#else
|
||||||
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
|
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
|
||||||
|
#endif
|
||||||
&da, &di, &dl, &dl, &p) == Success && p) {
|
&da, &di, &dl, &dl, &p) == Success && p) {
|
||||||
atom = *(Atom *)p;
|
atom = *(Atom *)p;
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
if (da == xatom[XembedInfo] && dl == 2)
|
||||||
|
atom = ((Atom *)p)[1];
|
||||||
|
#endif
|
||||||
|
|
||||||
XFree(p);
|
XFree(p);
|
||||||
}
|
}
|
||||||
return atom;
|
return atom;
|
||||||
|
@ -2642,8 +2731,6 @@ hidewin(Client *c) {
|
||||||
XSelectInput(dpy, root, ra.your_event_mask);
|
XSelectInput(dpy, root, ra.your_event_mask);
|
||||||
XSelectInput(dpy, w, ca.your_event_mask);
|
XSelectInput(dpy, w, ca.your_event_mask);
|
||||||
XUngrabServer(dpy);
|
XUngrabServer(dpy);
|
||||||
|
|
||||||
c->ishidden = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USEIPC
|
#if USEIPC
|
||||||
|
@ -2900,8 +2987,6 @@ showwin(Client *c)
|
||||||
if (!c || !HIDDEN(c))
|
if (!c || !HIDDEN(c))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
c->ishidden = 0;
|
|
||||||
|
|
||||||
XMapWindow(dpy, c->win);
|
XMapWindow(dpy, c->win);
|
||||||
setclientstate(c, NormalState);
|
setclientstate(c, NormalState);
|
||||||
arrange(c->mon);
|
arrange(c->mon);
|
||||||
|
@ -3166,7 +3251,11 @@ killclient(const Arg *arg)
|
||||||
{
|
{
|
||||||
if (!selmon->sel || selmon->sel->ispermanent)
|
if (!selmon->sel || selmon->sel->ispermanent)
|
||||||
return;
|
return;
|
||||||
|
#if USESYSTRAY
|
||||||
|
if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0)) {
|
||||||
|
#else
|
||||||
if (!sendevent(selmon->sel, wmatom[WMDelete])) {
|
if (!sendevent(selmon->sel, wmatom[WMDelete])) {
|
||||||
|
#endif
|
||||||
XGrabServer(dpy);
|
XGrabServer(dpy);
|
||||||
XSetErrorHandler(xerrordummy);
|
XSetErrorHandler(xerrordummy);
|
||||||
XSetCloseDownMode(dpy, DestroyAll);
|
XSetCloseDownMode(dpy, DestroyAll);
|
||||||
|
@ -3187,7 +3276,11 @@ killunsel(const Arg *arg)
|
||||||
|
|
||||||
for (i = selmon->clients; i; i = i->next) {
|
for (i = selmon->clients; i; i = i->next) {
|
||||||
if (ISVISIBLE(i) && i != selmon->sel) {
|
if (ISVISIBLE(i) && i != selmon->sel) {
|
||||||
|
#if USESYSTRAY
|
||||||
|
if (!sendevent(i->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0)) {
|
||||||
|
#else
|
||||||
if (!sendevent(selmon->sel, wmatom[WMDelete])) {
|
if (!sendevent(selmon->sel, wmatom[WMDelete])) {
|
||||||
|
#endif
|
||||||
XGrabServer(dpy);
|
XGrabServer(dpy);
|
||||||
XSetErrorHandler(xerrordummy);
|
XSetErrorHandler(xerrordummy);
|
||||||
XSetCloseDownMode(dpy, DestroyAll);
|
XSetCloseDownMode(dpy, DestroyAll);
|
||||||
|
@ -3388,6 +3481,14 @@ maprequest(XEvent *e)
|
||||||
static XWindowAttributes wa;
|
static XWindowAttributes wa;
|
||||||
XMapRequestEvent *ev = &e->xmaprequest;
|
XMapRequestEvent *ev = &e->xmaprequest;
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
Client *i;
|
||||||
|
|
||||||
|
if (!hidesystray && systray && (i = wintosystrayicon(ev->window))) {
|
||||||
|
sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
|
||||||
|
drawbarwin(systray->bar);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
|
if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
|
||||||
return;
|
return;
|
||||||
|
@ -3440,8 +3541,8 @@ window_map(Display *dpy, Client *c, int deiconify)
|
||||||
Window win = c->win;
|
Window win = c->win;
|
||||||
|
|
||||||
/* fix: hidden windows immediately get mapped */
|
/* fix: hidden windows immediately get mapped */
|
||||||
if (c->ishidden)
|
//if (c->ishidden)
|
||||||
return;
|
// return;
|
||||||
|
|
||||||
if (deiconify)
|
if (deiconify)
|
||||||
window_set_state(dpy, win, NormalState);
|
window_set_state(dpy, win, NormalState);
|
||||||
|
@ -4232,6 +4333,18 @@ propertynotify(XEvent *e)
|
||||||
Window trans;
|
Window trans;
|
||||||
XPropertyEvent *ev = &e->xproperty;
|
XPropertyEvent *ev = &e->xproperty;
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
if (!hidesystray && (c = wintosystrayicon(ev->window))) {
|
||||||
|
if (ev->atom == XA_WM_NORMAL_HINTS) {
|
||||||
|
updatesizehints(c);
|
||||||
|
updatesystrayicongeom(c, c->w, c->h);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
updatesystrayiconstate(c, ev);
|
||||||
|
drawbarwin(systray->bar);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((ev->window == root) && (ev->atom == XA_WM_NAME)) {
|
if ((ev->window == root) && (ev->atom == XA_WM_NAME)) {
|
||||||
if (!getsignal())
|
if (!getsignal())
|
||||||
updatestatus();
|
updatestatus();
|
||||||
|
@ -4798,27 +4911,121 @@ setdesktopnames(void)
|
||||||
XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]);
|
XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
int
|
int
|
||||||
|
#if USESYSTRAY
|
||||||
|
sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
|
||||||
|
#else
|
||||||
sendevent(Client *c, Atom proto)
|
sendevent(Client *c, Atom proto)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
Atom *protocols;
|
Atom *protocols;
|
||||||
int exists = 0;
|
int exists = 0;
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
Atom mt;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
|
||||||
|
mt = wmatom[WMProtocols];
|
||||||
|
if (XGetWMProtocols(dpy, w, &protocols, &n)) {
|
||||||
|
while (!exists && n--)
|
||||||
|
exists = protocols[n] == proto;
|
||||||
|
XFree(protocols);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exists = True;
|
||||||
|
mt = proto;
|
||||||
|
#else
|
||||||
if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
|
if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
|
||||||
while (!exists && n--)
|
while (!exists && n--)
|
||||||
exists = protocols[n] == proto;
|
exists = protocols[n] == proto;
|
||||||
XFree(protocols);
|
XFree(protocols);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (exists) {
|
if (exists) {
|
||||||
ev.type = ClientMessage;
|
ev.type = ClientMessage;
|
||||||
ev.xclient.format = 32;
|
ev.xclient.format = 32;
|
||||||
|
#if USESYSTRAY
|
||||||
|
ev.xclient.window = w;
|
||||||
|
ev.xclient.message_type = mt;
|
||||||
|
ev.xclient.data.l[0] = d0;
|
||||||
|
ev.xclient.data.l[1] = d1;
|
||||||
|
ev.xclient.data.l[2] = d2;
|
||||||
|
ev.xclient.data.l[3] = d3;
|
||||||
|
ev.xclient.data.l[4] = d4;
|
||||||
|
XSendEvent(dpy, w, False, mask, &ev);
|
||||||
|
#else
|
||||||
ev.xclient.window = c->win;
|
ev.xclient.window = c->win;
|
||||||
ev.xclient.message_type = wmatom[WMProtocols];
|
ev.xclient.message_type = wmatom[WMProtocols];
|
||||||
ev.xclient.data.l[0] = proto;
|
ev.xclient.data.l[0] = proto;
|
||||||
ev.xclient.data.l[1] = CurrentTime;
|
ev.xclient.data.l[1] = CurrentTime;
|
||||||
XSendEvent(dpy, c->win, False, NoEventMask, &ev);
|
XSendEvent(dpy, c->win, False, NoEventMask, &ev);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
#if USESYSTRAY
|
||||||
|
sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
|
||||||
|
#else
|
||||||
|
sendevent(Client *c, Atom proto)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
#if USESYSTRAY
|
||||||
|
Atom *protocols, mt;
|
||||||
|
#else
|
||||||
|
Atom *protocols;
|
||||||
|
#endif
|
||||||
|
int exists = 0;
|
||||||
|
XEvent ev;
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
|
||||||
|
mt = wmatom[WMProtocols];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
if (XGetWMProtocols(dpy, w, &protocols, &n)) {
|
||||||
|
#else
|
||||||
|
if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
|
||||||
|
#endif
|
||||||
|
while (!exists && n--)
|
||||||
|
exists = protocols[n] == proto;
|
||||||
|
XFree(protocols);
|
||||||
|
}
|
||||||
|
#if USESYSTRAY
|
||||||
|
} else {
|
||||||
|
exists = True;
|
||||||
|
mt = proto;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (exists) {
|
||||||
|
ev.type = ClientMessage;
|
||||||
|
ev.xclient.format = 32;
|
||||||
|
#if USESYSTRAY
|
||||||
|
ev.xclient.window = w;
|
||||||
|
ev.xclient.message_type = mt;
|
||||||
|
ev.xclient.data.l[0] = d0;
|
||||||
|
ev.xclient.data.l[1] = d1;
|
||||||
|
ev.xclient.data.l[2] = d2;
|
||||||
|
ev.xclient.data.l[3] = d3;
|
||||||
|
ev.xclient.data.l[4] = d4;
|
||||||
|
XSendEvent(dpy, w, False, mask, &ev);
|
||||||
|
#else
|
||||||
|
ev.xclient.window = c->win;
|
||||||
|
ev.xclient.message_type = wmatom[WMProtocols];
|
||||||
|
ev.xclient.data.l[0] = proto;
|
||||||
|
ev.xclient.data.l[1] = CurrentTime;
|
||||||
|
XSendEvent(dpy, c->win, False, NoEventMask, &ev);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
@ -4842,7 +5049,11 @@ setfocus(Client *c)
|
||||||
XA_WINDOW, 32, PropModeReplace,
|
XA_WINDOW, 32, PropModeReplace,
|
||||||
(unsigned char *) &(c->win), 1);
|
(unsigned char *) &(c->win), 1);
|
||||||
}
|
}
|
||||||
|
#if USESYSTRAY
|
||||||
|
sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
|
||||||
|
#else
|
||||||
sendevent(c, wmatom[WMTakeFocus]);
|
sendevent(c, wmatom[WMTakeFocus]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -5023,6 +5234,18 @@ setup(void)
|
||||||
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
|
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
|
||||||
netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
|
netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
|
||||||
|
|
||||||
|
#if USESYSTRAY
|
||||||
|
netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
|
||||||
|
netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
|
||||||
|
netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
|
||||||
|
netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
|
||||||
|
netatom[NetSystemTrayVisual] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_VISUAL", False);
|
||||||
|
netatom[NetWMWindowTypeDock] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
|
||||||
|
xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
|
||||||
|
xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
|
||||||
|
xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fullscreenhidebar)
|
if (fullscreenhidebar)
|
||||||
netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
|
netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
|
||||||
|
|
||||||
|
@ -5683,6 +5906,13 @@ unmapnotify(XEvent *e)
|
||||||
setclientstate(c, WithdrawnState);
|
setclientstate(c, WithdrawnState);
|
||||||
else
|
else
|
||||||
unmanage(c, 0);
|
unmanage(c, 0);
|
||||||
|
#if USESYSTRAY
|
||||||
|
} else if (!hidesystray && (c = wintosystrayicon(ev->window))) {
|
||||||
|
/* KLUDGE! sometimes icons occasionally unmap their windows, but do
|
||||||
|
* _not_ destroy them. We map those windows back */
|
||||||
|
XMapRaised(dpy, c->win);
|
||||||
|
drawbarwin(systray->bar);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
toggle.h
2
toggle.h
|
@ -19,7 +19,7 @@ Not compatible with BSDs so for those, set this to 0. */
|
||||||
|
|
||||||
/* Miscellanious */
|
/* Miscellanious */
|
||||||
#define USESWITCHER 1 /* Whether or not to include the switcher */
|
#define USESWITCHER 1 /* Whether or not to include the switcher */
|
||||||
#define USESYSTRAY 0 /* Whether or not to include the systray */
|
#define USESYSTRAY 1 /* Whether or not to include the systray */
|
||||||
#define USEROUNDCORNERS 1 /* Whether or not to include rounded corners */
|
#define USEROUNDCORNERS 1 /* Whether or not to include rounded corners */
|
||||||
#define USEMEDIA 1 /* Whether or not to include media keys */
|
#define USEMEDIA 1 /* Whether or not to include media keys */
|
||||||
#define USEMOUSE 1 /* Whether or not to include mouse binds */
|
#define USEMOUSE 1 /* Whether or not to include mouse binds */
|
||||||
|
|
Loading…
Reference in a new issue