commit d334e0f38aa6b6a723a01147f9bc0485d9154179
parent 00e8f07797f89e31a7dc59e57a0636534525b53e
Author: seninha <lucas@seninha.org>
Date: Thu, 22 Sep 2022 08:49:51 -0300
add dockapp states and desktop menus
Diffstat:
M | Makefile | | | 2 | +- |
M | shod.1 | | | 48 | +++++++++++++++++++++++++++++++++++++++++------- |
M | shod.c | | | 17 | ++++++----------- |
M | shod.h | | | 42 | +++++++++++++++++++++++++++++++----------- |
M | xbar.c | | | 2 | +- |
M | xcontainer.c | | | 329 | ++++++------------------------------------------------------------------------- |
M | xdock.c | | | 87 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
M | xdraw.c | | | 25 | +++++++++++++++++++++++-- |
M | xevents.c | | | 175 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
M | xhints.c | | | 2 | +- |
A | xmenu.c | | | 226 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | xmon.c | | | 15 | +++++++++++++-- |
M | xsplash.c | | | 53 | +++++++++++++++++++++++++++++++++++++++++++---------- |
13 files changed, 602 insertions(+), 421 deletions(-)
diff --git a/Makefile b/Makefile
@@ -11,7 +11,7 @@ XCPPFLAGS = -I${LOCALINC} -I${X11INC} -I/usr/include/freetype2 -I${X11INC}/freet
XLDFLAGS = -L${LOCALLIB} -L${X11LIB} -lfontconfig -lXft -lX11 -lXinerama -lXrender
SHOD_OBJS = shod.o config.o xhints.o xmon.o xdraw.o xevents.o \
- xcontainer.o xbar.o xdock.o xsplash.o xnotif.o xprompt.o
+ xcontainer.o xmenu.o xbar.o xdock.o xsplash.o xnotif.o xprompt.o
SHODC_OBJS = shodc.o
SHARED_OBJS = xutil.o
PROGS = shod shodc
diff --git a/shod.1 b/shod.1
@@ -81,7 +81,7 @@ ignore requests to configure a window size or position after the window is mappe
A client may request the window mager to configure (ie', resize or reposition) its own window.
For example,
.Xr xterm 1
-sends a configure request for the window manager to expand or shrink its window
+sends a configure request for the window manager to resize its window
when the user changes its font size.
Clients requesting to change its own size may be annoying,
so configure requests are ignored by default;
@@ -542,9 +542,10 @@ or
.Ic MWM_TEAROFF_WINDOW
(called menu windows)
are windows that cannot be tiled or tabbed into a container
-and are tied to a leader window.
-They are floating windows that always apeear on top of their leader
+and are optionally tied to a leader window.
+They are floating windows that always apear on top of their leader
and are not listed on the list of clients.
+If a menu has no leader window, they apear on top of all windows.
.Pp
Menu windows, often called
.Dq "torn off windows" ,
@@ -629,6 +630,32 @@ Inside the dock, dockapps are organized by order of map request.
.Pp
Dockapps, or docked applications are windows which appear to reside
inside an icon or a dock rather than a container.
+.Pp
+Dockapps can have one of three possible states: spaced, shrunk, or extended.
+The state of a dockapp can be set with the
+.Ic "shod.CLASS.NAME.ROLE.state"
+X resource.
+.Pp
+A
+.Dq Em "spaced"
+dockapp is centered on a slot whose size is multiple of, by default, 64 pixels
+(this value can be changed with the
+.Ic "shod.dockSpace"
+X resource).
+So for example, by default, if a dockapp has 58 pixels, it is centered on a slot of 64 pixels (64 * 1);
+but if a dockapp has 100 pixels, it is centered on a slot of 128 pixels (64 * 2).
+This is the default state for a dockapp.
+.Pp
+A
+.Dq Em "shrunk"
+dockapp
+has its slot resized to the size of the dockapp itself.
+.Pp
+An
+.Dq Em "extended"
+dockapp has is resized to fit all the remaining unused space of the dock.
+For example, if the only content of the dock is an extended taskbar dockapp,
+this dockapp is resized to fit all the dock.
.Sh RESOURCES
.Nm shod
understands the following X resources.
@@ -659,6 +686,12 @@ a horizontal dock will be placed in the north edge of the monitor, alligned to t
And for a value of
.Cm EF ,
a vertical dock will be placed in the east edge of the monitor, stretched to the full hight of the monitor.
+.It Ic "shod.dockSpace"
+The multiplier for the height (for vertical docks) or width (for horizontal docks)
+in pixels of the slot dockapps are placed in.
+See the section
+.Sx "Dockapps"
+above for more information.
.It Ic "shod.dockWidth"
The width (for vertical docks) or height (for horizontal docks)
of the dock in pixels.
@@ -719,7 +752,7 @@ Possible values are
.It Ic shod.CLASS.NAME.ROLE.state
Define the initial state of a window matching the given class, name and role.
Its value should be a comma-separated list of states.
-Possible states are
+Possible states for normal windows are
.Cm above ,
.Cm below ,
.Cm fullscreen ,
@@ -728,12 +761,13 @@ Possible states are
.Cm shaded ,
and
.Cm sticky .
+Possible states for dockapp windows are
+.Cm extend ,
+and
+.Cm shrunk .
.It Ic shod.CLASS.NAME.ROLE.dockpos
Define the position in the dock of a docked application matching the given class, name and role.
Its value should be a number, starting from position 1.
-If the value is followed by an asterisk
-.Pq "*" ,
-the docked application will be stretched to fill the dock.
.El
.Sh ENVIRONMENT
The following environment variables affect the execution of
diff --git a/shod.c b/shod.c
@@ -286,8 +286,8 @@ initdock(void)
static void
initdummywindows(void)
{
- Window wins[2];
int i;
+ XSetWindowAttributes swa;
for (i = 0; i < LAYER_LAST; i++) {
wm.layers[i].ncols = 0;
@@ -295,13 +295,8 @@ initdummywindows(void)
XRaiseWindow(dpy, wm.layers[i].frame);
TAILQ_INSERT_HEAD(&wm.stackq, &wm.layers[i], raiseentry);
}
-
- /* the layer of docks/bars are just below fullscreen containers */
- wm.docklayer = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
- wins[0] = wm.layers[LAYER_FULLSCREEN].frame;
- wins[1] = wm.docklayer;
- XRestackWindows(dpy, wins, 2);
-
+ swa = clientswa;
+ swa.event_mask |= KeyPressMask;
wm.wmcheckwin = XCreateWindow(
dpy, root,
- (2 * config.borderwidth + config.titlewidth),
@@ -309,8 +304,8 @@ initdummywindows(void)
2 * config.borderwidth + config.titlewidth,
2 * config.borderwidth + config.titlewidth,
0, depth, CopyFromParent, visual,
- clientmask | KeyPressMask,
- &clientswa
+ clientmask,
+ &swa
);
wm.wmcheckpix = XCreatePixmap(
dpy, wm.wmcheckwin,
@@ -325,6 +320,7 @@ static void
mapdummywins(void)
{
XMapWindow(dpy, wm.wmcheckwin);
+ XSetInputFocus(dpy, wm.wmcheckwin, RevertToParent, CurrentTime);
}
/* run stdin on sh */
@@ -351,7 +347,6 @@ cleandummywindows(void)
XFreePixmap(dpy, wm.wmcheckpix);
XDestroyWindow(dpy, wm.wmcheckwin);
- XDestroyWindow(dpy, wm.docklayer);
for (i = 0; i < LAYER_LAST; i++) {
XDestroyWindow(dpy, wm.layers[i].frame);
}
diff --git a/shod.h b/shod.h
@@ -98,6 +98,8 @@ enum {
LAYER_BELOW,
LAYER_NORMAL,
LAYER_ABOVE,
+ LAYER_MENU,
+ LAYER_DOCK,
LAYER_FULLSCREEN,
LAYER_LAST
};
@@ -129,6 +131,10 @@ enum {
SHADED = 0x20,
STICKY = 0x40,
USERPLACED = 0x80,
+
+ /* dockapp states bits */
+ EXTEND = 0x100,
+ SHRUNK = 0x200,
};
enum {
@@ -467,7 +473,9 @@ struct Dialog {
struct Menu {
struct Object obj;
- struct Tab *tab; /* pointer to parent tab */
+ struct Queue *menuq; /* pointer to queue it is in */
+ struct Tab *tab; /* tab for menu (if existant) */
+ struct Monitor *mon;
/*
* Frames, pixmaps, saved pixmap geometry, etc
@@ -497,12 +505,15 @@ struct Dockapp {
int x, y, w, h; /* dockapp position and size */
int ignoreunmap; /* number of unmap requests to ignore */
int dockpos; /* position of the dockapp in the dock */
- int extend; /* whether to maximize dockapp size to fit dock */
+ int state; /* dockapp state */
int slotsize; /* size of the slot the dockapp is in */
};
struct Splash {
struct Object obj;
+ struct Monitor *mon;
+ Window frame;
+ int desk;
int x, y, w, h; /* splash screen geometry */
};
@@ -523,6 +534,7 @@ struct WM {
struct Queue barq; /* queue of bars */
struct Queue splashq; /* queue of splash screen windows */
struct Queue notifq; /* queue of notifications */
+ struct Queue menuq; /* queue of desktop menus */
struct ContainerQueue focusq; /* queue of containers ordered by focus history */
int nclients; /* total number of container windows */
@@ -636,6 +648,7 @@ typedef void Managefunc(struct Tab *, struct Monitor *, int, Window, Window, XRe
typedef int Unmanagefunc(struct Object *obj, int ignoreunmap);
/* container routines */
+struct Container *getnextfocused(struct Monitor *mon, int desk);
struct Container *containerraisetemp(struct Container *prevc, int backward);
void containerbacktoplace(struct Container *c, int restack);
void containerdel(struct Container *c);
@@ -650,6 +663,7 @@ void containerconfigure(struct Container *c, unsigned int valuemask, XWindowChan
void containersendtodeskandfocus(struct Container *c, struct Monitor *mon, unsigned long desk);
void containerplace(struct Container *c, struct Monitor *mon, int desk, int userplaced);
void containerdelrow(struct Row *row);
+void containerhide(struct Container *c, int hide);
void tabdetach(struct Tab *tab, int x, int y);
void tabfocus(struct Tab *tab, int gotodesk);
void tabdecorate(struct Tab *t, int pressed);
@@ -657,22 +671,27 @@ void tabupdateurgency(struct Tab *t, int isurgent);
void rowstack(struct Column *col, struct Row *row);
void dialogconfigure(struct Dialog *d, unsigned int valuemask, XWindowChanges *wc);
void dialogmoveresize(struct Dialog *dial);
+int tabattach(struct Container *c, struct Tab *t, int x, int y);
+int containerisshaded(struct Container *c);
+int containerisvisible(struct Container *c, struct Monitor *mon, int desk);
+
+/* menu */
+void menuhide(struct Menu *menu, int hide);
void menuincrmove(struct Menu *menu, int x, int y);
void menuconfigure(struct Menu *menu, unsigned int valuemask, XWindowChanges *wc);
void menumoveresize(struct Menu *menu);
void menudecorate(struct Menu *menu, int titlepressed);
-void menuaddraise(struct Tab *tab, struct Menu *menu);
-void menuplace(struct Menu *menu);
-void deskfocus(struct Monitor *mon, int desk, int focus);
-void deskshow(int show);
-int tabattach(struct Container *c, struct Tab *t, int x, int y);
-int containerisshaded(struct Container *c);
-int containerisvisible(struct Container *c, struct Monitor *mon, int desk);
+void menuaddraise(struct Menu *menu);
+void menuraise(struct Menu *menu);
+void menuplace(struct Monitor *mon, struct Menu *menu);
/* other object routines */
+void dockappconfigure(struct Dockapp *dapp, unsigned int valuemask, XWindowChanges *wc);
void barstrut(struct Bar *bar);
void notifplace(void);
-void splashplace(struct Splash *splash);
+void splashplace(struct Monitor *mon, struct Splash *splash);
+void splashhide(struct Splash *splash, int hide);
+void splashrise(struct Splash *splash);
void dockupdate(void);
/* monitor routines */
@@ -707,7 +726,7 @@ void drawborders(Pixmap pix, int w, int h, int style);
void drawbackground(Pixmap pix, int x, int y, int w, int h, int style);
void drawframe(Pixmap pix, int isshaded, int w, int h, enum Octant o, int style);
void drawshadow(Pixmap pix, int x, int y, int w, int h, int style, int pressed);
-void drawtitle(Drawable pix, const char *text, int w, int drawlines, int style, int pressed);
+void drawtitle(Drawable pix, const char *text, int w, int drawlines, int style, int pressed, int ismenu);
void drawprompt(Pixmap pix, int w, int h);
void drawdock(Pixmap pix, int w, int h);
void buttonleftdecorate(Window button, Pixmap pix, int style, int pressed);
@@ -735,6 +754,7 @@ Unmanagefunc unmanagetab;
Unmanagefunc unmanagebar;
void setmod(void);
void scan(void);
+void deskupdate(struct Monitor *mon, int desk);
/* function tables */
extern void (*managefuncs[])(struct Tab *, struct Monitor *, int, Window, Window, XRectangle, int, int);
diff --git a/xbar.c b/xbar.c
@@ -36,7 +36,7 @@ managebar(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window lea
(void)rect;
(void)state;
(void)ignoreunmap;
- Window wins[2] = {wm.docklayer, win};
+ Window wins[2] = {wm.layers[LAYER_DOCK].frame, win};
bar = emalloc(sizeof(*bar));
*bar = (struct Bar){
diff --git a/xcontainer.c b/xcontainer.c
@@ -3,7 +3,7 @@
#define DIV 15 /* see containerplace() for details */
/* get next focused container after old on given monitor and desktop */
-static struct Container *
+struct Container *
getnextfocused(struct Monitor *mon, int desk)
{
struct Container *c;
@@ -78,13 +78,6 @@ clientsdecr(void)
wm.nclients--;
}
-/* check if desktop is visible */
-static int
-deskisvisible(struct Monitor *mon, int desk)
-{
- return mon->seldesk == desk;
-}
-
/* get decoration style (and state) of container */
static int
containergetstyle(struct Container *c)
@@ -163,7 +156,7 @@ dialognew(Window win, int maxw, int maxh, int ignoreunmap)
.obj.win = win,
.obj.type = TYPE_DIALOG,
};
- dial->frame = XCreateWindow(dpy, root, 0, 0, maxw, maxh, 0, depth, CopyFromParent, visual, clientmask, &clientswa),
+ dial->frame = XCreateWindow(dpy, root, 0, 0, maxw, maxh, 0, depth, CopyFromParent, visual, clientmask, &clientswa);
XReparentWindow(dpy, dial->obj.win, dial->frame, 0, 0);
XMapWindow(dpy, dial->obj.win);
return dial;
@@ -171,71 +164,23 @@ dialognew(Window win, int maxw, int maxh, int ignoreunmap)
/* map menus */
static void
-menumap(struct Tab *tab)
+tabhidemenus(struct Tab *tab, int hide)
{
struct Object *menu;
if (tab == NULL)
return;
TAILQ_FOREACH(menu, &tab->menuq, entry) {
- XMapWindow(dpy, ((struct Menu *)menu)->frame);
- icccmwmstate(menu->win, NormalState);
+ if (hide) {
+ XMapWindow(dpy, ((struct Menu *)menu)->frame);
+ icccmwmstate(menu->win, NormalState);
+ } else {
+ XUnmapWindow(dpy, ((struct Menu *)menu)->frame);
+ icccmwmstate(menu->win, IconicState);
+ }
}
}
-/* create new menu */
-static struct Menu *
-menunew(Window win, int x, int y, int w, int h, int ignoreunmap)
-{
- struct Menu *menu;
-
- menu = emalloc(sizeof(*menu));
- *menu = (struct Menu){
- .titlebar = None,
- .button = None,
- .obj.win = win,
- .obj.type = TYPE_MENU,
- .pix = None,
- .pixbutton = None,
- .pixtitlebar = None,
- .x = x - config.borderwidth,
- .y = y - config.borderwidth,
- .w = w + config.borderwidth * 2,
- .h = h + config.borderwidth * 2 + config.titlewidth,
- .ignoreunmap = ignoreunmap,
- };
- menu->frame = XCreateWindow(dpy, root, 0, 0,
- w + config.borderwidth * 2,
- h + config.borderwidth * 2 + config.titlewidth, 0,
- depth, CopyFromParent, visual,
- clientmask, &clientswa),
- menu->titlebar = XCreateWindow(dpy, menu->frame, config.borderwidth, config.borderwidth,
- max(1, menu->w - 2 * config.borderwidth - config.titlewidth),
- config.titlewidth, 0,
- depth, CopyFromParent, visual,
- clientmask, &clientswa);
- menu->button = XCreateWindow(dpy, menu->frame, menu->w - config.borderwidth - config.titlewidth, config.borderwidth,
- config.titlewidth, config.titlewidth, 0,
- depth, CopyFromParent, visual,
- clientmask, &clientswa);
- menu->pixbutton = XCreatePixmap(dpy, menu->button, config.titlewidth, config.titlewidth, depth);
- XDefineCursor(dpy, menu->button, wm.cursors[CURSOR_PIRATE]);
- XReparentWindow(dpy, menu->obj.win, menu->frame, config.borderwidth, config.borderwidth + config.titlewidth);
- XMapWindow(dpy, menu->obj.win);
- XMapWindow(dpy, menu->button);
- XMapWindow(dpy, menu->titlebar);
- return menu;
-}
-
-/* remove menu from the menu list */
-static void
-menudelraise(struct Tab *tab, struct Menu *menu)
-{
- if (TAILQ_EMPTY(&tab->menuq))
- return;
- TAILQ_REMOVE(&tab->menuq, (struct Object *)menu, entry);
-}
-
/* calculate position and width of tabs of a row */
static void
rowcalctabs(struct Row *row)
@@ -575,48 +520,6 @@ dialogdecorate(struct Dialog *d)
drawcommit(d->pix, d->frame, fullw, fullh);
}
-/* unmap menus */
-static void
-menuunmap(struct Tab *tab)
-{
- struct Object *menu;
-
- if (tab == NULL)
- return;
- TAILQ_FOREACH(menu, &tab->menuq, entry) {
- XUnmapWindow(dpy, ((struct Menu *)menu)->frame);
- icccmwmstate(menu->win, IconicState);
- }
-}
-
-/* raise menus */
-static void
-menuraise(struct Tab *tab)
-{
- struct Container *c;
- struct Object *p;
- struct Menu *menu;
- Window wins[2];
-
- c = tab->row->col->c;
- if (c == NULL || c->isminimized)
- return;
- if (c->isfullscreen)
- wins[0] = wm.layers[LAYER_FULLSCREEN].frame;
- else if (c->abovebelow > 0)
- wins[0] = wm.layers[LAYER_ABOVE].frame;
- else if (c->abovebelow < 0)
- wins[0] = wm.layers[LAYER_BELOW].frame;
- else
- wins[0] = wm.layers[LAYER_NORMAL].frame;
- TAILQ_FOREACH(p, &tab->menuq, entry) {
- menu = (struct Menu *)p;
- wins[1] = menu->frame;
- XRestackWindows(dpy, wins, 2);
- wins[0] = menu->frame;
- }
-}
-
/* get focused fullscreen window in given monitor and desktop */
static struct Container *
getfullscreen(struct Monitor *mon, int desk)
@@ -677,7 +580,7 @@ containerdelraise(struct Container *c)
}
/* hide container */
-static void
+void
containerhide(struct Container *c, int hide)
{
struct Object *t, *d;
@@ -687,7 +590,7 @@ containerhide(struct Container *c, int hide)
c->ishidden = hide;
if (hide) {
XUnmapWindow(dpy, c->frame);
- menuunmap(c->selcol->selrow->seltab);
+ tabhidemenus(c->selcol->selrow->seltab, ADD);
} else {
XMapWindow(dpy, c->frame);
}
@@ -1254,7 +1157,7 @@ containerincrmove(struct Container *c, int x, int y)
if (monto != NULL && monto != c->mon) {
containersendtodesk(c, monto, monto->seldesk);
if (wm.focused == c) {
- deskfocus(monto, monto->seldesk, 0);
+ deskupdate(monto, monto->seldesk);
}
}
}
@@ -1264,6 +1167,8 @@ containerincrmove(struct Container *c, int x, int y)
void
containerraise(struct Container *c, int isfullscreen, int abovebelow)
{
+ struct Menu *menu;
+ struct Object *obj;
Window wins[2];
int layer;
@@ -1283,7 +1188,12 @@ containerraise(struct Container *c, int isfullscreen, int abovebelow)
c->isfullscreen = isfullscreen;
c->abovebelow = abovebelow;
XRestackWindows(dpy, wins, 2);
- menuraise(c->selcol->selrow->seltab);
+ TAILQ_FOREACH(obj, &c->selcol->selrow->seltab->menuq, entry) {
+ menu = (struct Menu *)obj;
+ wins[1] = menu->frame;
+ XRestackWindows(dpy, wins, 2);
+ wins[0] = menu->frame;
+ }
ewmhsetclientsstacking();
}
@@ -1705,7 +1615,7 @@ tabfocus(struct Tab *tab, int gotodesk)
tab->row->col->selrow = tab->row;
tab->row->col->c->selcol = tab->row->col;
if (gotodesk)
- deskfocus(c->mon, c->issticky ? c->mon->seldesk : c->desk, 0);
+ deskupdate(c->mon, c->issticky ? c->mon->seldesk : c->desk);
if (tab->row->fact == 0.0)
rowstack(tab->row->col, tab->row);
XRaiseWindow(dpy, tab->frame);
@@ -1721,7 +1631,7 @@ tabfocus(struct Tab *tab, int gotodesk)
ewmhsetactivewindow(tab->obj.win);
if (tab->isurgent)
tabclearurgency(tab);
- menumap(tab);
+ tabhidemenus(tab, REMOVE);
containeraddfocus(c);
containerdecorate(c, NULL, NULL, 1, 0);
containerminimize(c, 0, 0);
@@ -1732,7 +1642,7 @@ tabfocus(struct Tab *tab, int gotodesk)
}
if (wm.prevfocused != NULL && wm.prevfocused != wm.focused) {
if (tab != wm.prevfocused->selcol->selrow->seltab)
- menuunmap(wm.prevfocused->selcol->selrow->seltab);
+ tabhidemenus(wm.prevfocused->selcol->selrow->seltab, ADD);
containerdecorate(wm.prevfocused, NULL, NULL, 1, 0);
ewmhsetstate(wm.prevfocused);
}
@@ -1774,7 +1684,7 @@ tabdecorate(struct Tab *t, int pressed)
/* write tab title */
if (t->name != NULL)
- drawtitle(t->pixtitle, t->name, t->w, drawlines, style, pressed);
+ drawtitle(t->pixtitle, t->name, t->w, drawlines, style, pressed, 0);
/* draw frame background */
drawbackground(t->pix, 0, 0, t->winw, t->winh, style);
@@ -1835,24 +1745,6 @@ dialogconfigure(struct Dialog *d, unsigned int valuemask, XWindowChanges *wc)
dialogmoveresize(d);
}
-/* configure menu window */
-void
-menuconfigure(struct Menu *menu, unsigned int valuemask, XWindowChanges *wc)
-{
- if (menu == NULL)
- return;
- if (valuemask & CWX)
- menu->x = wc->x;
- if (valuemask & CWY)
- menu->y = wc->y;
- if (valuemask & CWWidth)
- menu->w = wc->width;
- if (valuemask & CWHeight)
- menu->h = wc->height;
- menumoveresize(menu);
- menudecorate(menu, 0);
-}
-
/* commit dialog size and position */
void
dialogmoveresize(struct Dialog *dial)
@@ -1874,126 +1766,6 @@ dialogmoveresize(struct Dialog *dial)
}
}
-void
-menuincrmove(struct Menu *menu, int x, int y)
-{
- menu->x += x;
- menu->y += y;
- snaptoedge(&menu->x, &menu->y, menu->w, menu->h);
- XMoveWindow(dpy, menu->frame, menu->x, menu->y);
-}
-
-/* commit menu geometry */
-void
-menumoveresize(struct Menu *menu)
-{
- XMoveResizeWindow(dpy, menu->frame, menu->x, menu->y, menu->w, menu->h);
- XMoveWindow(dpy, menu->button, menu->w - config.borderwidth - config.titlewidth, config.borderwidth);
- XResizeWindow(dpy, menu->titlebar, max(1, menu->w - 2 * config.borderwidth - config.titlewidth), config.titlewidth);
- XResizeWindow(dpy, menu->obj.win, menu->w - 2 * config.borderwidth, menu->h - 2 * config.borderwidth - config.titlewidth);
-}
-
-/* decorate menu */
-void
-menudecorate(struct Menu *menu, int titlepressed)
-{
- int tw, th;
-
- if (menu->pw != menu->w || menu->ph != menu->h || menu->pix == None)
- pixmapnew(&menu->pix, menu->frame, menu->w, menu->h);
- menu->pw = menu->w;
- menu->ph = menu->h;
- tw = max(1, menu->w - 2 * config.borderwidth - config.titlewidth);
- th = config.titlewidth;
- if (menu->tw != tw || menu->th != th || menu->pixtitlebar == None)
- pixmapnew(&menu->pixtitlebar, menu->titlebar, tw, th);
- menu->tw = tw;
- menu->th = th;
-
- drawbackground(menu->pix, 0, 0, menu->w, menu->h, FOCUSED);
- drawborders(menu->pix, menu->w, menu->h, FOCUSED);
-
- drawbackground(menu->pixtitlebar, 0, 0, menu->tw, menu->th, FOCUSED);
- drawshadow(menu->pixtitlebar, 0, 0, menu->tw, config.titlewidth, FOCUSED, titlepressed);
- /* write menu title */
- if (menu->name != NULL)
- drawtitle(menu->pixtitlebar, menu->name, menu->tw, 0, FOCUSED, 0);
- buttonrightdecorate(menu->button, menu->pixbutton, FOCUSED, 0);
- drawcommit(menu->pix, menu->frame, menu->pw, menu->ph);
- drawcommit(menu->pixtitlebar, menu->titlebar, menu->tw, menu->th);
-}
-
-/* put menu on beginning of menu list */
-void
-menuaddraise(struct Tab *tab, struct Menu *menu)
-{
- menudelraise(tab, menu);
- TAILQ_INSERT_HEAD(&tab->menuq, (struct Object *)menu, entry);
- XSetInputFocus(dpy, menu->obj.win, RevertToParent, CurrentTime);
-}
-
-/* place menu next to its container */
-void
-menuplace(struct Menu *menu)
-{
- struct Container *c;
-
- c = menu->tab->row->col->c;
- fitmonitor(c->mon, &menu->x, &menu->y, &menu->w, &menu->h, 1.0);
- menumoveresize(menu);
-}
-
-/* change desktop */
-void
-deskfocus(struct Monitor *mon, int desk, int focus)
-{
- struct Container *c;
-
- if (desk < 0 || desk >= config.ndesktops || desk == wm.selmon->seldesk)
- return;
- if (!deskisvisible(mon, desk)) {
- /* unhide cointainers of new current desktop
- * hide containers of previous current desktop */
- TAILQ_FOREACH(c, &wm.focusq, entry) {
- if (!c->isminimized && c->desk == desk) {
- containerhide(c, 0);
- } else if (!c->issticky && c->desk == mon->seldesk) {
- containerhide(c, 1);
- }
- }
- }
-
- /* update current desktop */
- wm.selmon = mon;
- wm.selmon->seldesk = desk;
- if (wm.showingdesk)
- deskshow(0);
- ewmhsetcurrentdesktop(desk);
-
- /* focus client on the new current desktop */
- if (focus) {
- c = getnextfocused(mon, desk);
- if (c != NULL) {
- tabfocus(c->selcol->selrow->seltab, 0);
- } else {
- tabfocus(NULL, 0);
- }
- }
-}
-
-/* (un)show desktop */
-void
-deskshow(int show)
-{
- struct Container *c;
-
- TAILQ_FOREACH(c, &wm.focusq, entry)
- if (!c->isminimized)
- containerhide(c, show);
- wm.showingdesk = show;
- ewmhsetshowingdesktop(show);
-}
-
/* create container for tab */
void
managetab(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window leader, XRectangle rect, int state, int ignoreunmap)
@@ -2053,29 +1825,6 @@ managedialog(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window
ewmhsetclientsstacking();
}
-/* assign menu to tab */
-void
-managemenu(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window leader, XRectangle rect, int state, int ignoreunmap)
-{
- struct Menu *menu;
-
- (void)mon;
- (void)desk;
- (void)leader;
- (void)state;
- menu = menunew(win, rect.x, rect.y, rect.width, rect.height, ignoreunmap);
- menu->tab = tab;
- winupdatetitle(menu->obj.win, &menu->name);
- TAILQ_INSERT_HEAD(&tab->menuq, (struct Object *)menu, entry);
- icccmwmstate(menu->obj.win, NormalState);
- menuplace(menu);
- menudecorate(menu, 0);
- if (wm.focused != NULL && wm.focused->selcol->selrow->seltab == tab)
- tabfocus(tab, 0);
- ewmhsetclients();
- ewmhsetclientsstacking();
-}
-
/* unmanage tab (and delete its row if it is the only tab); return whether deletion occurred */
int
unmanagetab(struct Object *obj, int ignoreunmap)
@@ -2147,31 +1896,3 @@ unmanagedialog(struct Object *obj, int ignoreunmap)
free(dial);
return 1;
}
-
-/* delete menu; return whether menu was deleted */
-int
-unmanagemenu(struct Object *obj, int ignoreunmap)
-{
- struct Menu *menu;
-
- menu = (struct Menu *)obj;
- if (ignoreunmap && menu->ignoreunmap) {
- menu->ignoreunmap--;
- return 0;
- }
- menudelraise(menu->tab, menu);
- if (menu->pix != None)
- XFreePixmap(dpy, menu->pix);
- if (menu->pixbutton != None)
- XFreePixmap(dpy, menu->pixbutton);
- if (menu->pixtitlebar != None)
- XFreePixmap(dpy, menu->pixtitlebar);
- icccmdeletestate(menu->obj.win);
- XReparentWindow(dpy, menu->obj.win, root, 0, 0);
- XDestroyWindow(dpy, menu->frame);
- XDestroyWindow(dpy, menu->titlebar);
- XDestroyWindow(dpy, menu->button);
- free(menu->name);
- free(menu);
- return 1;
-}
diff --git a/xdock.c b/xdock.c
@@ -12,9 +12,40 @@ dockdecorate(void)
drawcommit(dock.pix, dock.win, dock.w, dock.h);
}
+/* configure dockapp window */
+void
+dockappconfigure(struct Dockapp *dapp, unsigned int valuemask, XWindowChanges *wc)
+{
+ if (dapp == NULL)
+ return;
+ if (valuemask & CWWidth)
+ dapp->w = wc->width;
+ if (valuemask & CWHeight)
+ dapp->h = wc->height;
+ switch (config.dockgravity[0]) {
+ case 'N':
+ case 'S':
+ if (dapp->state & SHRUNK)
+ dapp->slotsize = dapp->w;
+ else
+ dapp->slotsize = (dapp->w / config.dockspace + (dapp->w % config.dockspace ? 1 : 0)) * config.dockspace;
+ dapp->h = min(config.dockwidth, dapp->h);
+ break;
+ case 'W':
+ case 'E':
+ default:
+ if (dapp->state & SHRUNK)
+ dapp->slotsize = dapp->h;
+ else
+ dapp->slotsize = (dapp->h / config.dockspace + (dapp->h % config.dockspace ? 1 : 0)) * config.dockspace;
+ dapp->w = min(config.dockwidth, dapp->w);
+ break;
+ }
+}
+
/* create dockapp */
static void
-dockappnew(Window win, int w, int h, int dockpos, int ignoreunmap)
+dockappnew(Window win, int w, int h, int dockpos, int state, int ignoreunmap)
{
struct Dockapp *dapp;
struct Object *prev;
@@ -23,11 +54,13 @@ dockappnew(Window win, int w, int h, int dockpos, int ignoreunmap)
*dapp = (struct Dockapp){
.obj.type = TYPE_DOCKAPP,
.obj.win = win,
- .w = w,
- .h = h,
+ .x = 0,
+ .y = 0,
+ .w = 0,
+ .h = 0,
.ignoreunmap = ignoreunmap,
- .dockpos = abs(dockpos),
- .extend = dockpos < 0,
+ .dockpos = dockpos,
+ .state = state,
};
TAILQ_FOREACH_REVERSE(prev, &dock.dappq, Queue, entry)
if (((struct Dockapp *)prev)->dockpos <= dapp->dockpos)
@@ -37,26 +70,14 @@ dockappnew(Window win, int w, int h, int dockpos, int ignoreunmap)
} else {
TAILQ_INSERT_HEAD(&dock.dappq, (struct Object *)dapp, entry);
}
- switch (config.dockgravity[0]) {
- case 'N':
- dapp->slotsize = dapp->w / config.dockspace + (dapp->w % config.dockspace ? 1 : 0);
- dapp->h = min(config.dockwidth, dapp->h);
- break;
- case 'S':
- dapp->slotsize = dapp->w / config.dockspace + (dapp->w % config.dockspace ? 1 : 0);
- dapp->h = min(config.dockwidth, dapp->h);
- break;
- case 'W':
- dapp->slotsize = dapp->h / config.dockspace + (dapp->h % config.dockspace ? 1 : 0);
- dapp->w = min(config.dockwidth, dapp->w);
- break;
- case 'E':
- default:
- dapp->slotsize = dapp->h / config.dockspace + (dapp->h % config.dockspace ? 1 : 0);
- dapp->w = min(config.dockwidth, dapp->w);
- break;
- }
- dapp->slotsize *= config.dockspace;
+ dockappconfigure(
+ dapp,
+ CWWidth | CWHeight,
+ &(XWindowChanges){
+ .width = w,
+ .height = h,
+ }
+ );
}
/* update dock position; create it, if necessary */
@@ -215,7 +236,7 @@ dockupdatefull(void)
size = 0;
TAILQ_FOREACH(p, &dock.dappq, entry) {
dapp = (struct Dockapp *)p;
- if (dapp->extend) {
+ if (dapp->state & EXTEND) {
nextend++;
} else {
size += dapp->slotsize;
@@ -230,7 +251,7 @@ dockupdatefull(void)
dapp = (struct Dockapp *)p;
switch (config.dockgravity[0]) {
case 'N':
- if (dapp->extend) {
+ if (dapp->state & EXTEND) {
dapp->w = max(1, (i + 1) * part - i * part);
n = dapp->w;
} else {
@@ -240,7 +261,7 @@ dockupdatefull(void)
dapp->y = DOCKBORDER + max(0, (config.dockwidth - dapp->h) / 2);
break;
case 'S':
- if (dapp->extend) {
+ if (dapp->state & EXTEND) {
dapp->w = max(1, (i + 1) * part - i * part);
n = dapp->w;
} else {
@@ -250,7 +271,7 @@ dockupdatefull(void)
dapp->y = DOCKBORDER + max(0, (config.dockwidth - dapp->h) / 2);
break;
case 'W':
- if (dapp->extend) {
+ if (dapp->state & EXTEND) {
dapp->h = max(1, (i + 1) * part - i * part);
n = dapp->h;
} else {
@@ -261,7 +282,7 @@ dockupdatefull(void)
break;
case 'E':
default:
- if (dapp->extend) {
+ if (dapp->state & EXTEND) {
dapp->h = max(1, (i + 1) * part - i * part);
n = dapp->h;
} else {
@@ -289,7 +310,7 @@ dockupdate(void)
dockupdateresizeable();
}
dockdecorate();
- wins[0] = wm.docklayer;
+ wins[0] = wm.layers[LAYER_DOCK].frame;
wins[1] = dock.win;
XMoveResizeWindow(dpy, dock.win, dock.x, dock.y, dock.w, dock.h);
XRestackWindows(dpy, wins, 2);
@@ -299,14 +320,14 @@ dockupdate(void)
/* map dockapp window */
void
-managedockapp(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window leader, XRectangle rect, int pos, int ignoreunmap)
+managedockapp(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window leader, XRectangle rect, int state, int ignoreunmap)
{
(void)tab;
(void)mon;
(void)desk;
(void)leader;
XReparentWindow(dpy, win, dock.win, 0, 0);
- dockappnew(win, rect.width, rect.height, pos, ignoreunmap);
+ dockappnew(win, rect.width, rect.height, rect.x, state, ignoreunmap);
dockupdate();
monupdatearea();
}
diff --git a/xdraw.c b/xdraw.c
@@ -56,6 +56,27 @@ getexposed(Window win, Pixmap *pix, int *pw, int *ph)
*ph = dock.h;
return 1;
}
+ TAILQ_FOREACH(m, &wm.menuq, entry) {
+ menu = (struct Menu *)m;
+ if (menu->frame == win) {
+ *pix = menu->pix;
+ *pw = menu->pw;
+ *ph = menu->ph;
+ return 1;
+ }
+ if (menu->titlebar == win) {
+ *pix = menu->pixtitlebar;
+ *pw = menu->tw;
+ *ph = menu->th;
+ return 1;
+ }
+ if (menu->button == win) {
+ *pix = menu->pixbutton;
+ *pw = config.titlewidth;
+ *ph = config.titlewidth;
+ return 1;
+ }
+ }
TAILQ_FOREACH(n, &wm.notifq, entry) {
notif = (struct Notification *)n;
if (notif->frame == win) {
@@ -159,7 +180,7 @@ drawcommit(Pixmap pix, Window win, int w, int h)
/* draw text into drawable */
void
-drawtitle(Drawable pix, const char *text, int w, int drawlines, int style, int pressed)
+drawtitle(Drawable pix, const char *text, int w, int drawlines, int style, int pressed, int ismenu)
{
XGCValues val;
XGlyphInfo box;
@@ -171,7 +192,7 @@ drawtitle(Drawable pix, const char *text, int w, int drawlines, int style, int p
top = theme.border[style][pressed ? COLOR_DARK : COLOR_LIGHT];
bot = theme.border[style][pressed ? COLOR_LIGHT : COLOR_DARK];
- color = &theme.fg[style][1];
+ color = &theme.fg[style][ismenu ? 1 : drawlines];
draw = XftDrawCreate(dpy, pix, visual, colormap);
len = strlen(text);
XftTextExtentsUtf8(dpy, theme.font, text, len, &box);
diff --git a/xevents.c b/xevents.c
@@ -135,6 +135,13 @@ isuserplaced(Window win)
return (XGetWMNormalHints(dpy, win, &size, &dl) && (size.flags & USPosition));
}
+/* check if desktop is visible */
+static int
+deskisvisible(struct Monitor *mon, int desk)
+{
+ return mon->seldesk == desk;
+}
+
/* get pointer to managed object given a window */
static struct Object *
getmanaged(Window win)
@@ -148,7 +155,18 @@ getmanaged(Window win)
GETMANAGED(dock.dappq, p, win)
GETMANAGED(wm.barq, p, win)
GETMANAGED(wm.notifq, p, win)
- GETMANAGED(wm.splashq, p, win)
+ TAILQ_FOREACH(p, &wm.splashq, entry) {
+ if (p->win == win || ((struct Splash *)p)->frame) {
+ return p;
+ }
+ }
+ TAILQ_FOREACH(menu, &wm.menuq, entry) {
+ if (menu->win == win ||
+ ((struct Menu *)menu)->frame == win ||
+ ((struct Menu *)menu)->button == win ||
+ ((struct Menu *)menu)->titlebar == win)
+ return menu;
+ }
TAILQ_FOREACH(c, &wm.focusq, entry) {
if (c->frame == win)
return (struct Object *)c->selcol->selrow->seltab;
@@ -219,7 +237,7 @@ getleaderof(Window leader)
TAILQ_FOREACH(c, &wm.focusq, entry) {
TAB_FOREACH_BEGIN(c, tab){
- if (tab->win == leader || ((struct Tab *)tab)->leader == leader)
+ if (leader != None && (tab->win == leader || ((struct Tab *)tab)->leader == leader))
return (struct Tab *)tab;
}TAB_FOREACH_END
}
@@ -334,12 +352,11 @@ getmwmhints(Window win)
/* get window info based on its type */
static int
-getwintype(Window win, Window *leader, struct Tab **tab, int *state)
+getwintype(Window win, Window *leader, struct Tab **tab, int *state, XRectangle *rect)
{
/* rules for identifying windows */
enum { CLASS = 0, INSTANCE = 1, ROLE = 2 };
char *rule[] = { "_", "_", "_" };
- char *endp;
struct MwmHints *mwmhints;
XClassHint classh;
@@ -348,11 +365,12 @@ getwintype(Window win, Window *leader, struct Tab **tab, int *state)
Atom prop;
size_t i;
long n;
- int type, isdockapp, ismenu;
+ int type, isdockapp, ismenu, pos;
char *ds;
char buf[NAMEMAXLEN];
char role[NAMEMAXLEN];
+ pos = 0;
*tab = NULL;
*state = 0;
type = TYPE_UNKNOWN;
@@ -423,17 +441,19 @@ getwintype(Window win, Window *leader, struct Tab **tab, int *state)
if (strcasestr(xval.addr, "sticky") != NULL) {
*state |= STICKY;
}
+ if (strcasestr(xval.addr, "extend") != NULL) {
+ *state |= EXTEND;
+ }
+ if (strcasestr(xval.addr, "shrunk") != NULL) {
+ *state |= SHRUNK;
+ }
}
/* check for dockapp position */
(void)snprintf(buf, NAMEMAXLEN, "shod.%s.%s.%s.dockpos", rule[CLASS], rule[INSTANCE], rule[ROLE]);
if (XrmGetResource(xdb, buf, "*", &ds, &xval) == True) {
- if ((n = strtol(xval.addr, &endp, 10)) >= 0 && n < INT_MAX) {
- if (*endp == '*') {
- *state = -n;
- } else {
- *state = n;
- }
+ if ((n = strtol(xval.addr, NULL, 10)) >= 0 && n < INT_MAX) {
+ pos = n;
}
}
}
@@ -472,12 +492,9 @@ getwintype(Window win, Window *leader, struct Tab **tab, int *state)
prop == atoms[_NET_WM_WINDOW_TYPE_MENU] ||
prop == atoms[_NET_WM_WINDOW_TYPE_UTILITY] ||
prop == atoms[_NET_WM_WINDOW_TYPE_TOOLBAR]) {
- if (*tab == NULL) {
+ if (*tab == NULL)
*tab = getleaderof(*leader);
- }
- if (*tab != NULL) {
- type = TYPE_MENU;
- }
+ type = TYPE_MENU;
} else if (*tab != NULL) {
type = config.floatdialog ? TYPE_MENU : TYPE_DIALOG;
} else {
@@ -485,6 +502,8 @@ getwintype(Window win, Window *leader, struct Tab **tab, int *state)
}
done:
+ if (type == TYPE_DOCKAPP)
+ rect->x = rect->y = pos;
return type;
}
@@ -576,6 +595,79 @@ getquadrant(int w, int h, int x, int y)
return C;
}
+/* (un)show desktop */
+static void
+deskshow(int show)
+{
+ struct Object *obj;
+ struct Container *c;
+
+ TAILQ_FOREACH(c, &wm.focusq, entry)
+ if (!c->isminimized)
+ containerhide(c, show);
+ TAILQ_FOREACH(obj, &wm.splashq, entry)
+ splashhide((struct Splash *)obj, show);
+ wm.showingdesk = show;
+ ewmhsetshowingdesktop(show);
+}
+
+/* update desktop */
+void
+deskupdate(struct Monitor *mon, int desk)
+{
+ struct Object *obj;
+ struct Splash *splash;
+ struct Container *c;
+
+ if (desk < 0 || desk >= config.ndesktops || (mon == wm.selmon && desk == wm.selmon->seldesk))
+ return;
+ if (wm.showingdesk)
+ deskshow(0);
+ if (!deskisvisible(mon, desk)) {
+ /* unhide cointainers of new current desktop
+ * hide containers of previous current desktop */
+ TAILQ_FOREACH(c, &wm.focusq, entry) {
+ if (c->mon != mon)
+ continue;
+ if (!c->isminimized && c->desk == desk) {
+ containerhide(c, 0);
+ } else if (!c->issticky && c->desk == mon->seldesk) {
+ containerhide(c, 1);
+ }
+ }
+ TAILQ_FOREACH(obj, &wm.splashq, entry) {
+ splash = (struct Splash *)obj;
+ if (splash->mon != mon)
+ continue;
+ if (splash->desk == desk) {
+ splashhide(splash, 0);
+ } else if (splash->desk == mon->seldesk) {
+ splashhide(splash, 1);
+ }
+ }
+ }
+ wm.selmon = mon;
+ wm.selmon->seldesk = desk;
+ ewmhsetcurrentdesktop(desk);
+}
+
+/* change desktop */
+static void
+deskfocus(struct Monitor *mon, int desk)
+{
+ struct Container *c;
+
+ if (desk < 0 || desk >= config.ndesktops || (mon == wm.selmon && desk == wm.selmon->seldesk))
+ return;
+ deskupdate(mon, desk);
+ c = getnextfocused(mon, desk);
+ if (c != NULL) {
+ tabfocus(c->selcol->selrow->seltab, 0);
+ } else {
+ tabfocus(NULL, 0);
+ }
+}
+
/* call one of the manage- functions */
static void
manage(Window win, XRectangle rect, int ignoreunmap)
@@ -586,7 +678,7 @@ manage(Window win, XRectangle rect, int ignoreunmap)
if (getmanaged(win) != NULL)
return;
- type = getwintype(win, &leader, &tab, &state);
+ type = getwintype(win, &leader, &tab, &state, &rect);
if (type == TYPE_DESKTOP) {
/* we do not handle desktop windows */
XLowerWindow(dpy, win);
@@ -1131,12 +1223,13 @@ xeventbuttonpress(XEvent *e)
if ((obj = getmanaged(ev->window)) == NULL) {
/* if user clicked in no window, focus the monitor below cursor */
if ((mon = getmon(ev->x_root, ev->y_root)) != NULL)
- deskfocus(mon, mon->seldesk, 1);
+ deskfocus(mon, mon->seldesk);
goto done;
}
menu = NULL;
tab = NULL;
+ c = NULL;
switch (obj->type) {
case TYPE_NORMAL:
tab = (struct Tab *)obj;
@@ -1149,27 +1242,32 @@ xeventbuttonpress(XEvent *e)
case TYPE_MENU:
menu = (struct Menu *)obj;
tab = menu->tab;
- c = tab->row->col->c;
+ if (tab != NULL)
+ c = tab->row->col->c;
break;
+ case TYPE_SPLASH:
+ splashrise((struct Splash *)obj);
+ goto done;
default:
if ((mon = getmon(ev->x_root, ev->y_root)) != NULL)
- deskfocus(mon, mon->seldesk, 1);
+ deskfocus(mon, mon->seldesk);
goto done;
}
/* raise menu above others or focus tab */
if (menu != NULL)
- menuaddraise(tab, menu);
+ menuaddraise(menu);
else if ((wm.focused == NULL || tab != wm.focused->selcol->selrow->seltab) && ev->button == Button1)
tabfocus(tab, 1);
/* raise client */
- if (ev->button == Button1)
- containerraise(c, c->isfullscreen, c->abovebelow);
-
- /* get pointer position */
- if (!XTranslateCoordinates(dpy, ev->window, c->frame, ev->x, ev->y, &x, &y, &dw))
- goto done;
+ if (ev->button == Button1) {
+ if (c != NULL) {
+ containerraise(c, c->isfullscreen, c->abovebelow);
+ } else if (menu != NULL) {
+ menuraise(menu);
+ }
+ }
/* do action performed by mouse */
if (menu != NULL) {
@@ -1181,10 +1279,14 @@ xeventbuttonpress(XEvent *e)
|| (isvalidstate(ev->state) && ev->button == Button1)) {
mousemove(FLOAT_MENU, menu, ev->x_root, ev->y_root, 0);
} else if (isvalidstate(ev->state) && ev->button == Button3) {
+ if (!XTranslateCoordinates(dpy, ev->window, menu->frame, ev->x, ev->y, &x, &y, &dw))
+ goto done;
o = getquadrant(menu->w, menu->h, x, y);
mouseresize(FLOAT_MENU, menu, ev->x_root, ev->y_root, o);
}
- } else {
+ } else if (tab != NULL) {
+ if (!XTranslateCoordinates(dpy, ev->window, c->frame, ev->x, ev->y, &x, &y, &dw))
+ goto done;
if (ev->window == tab->title && ev->button == Button1) {
if (lastc == c && ev->time - lasttime < DOUBLECLICK) {
containersetstate(
@@ -1242,7 +1344,6 @@ xeventclientmessage(XEvent *e)
{
struct Container *c = NULL;
struct Tab *tab = NULL;
- struct Menu *menu = NULL;
struct Object *obj;
XClientMessageEvent *ev;
XWindowChanges wc;
@@ -1261,20 +1362,15 @@ xeventclientmessage(XEvent *e)
tab = ((struct Dialog *)obj)->tab;
c = tab->row->col->c;
break;
- case TYPE_MENU:
- menu = (struct Menu *)obj;
- tab = menu->tab;
- c = tab->row->col->c;
- break;
}
}
if (ev->message_type == atoms[_NET_CURRENT_DESKTOP]) {
- deskfocus(wm.selmon, ev->data.l[0], 1);
+ deskfocus(wm.selmon, ev->data.l[0]);
} else if (ev->message_type == atoms[_NET_SHOWING_DESKTOP]) {
if (ev->data.l[0]) {
deskshow(1);
} else {
- deskfocus(wm.selmon, wm.selmon->seldesk, 1);
+ deskfocus(wm.selmon, wm.selmon->seldesk);
}
} else if (ev->message_type == atoms[_NET_WM_STATE]) {
if (obj == NULL || obj->type != TYPE_NORMAL)
@@ -1370,8 +1466,8 @@ xeventclientmessage(XEvent *e)
*/
if (obj == NULL || (obj->type != TYPE_NORMAL && obj->type != TYPE_MENU))
return;
- if (menu != NULL) {
- p = menu;
+ if (obj->type == TYPE_MENU) {
+ p = obj;
floattype = FLOAT_MENU;
} else {
p = c;
@@ -1448,6 +1544,8 @@ xeventconfigurerequest(XEvent *e)
dialogconfigure((struct Dialog *)obj, ev->value_mask, &wc);
} else if (obj->type == TYPE_MENU) {
menuconfigure((struct Menu *)obj, ev->value_mask, &wc);
+ } else if (obj->type == TYPE_DOCKAPP) {
+ dockappconfigure((struct Dockapp *)obj, ev->value_mask, &wc);
} else if (obj->type == TYPE_NORMAL) {
if (config.honorconfig) {
containerconfigure(((struct Tab *)obj)->row->col->c, ev->value_mask, &wc);
@@ -1555,6 +1653,7 @@ xeventkeypress(XEvent *e)
alttab(e);
}
if (ev->window == wm.wmcheckwin) {
+ e->xkey.window = root;
XSendEvent(dpy, root, False, KeyPressMask, e);
}
}
diff --git a/xhints.c b/xhints.c
@@ -39,7 +39,7 @@ isobscured(struct Container *c, struct Monitor *mon, int desk, int x, int y, int
if (!isobscured(c, mon, desk, x, y, w, c->y - y))
return 0;
if (x < c->x)
- if (!isobscured(c, mon, desk, x, y, c->x - x, y))
+ if (!isobscured(c, mon, desk, x, y, c->x - x, h))
return 0;
if (y + h > c->y + c->h)
if (!isobscured(c, mon, desk, x, c->y + c->h, w, h))
diff --git a/xmenu.c b/xmenu.c
@@ -0,0 +1,226 @@
+#include "shod.h"
+
+/* create new menu */
+static struct Menu *
+menunew(Window win, int x, int y, int w, int h, int ignoreunmap)
+{
+ struct Menu *menu;
+
+ menu = emalloc(sizeof(*menu));
+ *menu = (struct Menu){
+ .titlebar = None,
+ .button = None,
+ .obj.win = win,
+ .obj.type = TYPE_MENU,
+ .pix = None,
+ .pixbutton = None,
+ .pixtitlebar = None,
+ .x = x - config.borderwidth,
+ .y = y - config.borderwidth,
+ .w = w + config.borderwidth * 2,
+ .h = h + config.borderwidth * 2 + config.titlewidth,
+ .ignoreunmap = ignoreunmap,
+ };
+ menu->frame = XCreateWindow(dpy, root, 0, 0,
+ w + config.borderwidth * 2,
+ h + config.borderwidth * 2 + config.titlewidth, 0,
+ depth, CopyFromParent, visual,
+ clientmask, &clientswa),
+ menu->titlebar = XCreateWindow(dpy, menu->frame, config.borderwidth, config.borderwidth,
+ max(1, menu->w - 2 * config.borderwidth - config.titlewidth),
+ config.titlewidth, 0,
+ depth, CopyFromParent, visual,
+ clientmask, &clientswa);
+ menu->button = XCreateWindow(dpy, menu->frame, menu->w - config.borderwidth - config.titlewidth, config.borderwidth,
+ config.titlewidth, config.titlewidth, 0,
+ depth, CopyFromParent, visual,
+ clientmask, &clientswa);
+ menu->pixbutton = XCreatePixmap(dpy, menu->button, config.titlewidth, config.titlewidth, depth);
+ XDefineCursor(dpy, menu->button, wm.cursors[CURSOR_PIRATE]);
+ XReparentWindow(dpy, menu->obj.win, menu->frame, config.borderwidth, config.borderwidth + config.titlewidth);
+ XMapWindow(dpy, menu->obj.win);
+ XMapWindow(dpy, menu->button);
+ XMapWindow(dpy, menu->titlebar);
+ return menu;
+}
+
+/* remove menu from the menu list */
+static void
+menudelraise(struct Menu *menu)
+{
+ if (TAILQ_EMPTY(menu->menuq))
+ return;
+ TAILQ_REMOVE(menu->menuq, (struct Object *)menu, entry);
+}
+
+/* configure menu window */
+void
+menuconfigure(struct Menu *menu, unsigned int valuemask, XWindowChanges *wc)
+{
+ if (menu == NULL)
+ return;
+ if (valuemask & CWX)
+ menu->x = wc->x;
+ if (valuemask & CWY)
+ menu->y = wc->y;
+ if (valuemask & CWWidth)
+ menu->w = wc->width;
+ if (valuemask & CWHeight)
+ menu->h = wc->height;
+ menumoveresize(menu);
+ menudecorate(menu, 0);
+}
+
+void
+menuincrmove(struct Menu *menu, int x, int y)
+{
+ menu->x += x;
+ menu->y += y;
+ //snaptoedge(&menu->x, &menu->y, menu->w, menu->h);
+ XMoveWindow(dpy, menu->frame, menu->x, menu->y);
+}
+
+/* commit menu geometry */
+void
+menumoveresize(struct Menu *menu)
+{
+ struct Monitor *mon;
+
+ XMoveResizeWindow(dpy, menu->frame, menu->x, menu->y, menu->w, menu->h);
+ XMoveWindow(dpy, menu->button, menu->w - config.borderwidth - config.titlewidth, config.borderwidth);
+ XResizeWindow(dpy, menu->titlebar, max(1, menu->w - 2 * config.borderwidth - config.titlewidth), config.titlewidth);
+ XResizeWindow(dpy, menu->obj.win, menu->w - 2 * config.borderwidth, menu->h - 2 * config.borderwidth - config.titlewidth);
+ if (menu->tab == NULL && (mon = getmon(menu->x, menu->y)) != NULL) {
+ menu->mon = mon;
+ }
+}
+
+/* decorate menu */
+void
+menudecorate(struct Menu *menu, int titlepressed)
+{
+ int tw, th;
+
+ if (menu->pw != menu->w || menu->ph != menu->h || menu->pix == None)
+ pixmapnew(&menu->pix, menu->frame, menu->w, menu->h);
+ menu->pw = menu->w;
+ menu->ph = menu->h;
+ tw = max(1, menu->w - 2 * config.borderwidth - config.titlewidth);
+ th = config.titlewidth;
+ if (menu->tw != tw || menu->th != th || menu->pixtitlebar == None)
+ pixmapnew(&menu->pixtitlebar, menu->titlebar, tw, th);
+ menu->tw = tw;
+ menu->th = th;
+
+ drawbackground(menu->pix, 0, 0, menu->w, menu->h, FOCUSED);
+ drawborders(menu->pix, menu->w, menu->h, FOCUSED);
+
+ drawbackground(menu->pixtitlebar, 0, 0, menu->tw, menu->th, FOCUSED);
+ drawshadow(menu->pixtitlebar, 0, 0, menu->tw, config.titlewidth, FOCUSED, titlepressed);
+ /* write menu title */
+ if (menu->name != NULL)
+ drawtitle(menu->pixtitlebar, menu->name, menu->tw, 0, FOCUSED, 0, 1);
+ buttonrightdecorate(menu->button, menu->pixbutton, FOCUSED, 0);
+ drawcommit(menu->pix, menu->frame, menu->pw, menu->ph);
+ drawcommit(menu->pixtitlebar, menu->titlebar, menu->tw, menu->th);
+}
+
+/* put menu on beginning of menu list */
+void
+menuaddraise(struct Menu *menu)
+{
+ menudelraise(menu);
+ TAILQ_INSERT_HEAD(menu->menuq, (struct Object *)menu, entry);
+ XSetInputFocus(dpy, menu->obj.win, RevertToParent, CurrentTime);
+}
+
+/* place menu next to its container */
+void
+menuplace(struct Monitor *mon, struct Menu *menu)
+{
+ fitmonitor(mon, &menu->x, &menu->y, &menu->w, &menu->h, 1.0);
+ menumoveresize(menu);
+}
+
+/* raise desktop menu */
+void
+menuraise(struct Menu *menu)
+{
+ Window wins[2];
+
+ wins[1] = menu->frame;
+ wins[0] = wm.layers[LAYER_MENU].frame;
+ XRestackWindows(dpy, wins, 2);
+}
+
+/* (un)hide menu */
+void
+menuhide(struct Menu *menu, int hide)
+{
+ if (hide)
+ XUnmapWindow(dpy, menu->frame);
+ else
+ XMapWindow(dpy, menu->frame);
+ icccmwmstate(menu->obj.win, (hide ? IconicState : NormalState));
+}
+
+/* assign menu to tab */
+void
+managemenu(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window leader, XRectangle rect, int state, int ignoreunmap)
+{
+ struct Queue *menuq;
+ struct Menu *menu;
+
+ (void)leader;
+ (void)desk;
+ (void)state;
+ menu = menunew(win, rect.x, rect.y, rect.width, rect.height, ignoreunmap);
+ if (tab) {
+ menuq = &tab->menuq;
+ mon = tab->row->col->c->mon;
+ } else {
+ menuq = &wm.menuq;
+ }
+ menu->mon = mon;
+ menu->menuq = menuq;
+ menu->tab = tab;
+ winupdatetitle(menu->obj.win, &menu->name);
+ TAILQ_INSERT_HEAD(menuq, (struct Object *)menu, entry);
+ icccmwmstate(menu->obj.win, NormalState);
+ menuplace(mon, menu);
+ menudecorate(menu, 0);
+ if (tab != NULL && wm.focused != NULL && wm.focused->selcol->selrow->seltab == tab) {
+ tabfocus(tab, 0);
+ } else {
+ menuraise(menu);
+ XMapWindow(dpy, menu->frame);
+ }
+}
+
+/* delete menu; return whether menu was deleted */
+int
+unmanagemenu(struct Object *obj, int ignoreunmap)
+{
+ struct Menu *menu;
+
+ menu = (struct Menu *)obj;
+ if (ignoreunmap && menu->ignoreunmap) {
+ menu->ignoreunmap--;
+ return 0;
+ }
+ menudelraise(menu);
+ if (menu->pix != None)
+ XFreePixmap(dpy, menu->pix);
+ if (menu->pixbutton != None)
+ XFreePixmap(dpy, menu->pixbutton);
+ if (menu->pixtitlebar != None)
+ XFreePixmap(dpy, menu->pixtitlebar);
+ icccmdeletestate(menu->obj.win);
+ XReparentWindow(dpy, menu->obj.win, root, 0, 0);
+ XDestroyWindow(dpy, menu->frame);
+ XDestroyWindow(dpy, menu->titlebar);
+ XDestroyWindow(dpy, menu->button);
+ free(menu->name);
+ free(menu);
+ return 1;
+}
diff --git a/xmon.c b/xmon.c
@@ -38,12 +38,19 @@ monnew(XineramaScreenInfo *info)
void
mondel(struct Monitor *mon)
{
+ struct Object *obj;
struct Container *c;
TAILQ_REMOVE(&wm.monq, mon, entry);
TAILQ_FOREACH(c, &wm.focusq, entry)
if (c->mon == mon)
c->mon = NULL;
+ TAILQ_FOREACH(obj, &wm.menuq, entry)
+ if (((struct Menu *)obj)->mon == mon)
+ ((struct Menu *)obj)->mon = NULL;
+ TAILQ_FOREACH(obj, &wm.splashq, entry)
+ if (((struct Splash *)obj)->mon == mon)
+ ((struct Splash *)obj)->mon = NULL;
free(mon);
}
@@ -133,7 +140,7 @@ monupdate(void)
/* move menus to new monitor */
TAB_FOREACH_BEGIN(c, t) {
TAILQ_FOREACH(m, &((struct Tab *)t)->menuq, entry) {
- menuplace((struct Menu *)m);
+ menuplace(wm.selmon, (struct Menu *)m);
}
} TAB_FOREACH_END
@@ -141,8 +148,12 @@ monupdate(void)
ewmhsetstate(c);
}
}
+ TAILQ_FOREACH(m, &wm.menuq, entry)
+ if (((struct Menu *)m)->mon == NULL)
+ menuplace(wm.selmon, (struct Menu *)m);
TAILQ_FOREACH(s, &wm.splashq, entry)
- splashplace((struct Splash *)s);
+ if (((struct Splash *)s)->mon == NULL)
+ splashplace(wm.selmon, (struct Splash *)s);
if (focus != NULL) /* if a contained changed desktop, focus it */
tabfocus(focus->selcol->selrow->seltab, 1);
ewmhsetclientsstacking();
diff --git a/xsplash.c b/xsplash.c
@@ -14,22 +14,54 @@ splashnew(Window win, int w, int h)
.h = h,
};
((struct Object *)splash)->type = TYPE_SPLASH;
- XReparentWindow(dpy, win, root, 0, 0);
+ splash->frame = XCreateWindow(
+ dpy,
+ root,
+ 0, 0,
+ w, h,
+ 0,
+ depth, CopyFromParent, visual,
+ clientmask, &clientswa
+ );
+ XReparentWindow(dpy, win, splash->frame, 0, 0);
+ XMapWindow(dpy, splash->frame);
TAILQ_INSERT_HEAD(&wm.splashq, (struct Object *)splash, entry);
return splash;
}
/* center splash screen on monitor and raise it above other windows */
void
-splashplace(struct Splash *splash)
+splashplace(struct Monitor *mon, struct Splash *splash)
{
Window wins[2];
- fitmonitor(wm.selmon, &splash->x, &splash->y, &splash->w, &splash->h, 0.5);
- splash->x = wm.selmon->wx + (wm.selmon->ww - splash->w) / 2;
- splash->y = wm.selmon->wy + (wm.selmon->wh - splash->h) / 2;
- wins[1] = splash->obj.win;
+
+ fitmonitor(mon, &splash->x, &splash->y, &splash->w, &splash->h, 0.5);
+ splash->x = mon->wx + (mon->ww - splash->w) / 2;
+ splash->y = mon->wy + (mon->wh - splash->h) / 2;
+ wins[1] = splash->frame;
+ wins[0] = wm.layers[LAYER_NORMAL].frame;
+ XMoveWindow(dpy, splash->frame, splash->x, splash->y);
+ XRestackWindows(dpy, wins, 2);
+}
+
+/* (un)hide splash screen */
+void
+splashhide(struct Splash *splash, int hide)
+{
+ if (hide)
+ XUnmapWindow(dpy, splash->frame);
+ else
+ XMapWindow(dpy, splash->frame);
+ icccmwmstate(splash->frame, (hide ? IconicState : NormalState));
+}
+
+void
+splashrise(struct Splash *splash)
+{
+ Window wins[2];
+
+ wins[1] = splash->frame;
wins[0] = wm.layers[LAYER_NORMAL].frame;
- XMoveWindow(dpy, splash->obj.win, splash->x, splash->y);
XRestackWindows(dpy, wins, 2);
}
@@ -43,6 +75,7 @@ unmanagesplash(struct Object *obj, int dummy)
(void)dummy;
TAILQ_REMOVE(&wm.splashq, (struct Object *)splash, entry);
icccmdeletestate(splash->obj.win);
+ XDestroyWindow(dpy, splash->frame);
free(splash);
return 0;
}
@@ -54,13 +87,13 @@ managesplash(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window
struct Splash *splash;
(void)tab;
- (void)mon;
- (void)desk;
(void)leader;
(void)state;
(void)ignoreunmap;
splash = splashnew(win, rect.width, rect.height);
+ splash->mon = mon;
+ splash->desk = desk;
icccmwmstate(splash->obj.win, NormalState);
- splashplace(splash);
+ splashplace(mon, splash);
XMapWindow(dpy, splash->obj.win);
}