first import
This commit is contained in:
commit
f7173bd79d
|
@ -0,0 +1,26 @@
|
|||
MIT/X Consortium License
|
||||
|
||||
© 2006-2007 Anselm R. Garbe <garbeam at gmail dot com>
|
||||
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
|
||||
© 2006-2007 Jukka Salmi <jukka at salmi dot ch>
|
||||
© 2007 Premysl Hruby <dfenze at gmail dot com>
|
||||
© 2007 Szabolcs Nagy <nszabolcs at gmail dot com>
|
||||
© 2007 Julien Danjou <julien at danjou dot info>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,62 @@
|
|||
# jdwm - Julien's dynamic window manager
|
||||
# © 2007 Julien Danjou
|
||||
# © 2006-2007 Anselm R. Garbe, Sander van Dijk
|
||||
|
||||
include config.mk
|
||||
|
||||
SRC = client.c draw.c event.c layout.c jdwm.c tag.c util.c config.c
|
||||
OBJ = ${SRC:.c=.o} ${LAYOUTS:.c=.o}
|
||||
|
||||
all: options jdwm
|
||||
|
||||
options:
|
||||
@echo jdwm build options:
|
||||
@echo "LAYOUTS = ${LAYOUTS}"
|
||||
@echo "CFLAGS = ${CFLAGS}"
|
||||
@echo "LDFLAGS = ${LDFLAGS}"
|
||||
@echo "CC = ${CC}"
|
||||
|
||||
.c.o:
|
||||
@echo -e \\t\(CC\) $<
|
||||
@${CC} -c ${CFLAGS} $< -o $@
|
||||
|
||||
${OBJ}: jdwm.h config.mk
|
||||
|
||||
jdwm: ${OBJ}
|
||||
@echo -e \\t\(CC\) ${OBJ} -o $@
|
||||
@${CC} -o $@ ${OBJ} ${LDFLAGS}
|
||||
|
||||
clean:
|
||||
@echo cleaning
|
||||
@rm -f jdwm ${OBJ} jdwm-${VERSION}.tar.gz
|
||||
|
||||
dist: clean
|
||||
@echo creating dist tarball
|
||||
@mkdir -p jdwm-${VERSION}
|
||||
@cp -R LICENSE Makefile README config.*.h config.mk \
|
||||
jdwm.1 jdwm.h grid.h tile.h mem.h ${SRC} ${LAYOUTS} jdwm-${VERSION}
|
||||
@tar -cf jdwm-${VERSION}.tar jdwm-${VERSION}
|
||||
@gzip jdwm-${VERSION}.tar
|
||||
@rm -rf jdwm-${VERSION}
|
||||
|
||||
install: all
|
||||
@echo installing executable file to ${DESTDIR}${PREFIX}/bin
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f jdwm ${DESTDIR}${PREFIX}/bin
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/jdwm
|
||||
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@sed "s/VERSION/${VERSION}/g" < jdwm.1 > ${DESTDIR}${MANPREFIX}/man1/jdwm.1
|
||||
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/jdwm.1
|
||||
|
||||
uninstall:
|
||||
@echo removing executable file from ${DESTDIR}${PREFIX}/bin
|
||||
@rm -f ${DESTDIR}${PREFIX}/bin/jdwm
|
||||
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
|
||||
@rm -f ${DESTDIR}${MANPREFIX}/man1/jdwm.1
|
||||
|
||||
doc:
|
||||
@echo generating documentation
|
||||
@doxygen jdwm.doxygen
|
||||
|
||||
.PHONY: all options clean dist install uninstall doc
|
|
@ -0,0 +1,47 @@
|
|||
jdwm - Julien's dynamic window manager
|
||||
============================
|
||||
jdwm is an extremely fast, small, and dynamic window manager for X.
|
||||
It's based on dwm.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
In order to build jdwm you need the Xlib header files.
|
||||
|
||||
Installation
|
||||
------------
|
||||
Edit config.mk to match your local setup (jdwm is installed into
|
||||
the /usr/local namespace by default).
|
||||
|
||||
Afterwards enter the following command to build and install jdwm (if
|
||||
necessary as root):
|
||||
|
||||
make clean install
|
||||
|
||||
Running jdwm
|
||||
-----------
|
||||
Add the following line to your .xinitrc to start jdwm using startx
|
||||
or to .xsession to start jdwm using gdm/kdm/xdm...:
|
||||
|
||||
exec jdwm
|
||||
|
||||
In order to connect jdwm to a specific display, make sure that
|
||||
the DISPLAY environment variable is set correctly, e.g.:
|
||||
|
||||
DISPLAY=foo.bar:1 exec jdwm
|
||||
|
||||
(This will start jdwm on display :1 of the host foo.bar.)
|
||||
|
||||
In order to display status info in the bar, you can do something
|
||||
like this in your .xinitrc:
|
||||
|
||||
while true
|
||||
do
|
||||
echo `date` `uptime | sed 's/.*,//'`
|
||||
sleep 1
|
||||
done | jdwm
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
The configuration of jdwm is done by creating a custom config.h
|
||||
and (re)compiling the source code.
|
|
@ -0,0 +1,657 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include "jdwm.h"
|
||||
#include "util.h"
|
||||
#include "layout.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include "layouts/floating.h"
|
||||
|
||||
/* extern */
|
||||
extern int sx, sy, sw, sh; /* screen geometry */
|
||||
extern int wax, way, wah, waw; /* windowarea geometry */
|
||||
extern Client *clients, *sel, *stack; /* global client list and stack */
|
||||
extern Bool selscreen;
|
||||
extern Atom jdwmprops, wmatom[WMLast], netatom[NetLast];
|
||||
|
||||
/* static */
|
||||
|
||||
static char prop[128];
|
||||
|
||||
/** Attach client stack to clients stacks
|
||||
* \param c the client
|
||||
*/
|
||||
static inline void
|
||||
attachstack(Client * c)
|
||||
{
|
||||
c->snext = stack;
|
||||
stack = c;
|
||||
}
|
||||
|
||||
/** Detach client from stack
|
||||
* \param c the client
|
||||
*/
|
||||
static inline void
|
||||
detachstack(Client * c)
|
||||
{
|
||||
Client **tc;
|
||||
|
||||
for(tc = &stack; *tc && *tc != c; tc = &(*tc)->snext);
|
||||
*tc = c->snext;
|
||||
}
|
||||
|
||||
/** Grab or ungrab buttons when a client is focused
|
||||
* \param c client
|
||||
* \param focused True if client is focused
|
||||
* \param modkey Mod key mask
|
||||
* \param numlockmask Numlock mask
|
||||
*/
|
||||
static void
|
||||
grabbuttons(Client * c, Bool focused, KeySym modkey, unsigned int numlockmask)
|
||||
{
|
||||
XUngrabButton(c->display, AnyButton, AnyModifier, c->win);
|
||||
|
||||
if(focused)
|
||||
{
|
||||
XGrabButton(c->display, Button1, modkey, c->win, False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button1, modkey | LockMask, c->win, False,
|
||||
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button1, modkey | numlockmask, c->win, False,
|
||||
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button1, modkey | numlockmask | LockMask,
|
||||
c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
||||
|
||||
XGrabButton(c->display, Button2, modkey, c->win, False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button2, modkey | LockMask, c->win, False,
|
||||
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button2, modkey | numlockmask, c->win, False,
|
||||
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button2, modkey | numlockmask | LockMask,
|
||||
c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
||||
|
||||
XGrabButton(c->display, Button3, modkey, c->win, False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button3, modkey | LockMask, c->win, False,
|
||||
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button3, modkey | numlockmask, c->win, False,
|
||||
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button3, modkey | numlockmask | LockMask,
|
||||
c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
||||
|
||||
XUngrabButton(c->display, AnyButton, AnyModifier, DefaultRootWindow(c->display));
|
||||
}
|
||||
else
|
||||
{
|
||||
XGrabButton(c->display, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button4, NoSymbol, DefaultRootWindow(c->display), False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button4, LockMask, DefaultRootWindow(c->display), False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button4, numlockmask, DefaultRootWindow(c->display), False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button4, numlockmask | LockMask, DefaultRootWindow(c->display), False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
|
||||
XGrabButton(c->display, Button5, NoSymbol, DefaultRootWindow(c->display), False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button5, LockMask, DefaultRootWindow(c->display), False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button5, numlockmask, DefaultRootWindow(c->display), False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
XGrabButton(c->display, Button5, numlockmask | LockMask, DefaultRootWindow(c->display), False, BUTTONMASK,
|
||||
GrabModeAsync, GrabModeSync, None, None);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** XXX: No idea
|
||||
* \param c the client
|
||||
* \return True if atom has WMDelete
|
||||
*/
|
||||
static Bool
|
||||
isprotodel(Client * c)
|
||||
{
|
||||
int i, n;
|
||||
Atom *protocols;
|
||||
Bool ret = False;
|
||||
|
||||
if(XGetWMProtocols(c->display, c->win, &protocols, &n))
|
||||
{
|
||||
for(i = 0; !ret && i < n; i++)
|
||||
if(protocols[i] == wmatom[WMDelete])
|
||||
ret = True;
|
||||
XFree(protocols);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** XXX: No idea
|
||||
* \param c the client
|
||||
* \param state no idea
|
||||
*/
|
||||
static void
|
||||
setclientstate(Client * c, long state)
|
||||
{
|
||||
long data[] = { state, None };
|
||||
|
||||
XChangeProperty(c->display, c->win, wmatom[WMState], wmatom[WMState], 32,
|
||||
PropModeReplace, (unsigned char *) data, 2);
|
||||
}
|
||||
|
||||
/* extern */
|
||||
|
||||
/** Attach client to the beginning of the clients stack
|
||||
* \param c the client
|
||||
*/
|
||||
inline void
|
||||
attach(Client * c)
|
||||
{
|
||||
if(clients)
|
||||
clients->prev = c;
|
||||
c->next = clients;
|
||||
clients = c;
|
||||
}
|
||||
|
||||
inline void
|
||||
updatetitle(Client * c)
|
||||
{
|
||||
if(!gettextprop(c->display, c->win, netatom[NetWMName], c->name, sizeof c->name))
|
||||
gettextprop(c->display, c->win, wmatom[WMName], c->name, sizeof c->name);
|
||||
}
|
||||
|
||||
/** Ban client
|
||||
* \param c the client
|
||||
*/
|
||||
void
|
||||
ban(Client * c)
|
||||
{
|
||||
if(c->isbanned)
|
||||
return;
|
||||
XUnmapWindow(c->display, c->win);
|
||||
setclientstate(c, IconicState);
|
||||
c->isbanned = True;
|
||||
c->unmapped++;
|
||||
}
|
||||
|
||||
|
||||
/** Configure client
|
||||
* \param c the client
|
||||
*/
|
||||
void
|
||||
configure(Client * c)
|
||||
{
|
||||
XConfigureEvent ce;
|
||||
|
||||
ce.type = ConfigureNotify;
|
||||
ce.display = c->display;
|
||||
ce.event = c->win;
|
||||
ce.window = c->win;
|
||||
ce.x = c->x;
|
||||
ce.y = c->y;
|
||||
ce.width = c->w;
|
||||
ce.height = c->h;
|
||||
ce.border_width = c->border;
|
||||
ce.above = None;
|
||||
ce.override_redirect = False;
|
||||
XSendEvent(c->display, c->win, False, StructureNotifyMask, (XEvent *) & ce);
|
||||
}
|
||||
|
||||
void
|
||||
detach(Client * c)
|
||||
{
|
||||
if(c->prev)
|
||||
c->prev->next = c->next;
|
||||
if(c->next)
|
||||
c->next->prev = c->prev;
|
||||
if(c == clients)
|
||||
clients = c->next;
|
||||
c->next = c->prev = NULL;
|
||||
}
|
||||
|
||||
/** Give focus to client, or to first client if c is NULL
|
||||
* \param disp Display ref
|
||||
* \param drawcontext drawcontext ref
|
||||
* \param c client
|
||||
* \param jdwmconf jdwm config
|
||||
*/
|
||||
void
|
||||
focus(Display *disp, DC *drawcontext, Client * c, jdwm_config *jdwmconf)
|
||||
{
|
||||
/* if c is NULL or invisible, take next client in the stack */
|
||||
if((!c && selscreen) || (c && !isvisible(c, jdwmconf->ntags)))
|
||||
for(c = stack; c && !isvisible(c, jdwmconf->ntags); c = c->snext);
|
||||
|
||||
/* if a client was selected but it's not the current client, unfocus it */
|
||||
if(sel && sel != c)
|
||||
{
|
||||
grabbuttons(sel, False, jdwmconf->modkey, jdwmconf->numlockmask);
|
||||
XSetWindowBorder(sel->display, sel->win, drawcontext->norm[ColBorder]);
|
||||
setclienttrans(sel, jdwmconf->opacity_unfocused, 0);
|
||||
}
|
||||
if(c)
|
||||
{
|
||||
detachstack(c);
|
||||
attachstack(c);
|
||||
grabbuttons(c, True, jdwmconf->modkey, jdwmconf->numlockmask);
|
||||
}
|
||||
if(!selscreen)
|
||||
return;
|
||||
sel = c;
|
||||
drawstatus(disp, jdwmconf);
|
||||
if(sel)
|
||||
{
|
||||
XSetWindowBorder(sel->display, sel->win, drawcontext->sel[ColBorder]);
|
||||
XSetInputFocus(sel->display, sel->win, RevertToPointerRoot, CurrentTime);
|
||||
for(c = stack; c; c = c->snext)
|
||||
if(c != sel)
|
||||
setclienttrans(c, jdwmconf->opacity_unfocused, 0);
|
||||
setclienttrans(sel, -1, 0);
|
||||
}
|
||||
else
|
||||
XSetInputFocus(disp, DefaultRootWindow(disp), RevertToPointerRoot, CurrentTime);
|
||||
}
|
||||
|
||||
/** Kill selected client
|
||||
* \param disp Display ref
|
||||
* \param jdwmconf jdwm config
|
||||
* \param arg unused
|
||||
* \ingroup ui_callback
|
||||
*/
|
||||
void
|
||||
uicb_killclient(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config *jdwmconf __attribute__ ((unused)),
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
XEvent ev;
|
||||
|
||||
if(!sel)
|
||||
return;
|
||||
if(isprotodel(sel))
|
||||
{
|
||||
ev.type = ClientMessage;
|
||||
ev.xclient.window = sel->win;
|
||||
ev.xclient.message_type = wmatom[WMProtocols];
|
||||
ev.xclient.format = 32;
|
||||
ev.xclient.data.l[0] = wmatom[WMDelete];
|
||||
ev.xclient.data.l[1] = CurrentTime;
|
||||
XSendEvent(sel->display, sel->win, False, NoEventMask, &ev);
|
||||
}
|
||||
else
|
||||
XKillClient(sel->display, sel->win);
|
||||
}
|
||||
|
||||
static Bool
|
||||
loadprops(Client * c, int ntags)
|
||||
{
|
||||
int i;
|
||||
Bool result = False;
|
||||
|
||||
if(gettextprop(c->display, c->win, jdwmprops, prop, sizeof(prop)))
|
||||
{
|
||||
for(i = 0; i < ntags && i < ssizeof(prop) - 1 && prop[i] != '\0'; i++)
|
||||
if((c->tags[i] = prop[i] == '1'))
|
||||
result = True;
|
||||
if(i < ssizeof(prop) - 1 && prop[i] != '\0')
|
||||
c->isfloating = prop[i] == '1';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
manage(Display * disp, DC *drawcontext, Window w, XWindowAttributes * wa, jdwm_config *jdwmconf)
|
||||
{
|
||||
int i;
|
||||
Client *c, *t = NULL;
|
||||
Window trans;
|
||||
Status rettrans;
|
||||
XWindowChanges wc;
|
||||
|
||||
c = p_new(Client, 1);
|
||||
c->tags = p_new(Bool, jdwmconf->ntags);
|
||||
c->win = w;
|
||||
c->ftview = True;
|
||||
c->x = c->rw = wa->x;
|
||||
c->y = c->ry = wa->y;
|
||||
c->w = c->rw = wa->width;
|
||||
c->h = c->rh = wa->height;
|
||||
c->oldborder = wa->border_width;
|
||||
c->display = disp;
|
||||
if(c->w == sw && c->h == sh)
|
||||
{
|
||||
c->x = sx;
|
||||
c->y = sy;
|
||||
c->border = wa->border_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(c->x + c->w + 2 * c->border > wax + waw)
|
||||
c->x = c->rx = wax + waw - c->w - 2 * c->border;
|
||||
if(c->y + c->h + 2 * c->border > way + wah)
|
||||
c->y = c->ry = way + wah - c->h - 2 * c->border;
|
||||
if(c->x < wax)
|
||||
c->x = c->rx = wax;
|
||||
if(c->y < way)
|
||||
c->y = c->ry = way;
|
||||
c->border = jdwmconf->borderpx;
|
||||
}
|
||||
wc.border_width = c->border;
|
||||
XConfigureWindow(disp, w, CWBorderWidth, &wc);
|
||||
XSetWindowBorder(disp, w, drawcontext->norm[ColBorder]);
|
||||
configure(c); /* propagates border_width, if size doesn't change */
|
||||
updatesizehints(c);
|
||||
XSelectInput(disp, w, StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
|
||||
grabbuttons(c, False, jdwmconf->modkey, jdwmconf->numlockmask);
|
||||
updatetitle(c);
|
||||
if((rettrans = XGetTransientForHint(disp, w, &trans) == Success))
|
||||
for(t = clients; t && t->win != trans; t = t->next);
|
||||
if(t)
|
||||
for(i = 0; i < jdwmconf->ntags; i++)
|
||||
c->tags[i] = t->tags[i];
|
||||
if(!loadprops(c, jdwmconf->ntags))
|
||||
applyrules(c, jdwmconf);
|
||||
if(!c->isfloating)
|
||||
c->isfloating = (rettrans == Success) || c->isfixed;
|
||||
saveprops(c, jdwmconf->ntags);
|
||||
attach(c);
|
||||
attachstack(c);
|
||||
XMoveResizeWindow(disp, c->win, c->x, c->y, c->w, c->h); /* some windows require this */
|
||||
ban(c);
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
void
|
||||
resize(Client * c, int x, int y, int w, int h, Bool sizehints)
|
||||
{
|
||||
double dx, dy, max, min, ratio;
|
||||
XWindowChanges wc;
|
||||
|
||||
if(sizehints)
|
||||
{
|
||||
if(c->minay > 0 && c->maxay > 0 && (h - c->baseh) > 0 && (w - c->basew) > 0)
|
||||
{
|
||||
dx = (double) (w - c->basew);
|
||||
dy = (double) (h - c->baseh);
|
||||
min = (double) (c->minax) / (double) (c->minay);
|
||||
max = (double) (c->maxax) / (double) (c->maxay);
|
||||
ratio = dx / dy;
|
||||
if(max > 0 && min > 0 && ratio > 0)
|
||||
{
|
||||
if(ratio < min)
|
||||
{
|
||||
dy = (dx * min + dy) / (min * min + 1);
|
||||
dx = dy * min;
|
||||
w = (int) dx + c->basew;
|
||||
h = (int) dy + c->baseh;
|
||||
}
|
||||
else if(ratio > max)
|
||||
{
|
||||
dy = (dx * min + dy) / (max * max + 1);
|
||||
dx = dy * min;
|
||||
w = (int) dx + c->basew;
|
||||
h = (int) dy + c->baseh;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(c->minw && w < c->minw)
|
||||
w = c->minw;
|
||||
if(c->minh && h < c->minh)
|
||||
h = c->minh;
|
||||
if(c->maxw && w > c->maxw)
|
||||
w = c->maxw;
|
||||
if(c->maxh && h > c->maxh)
|
||||
h = c->maxh;
|
||||
if(c->incw)
|
||||
w -= (w - c->basew) % c->incw;
|
||||
if(c->inch)
|
||||
h -= (h - c->baseh) % c->inch;
|
||||
}
|
||||
if(w <= 0 || h <= 0)
|
||||
return;
|
||||
/* offscreen appearance fixes */
|
||||
if(x > sw)
|
||||
x = sw - w - 2 * c->border;
|
||||
if(y > sh)
|
||||
y = sh - h - 2 * c->border;
|
||||
if(x + w + 2 * c->border < sx)
|
||||
x = sx;
|
||||
if(y + h + 2 * c->border < sy)
|
||||
y = sy;
|
||||
if(c->x != x || c->y != y || c->w != w || c->h != h)
|
||||
{
|
||||
c->x = wc.x = x;
|
||||
c->y = wc.y = y;
|
||||
c->w = wc.width = w;
|
||||
c->h = wc.height = h;
|
||||
wc.border_width = c->border;
|
||||
XConfigureWindow(c->display, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
|
||||
configure(c);
|
||||
XSync(c->display, False);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uicb_moveresize(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg)
|
||||
{
|
||||
int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh;
|
||||
char xabs, yabs, wabs, habs;
|
||||
int mx, my, dx, dy, nmx, nmy;
|
||||
unsigned int dui;
|
||||
Window dummy;
|
||||
|
||||
if(!IS_ARRANGE(floating))
|
||||
if(!sel || !sel->isfloating || sel->isfixed || !arg)
|
||||
return;
|
||||
if(sscanf(arg, "%d%c %d%c %d%c %d%c", &x, &xabs, &y, &yabs, &w, &wabs, &h, &habs) != 8)
|
||||
return;
|
||||
nx = xabs == 'x' ? sel->x + x : x;
|
||||
ny = yabs == 'y' ? sel->y + y : y;
|
||||
nw = wabs == 'w' ? sel->w + w : w;
|
||||
nh = habs == 'h' ? sel->h + h : h;
|
||||
|
||||
ox = sel->x;
|
||||
oy = sel->y;
|
||||
ow = sel->w;
|
||||
oh = sel->h;
|
||||
|
||||
Bool xqp = XQueryPointer(sel->display, DefaultRootWindow(sel->display), &dummy, &dummy, &mx, &my, &dx, &dy, &dui);
|
||||
resize(sel, nx, ny, nw, nh, True);
|
||||
if (xqp && ox <= mx && (ox + ow) >= mx && oy <= my && (oy + oh) >= my)
|
||||
{
|
||||
nmx = mx-ox+sel->w-ow-1 < 0 ? 0 : mx-ox+sel->w-ow-1;
|
||||
nmy = my-oy+sel->h-oh-1 < 0 ? 0 : my-oy+sel->h-oh-1;
|
||||
XWarpPointer(sel->display, None, sel->win, 0, 0, 0, 0, nmx, nmy);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
saveprops(Client * c, int ntags)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < ntags && i < ssizeof(prop) - 1; i++)
|
||||
prop[i] = c->tags[i] ? '1' : '0';
|
||||
if(i < ssizeof(prop) - 1)
|
||||
prop[i++] = c->isfloating ? '1' : '0';
|
||||
|
||||
prop[i] = '\0';
|
||||
XChangeProperty(c->display, c->win, jdwmprops, XA_STRING, 8,
|
||||
PropModeReplace, (unsigned char *) prop, i);
|
||||
}
|
||||
|
||||
void
|
||||
unban(Client * c)
|
||||
{
|
||||
if(!c->isbanned)
|
||||
return;
|
||||
XMapWindow(c->display, c->win);
|
||||
setclientstate(c, NormalState);
|
||||
c->isbanned = False;
|
||||
}
|
||||
|
||||
void
|
||||
unmanage(Client * c, DC *drawcontext, long state, jdwm_config *jdwmconf)
|
||||
{
|
||||
XWindowChanges wc;
|
||||
|
||||
wc.border_width = c->oldborder;
|
||||
/* The server grab construct avoids race conditions. */
|
||||
XGrabServer(c->display);
|
||||
XConfigureWindow(c->display, c->win, CWBorderWidth, &wc); /* restore border */
|
||||
detach(c);
|
||||
detachstack(c);
|
||||
if(sel == c)
|
||||
focus(c->display, drawcontext, NULL, jdwmconf);
|
||||
XUngrabButton(c->display, AnyButton, AnyModifier, c->win);
|
||||
setclientstate(c, state);
|
||||
XSync(c->display, False);
|
||||
XSetErrorHandler(xerror);
|
||||
XUngrabServer(c->display);
|
||||
if(state != NormalState)
|
||||
arrange(c->display, jdwmconf);
|
||||
p_delete(&c->tags);
|
||||
p_delete(&c);
|
||||
}
|
||||
|
||||
void
|
||||
updatesizehints(Client * c)
|
||||
{
|
||||
long msize;
|
||||
XSizeHints size;
|
||||
|
||||
if(!XGetWMNormalHints(c->display, c->win, &size, &msize) || !size.flags)
|
||||
size.flags = PSize;
|
||||
c->flags = size.flags;
|
||||
if(c->flags & PBaseSize)
|
||||
{
|
||||
c->basew = size.base_width;
|
||||
c->baseh = size.base_height;
|
||||
}
|
||||
else if(c->flags & PMinSize)
|
||||
{
|
||||
c->basew = size.min_width;
|
||||
c->baseh = size.min_height;
|
||||
}
|
||||
else
|
||||
c->basew = c->baseh = 0;
|
||||
if(c->flags & PResizeInc)
|
||||
{
|
||||
c->incw = size.width_inc;
|
||||
c->inch = size.height_inc;
|
||||
}
|
||||
else
|
||||
c->incw = c->inch = 0;
|
||||
|
||||
if(c->flags & PMaxSize)
|
||||
{
|
||||
c->maxw = size.max_width;
|
||||
c->maxh = size.max_height;
|
||||
}
|
||||
else
|
||||
c->maxw = c->maxh = 0;
|
||||
|
||||
if(c->flags & PMinSize)
|
||||
{
|
||||
c->minw = size.min_width;
|
||||
c->minh = size.min_height;
|
||||
}
|
||||
else if(c->flags & PBaseSize)
|
||||
{
|
||||
c->minw = size.base_width;
|
||||
c->minh = size.base_height;
|
||||
}
|
||||
else
|
||||
c->minw = c->minh = 0;
|
||||
|
||||
if(c->flags & PAspect)
|
||||
{
|
||||
c->minax = size.min_aspect.x;
|
||||
c->maxax = size.max_aspect.x;
|
||||
c->minay = size.min_aspect.y;
|
||||
c->maxay = size.max_aspect.y;
|
||||
}
|
||||
else
|
||||
c->minax = c->maxax = c->minay = c->maxay = 0;
|
||||
|
||||
c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
|
||||
&& c->maxw == c->minw && c->maxh == c->minh);
|
||||
}
|
||||
|
||||
void
|
||||
setclienttrans(Client *c, double opacity, unsigned int current_opacity)
|
||||
{
|
||||
unsigned int real_opacity = 0xffffffff;
|
||||
|
||||
if(opacity >= 0 && opacity <= 100)
|
||||
{
|
||||
real_opacity = ((opacity / 100.0) * 0xffffffff) + current_opacity;
|
||||
XChangeProperty(c->display, c->win,
|
||||
XInternAtom(c->display, "_NET_WM_WINDOW_OPACITY", False),
|
||||
XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &real_opacity, 1L);
|
||||
}
|
||||
else
|
||||
XDeleteProperty(c->display, c->win, XInternAtom(c->display, "_NET_WM_WINDOW_OPACITY", False));
|
||||
|
||||
XSync(c->display, False);
|
||||
}
|
||||
|
||||
void
|
||||
uicb_settrans(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config *jdwmconf __attribute__ ((unused)),
|
||||
const char *arg)
|
||||
{
|
||||
unsigned int current_opacity = 0;
|
||||
double delta = 100.0;
|
||||
unsigned char *data;
|
||||
Atom actual;
|
||||
int format;
|
||||
unsigned long n, left;
|
||||
int set_prop = 0;
|
||||
|
||||
if(!sel)
|
||||
return;
|
||||
|
||||
if(arg && sscanf(arg, "%lf", &delta))
|
||||
{
|
||||
if(arg[0] == '+' || arg[0] == '-')
|
||||
{
|
||||
XGetWindowProperty(sel->display, sel->win, XInternAtom(sel->display, "_NET_WM_WINDOW_OPACITY", False),
|
||||
0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left,
|
||||
(unsigned char **) &data);
|
||||
if(data)
|
||||
{
|
||||
memcpy(¤t_opacity, data, sizeof(double));
|
||||
XFree((void *) data);
|
||||
delta += ((current_opacity * 100.0) / 0xffffffff);
|
||||
}
|
||||
else
|
||||
{
|
||||
delta += 100.0;
|
||||
set_prop = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(delta <= 0.0)
|
||||
delta = 0.0;
|
||||
else if(delta > 100.0)
|
||||
{
|
||||
delta = 100.0;
|
||||
set_prop = 1;
|
||||
}
|
||||
|
||||
if(delta == 100.0 && !set_prop)
|
||||
setclienttrans(sel, -1, 0);
|
||||
else
|
||||
setclienttrans(sel, delta, current_opacity);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_CLIENT_H
|
||||
#define JDWM_CLIENT_H
|
||||
|
||||
/* mask shorthands, used in event.c and client.c */
|
||||
#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
|
||||
|
||||
#include "draw.h"
|
||||
|
||||
typedef struct Client Client;
|
||||
struct Client
|
||||
{
|
||||
char name[256];
|
||||
int x, y, w, h;
|
||||
int rx, ry, rw, rh; /* revert geometry */
|
||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
||||
int minax, maxax, minay, maxay;
|
||||
int unmapped;
|
||||
long flags;
|
||||
int border, oldborder;
|
||||
Bool isbanned, isfixed, ismax, isfloating, wasfloating;
|
||||
Bool *tags;
|
||||
Client *next;
|
||||
Client *prev;
|
||||
Client *snext;
|
||||
Window win;
|
||||
Display * display;
|
||||
Bool ftview; /* first time viewed on new layout */
|
||||
};
|
||||
|
||||
void attach(Client *); /* attaches c to global client list */
|
||||
void ban(Client *); /* bans c */
|
||||
void configure(Client *); /* send synthetic configure event */
|
||||
void detach(Client *); /* detaches c from global client list */
|
||||
void focus(Display *, DC *, Client *, jdwm_config *); /* focus c if visible && !NULL, or focus top visible */
|
||||
void manage(Display *, DC *, Window, XWindowAttributes *, jdwm_config *); /* manage new client */
|
||||
void resize(Client *, int, int, int, int, Bool); /* resize with given coordinates c */
|
||||
void unban(Client *); /* unbans c */
|
||||
void unmanage(Client *, DC *, long, jdwm_config *); /* unmanage c */
|
||||
void updatesizehints(Client *); /* update the size hint variables of c */
|
||||
void updatetitle(Client *); /* update the name of c */
|
||||
void saveprops(Client * c, int); /* saves client properties */
|
||||
void uicb_killclient(Display *, jdwm_config *, const char *); /* kill client */
|
||||
void uicb_moveresize(Display *, jdwm_config *, const char *); /* move and resize window */
|
||||
void uicb_settrans(Display *, jdwm_config *, const char *);
|
||||
void setclienttrans(Client *c, double, unsigned int);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,405 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
/**
|
||||
* \defgroup ui_callback
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libconfig.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#include "jdwm.h"
|
||||
#include "util.h"
|
||||
#include "layout.h"
|
||||
#include "tag.h"
|
||||
#include "layouts/tile.h"
|
||||
#include "layouts/grid.h"
|
||||
#include "layouts/spiral.h"
|
||||
#include "layouts/floating.h"
|
||||
|
||||
/* static */
|
||||
static void initfont(const char *, Display *, DC *);
|
||||
static unsigned long initcolor(const char *colstr, Display *, int);
|
||||
static unsigned int get_numlockmask(Display *);
|
||||
|
||||
/** Main configuration object for parsing*/
|
||||
config_t jdwmlibconf;
|
||||
|
||||
/** Current bar position */
|
||||
int bpos;
|
||||
|
||||
/** Link a name to a function */
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
void *func;
|
||||
} NameFuncLink;
|
||||
|
||||
/** Link a name to a key symbol */
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
KeySym keysym;
|
||||
} KeyMod;
|
||||
|
||||
/** List of keyname and corresponding X11 mask codes */
|
||||
static const KeyMod KeyModList[] = { {"Shift", ShiftMask},
|
||||
{"Lock", LockMask},
|
||||
{"Control", ControlMask},
|
||||
{"Mod1", Mod1Mask},
|
||||
{"Mod2", Mod2Mask},
|
||||
{"Mod3", Mod3Mask},
|
||||
{"Mod4", Mod4Mask},
|
||||
{"Mod5", Mod5Mask},
|
||||
{"None", 0}
|
||||
};
|
||||
|
||||
/** List of available layouts and link between name and functions */
|
||||
static const NameFuncLink LayoutsList[] = { {"tile", tile},
|
||||
{"tileleft", tileleft},
|
||||
{"floating", floating},
|
||||
{"grid", grid},
|
||||
{"spiral", spiral},
|
||||
{"dwindle", dwindle},
|
||||
{"bstack", bstack},
|
||||
{"bstackportrait", bstackportrait},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/** List of available UI bindable callbacks and functions */
|
||||
static const NameFuncLink KeyfuncList[] = {
|
||||
/* util.c */
|
||||
{"spawn", spawn},
|
||||
/* client.c */
|
||||
{"killclient", uicb_killclient},
|
||||
{"moveresize", uicb_moveresize},
|
||||
{"settrans", uicb_settrans},
|
||||
/* config.c */
|
||||
{"reload", uicb_reload},
|
||||
/* tag.c */
|
||||
{"tag", uicb_tag},
|
||||
{"togglefloating", uicb_togglefloating},
|
||||
{"toggleview", uicb_toggleview},
|
||||
{"toggletag", uicb_toggletag},
|
||||
{"view", uicb_view},
|
||||
{"viewprevtags", uicb_viewprevtags},
|
||||
/* layout.c */
|
||||
{"setlayout", uicb_setlayout},
|
||||
{"togglebar", uicb_togglebar},
|
||||
{"focusnext", uicb_focusnext},
|
||||
{"focusprev", uicb_focusprev},
|
||||
{"togglemax", uicb_togglemax},
|
||||
{"toggleverticalmax", uicb_toggleverticalmax},
|
||||
{"togglehorizontalmax", uicb_togglehorizontalmax},
|
||||
{"zoom", uicb_zoom},
|
||||
/* layouts/tile.c */
|
||||
{"setmwfact", uicb_setmwfact},
|
||||
{"incnmaster", uicb_incnmaster},
|
||||
/* jdwm.c */
|
||||
{"quit", uicb_quit},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/** Lookup for a key mask from its name
|
||||
* \param keyname Key name
|
||||
* \return Key mask or 0 if not found
|
||||
*/
|
||||
static KeySym
|
||||
key_mask_lookup(const char *keyname)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(keyname)
|
||||
for(i = 0; KeyModList[i].name; i++)
|
||||
if(!strcmp(keyname, KeyModList[i].name))
|
||||
return KeyModList[i].keysym;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/** Lookup for a function pointer from its name
|
||||
* in the given NameFuncLink list
|
||||
* \param funcname Function name
|
||||
* \param list Function and name link list
|
||||
* \return function pointer
|
||||
*/
|
||||
static void *
|
||||
name_func_lookup(const char *funcname, const NameFuncLink * list)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(funcname && list)
|
||||
for(i = 0; list[i].name; i++)
|
||||
if(!strcmp(funcname, list[i].name))
|
||||
return list[i].func;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \todo remove screen */
|
||||
extern int screen;
|
||||
/** \todo remove dc */
|
||||
extern DC dc;
|
||||
|
||||
/** Reload configuration file
|
||||
* \param disp Display ref
|
||||
* \param arg unused
|
||||
* \ingroup ui_callback
|
||||
* \todo not really working nor safe I guess
|
||||
*/
|
||||
void
|
||||
uicb_reload(Display *disp, jdwm_config *jdwmconf, const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
config_destroy(&jdwmlibconf);
|
||||
p_delete(&jdwmconf->rules);
|
||||
p_delete(&jdwmconf->tags);
|
||||
p_delete(&jdwmconf->layouts);
|
||||
parse_config(disp, screen, &dc, jdwmconf);
|
||||
}
|
||||
|
||||
static void
|
||||
set_default_config(jdwm_config *jdwmconf)
|
||||
{
|
||||
strcpy(jdwmconf->statustext, "jdwm-" VERSION);
|
||||
}
|
||||
|
||||
/** Parse configuration file and initialize some stuff
|
||||
* \param disp Display ref
|
||||
* \param scr Screen number
|
||||
* \param drawcontext Draw context
|
||||
*/
|
||||
void
|
||||
parse_config(Display * disp, int scr, DC * drawcontext, jdwm_config *jdwmconf)
|
||||
{
|
||||
config_setting_t *conftags;
|
||||
config_setting_t *conflayouts, *confsublayouts;
|
||||
config_setting_t *confrules, *confsubrules;
|
||||
config_setting_t *confkeys, *confsubkeys, *confkeysmasks, *confkeymaskelem;
|
||||
int i, j;
|
||||
const char *tmp, *homedir;
|
||||
char *confpath;
|
||||
|
||||
set_default_config(jdwmconf);
|
||||
|
||||
homedir = getenv("HOME");
|
||||
confpath = p_new(char, strlen(homedir) + strlen(JDWM_CONFIG_FILE) + 2);
|
||||
strcpy(confpath, homedir);
|
||||
strcat(confpath, "/");
|
||||
strcat(confpath, JDWM_CONFIG_FILE);
|
||||
|
||||
config_init(&jdwmlibconf);
|
||||
|
||||
if(config_read_file(&jdwmlibconf, confpath) == CONFIG_FALSE)
|
||||
eprint("error parsing configuration file at line %d: %s\n",
|
||||
config_error_line(&jdwmlibconf), config_error_text(&jdwmlibconf));
|
||||
|
||||
/* tags */
|
||||
conftags = config_lookup(&jdwmlibconf, "jdwm.tags");
|
||||
|
||||
if(!conftags)
|
||||
eprint("tags not found in configuration file\n");
|
||||
|
||||
jdwmconf->ntags = config_setting_length(conftags);
|
||||
jdwmconf->tags = p_new(const char *, jdwmconf->ntags);
|
||||
for(i = 0; (tmp = config_setting_get_string_elem(conftags, i)); i++)
|
||||
jdwmconf->tags[i] = tmp;
|
||||
|
||||
/* layouts */
|
||||
conflayouts = config_lookup(&jdwmlibconf, "jdwm.layouts");
|
||||
|
||||
if(!conflayouts)
|
||||
eprint("layouts not found in configuration file\n");
|
||||
|
||||
jdwmconf->nlayouts = config_setting_length(conflayouts);
|
||||
jdwmconf->layouts = p_new(Layout, jdwmconf->nlayouts + 1);
|
||||
for(i = 0; (confsublayouts = config_setting_get_elem(conflayouts, i)); i++)
|
||||
{
|
||||
jdwmconf->layouts[i].symbol = config_setting_get_string_elem(confsublayouts, 0);
|
||||
jdwmconf->layouts[i].arrange =
|
||||
name_func_lookup(config_setting_get_string_elem(confsublayouts, 1), LayoutsList);
|
||||
if(!jdwmconf->layouts[i].arrange)
|
||||
eprint("unknown layout in configuration file: %s", tmp);
|
||||
}
|
||||
jdwmconf->layouts[i].symbol = NULL;
|
||||
jdwmconf->layouts[i].arrange = NULL;
|
||||
|
||||
/** \todo put this in set_default_layout */
|
||||
jdwmconf->current_layout = jdwmconf->layouts;
|
||||
|
||||
/* rules */
|
||||
confrules = config_lookup(&jdwmlibconf, "jdwm.rules");
|
||||
|
||||
if(!confrules)
|
||||
eprint("rules not found in configuration file\n");
|
||||
|
||||
jdwmconf->nrules = config_setting_length(confrules);
|
||||
jdwmconf->rules = p_new(Rule, jdwmconf->nrules);
|
||||
for(i = 0; (confsubrules = config_setting_get_elem(confrules, i)); i++)
|
||||
{
|
||||
jdwmconf->rules[i].prop = config_setting_get_string(config_setting_get_member(confsubrules, "name"));
|
||||
jdwmconf->rules[i].tags = config_setting_get_string(config_setting_get_member(confsubrules, "tags"));
|
||||
if(jdwmconf->rules[i].tags && !strlen(jdwmconf->rules[i].tags))
|
||||
jdwmconf->rules[i].tags = NULL;
|
||||
jdwmconf->rules[i].isfloating =
|
||||
config_setting_get_bool(config_setting_get_member(confsubrules, "float"));
|
||||
}
|
||||
|
||||
/* modkey */
|
||||
jdwmconf->modkey = key_mask_lookup(config_lookup_string(&jdwmlibconf, "jdwm.modkey"));
|
||||
|
||||
/* find numlock mask */
|
||||
jdwmconf->numlockmask = get_numlockmask(disp);
|
||||
|
||||
/* keys */
|
||||
confkeys = config_lookup(&jdwmlibconf, "jdwm.keys");
|
||||
|
||||
if(!confkeys)
|
||||
eprint("keys not found in configuration file\n");
|
||||
|
||||
jdwmconf->nkeys = config_setting_length(confkeys);
|
||||
jdwmconf->keys = p_new(Key, jdwmconf->nkeys);
|
||||
|
||||
for(i = 0; (confsubkeys = config_setting_get_elem(confkeys, i)); i++)
|
||||
{
|
||||
confkeysmasks = config_setting_get_elem(confsubkeys, 0);
|
||||
for(j = 0; (confkeymaskelem = config_setting_get_elem(confkeysmasks, j)); j++)
|
||||
jdwmconf->keys[i].mod |= key_mask_lookup(config_setting_get_string(confkeymaskelem));
|
||||
jdwmconf->keys[i].keysym = XStringToKeysym(config_setting_get_string_elem(confsubkeys, 1));
|
||||
jdwmconf->keys[i].func =
|
||||
name_func_lookup(config_setting_get_string_elem(confsubkeys, 2), KeyfuncList);
|
||||
jdwmconf->keys[i].arg = config_setting_get_string_elem(confsubkeys, 3);
|
||||
}
|
||||
|
||||
/* barpos */
|
||||
tmp = config_lookup_string(&jdwmlibconf, "jdwm.barpos");
|
||||
|
||||
if(!strncmp(tmp, "BarTop", 6))
|
||||
jdwmconf->bpos = BarTop;
|
||||
else if(!strncmp(tmp, "BarBot", 6))
|
||||
jdwmconf->bpos = BarBot;
|
||||
else if(!strncmp(tmp, "BarOff", 6))
|
||||
jdwmconf->bpos = BarOff;
|
||||
|
||||
bpos = jdwmconf->bpos;
|
||||
|
||||
/* borderpx */
|
||||
jdwmconf->borderpx = config_lookup_int(&jdwmlibconf, "jdwm.borderpx");
|
||||
|
||||
/* opacity */
|
||||
jdwmconf->opacity_unfocused = config_lookup_int(&jdwmlibconf, "jdwm.opacity_unfocused");
|
||||
if(jdwmconf->opacity_unfocused >= 100)
|
||||
jdwmconf->opacity_unfocused = -1;
|
||||
|
||||
/* snap */
|
||||
jdwmconf->snap = config_lookup_int(&jdwmlibconf, "jdwm.snap");
|
||||
|
||||
/* nmaster */
|
||||
jdwmconf->nmaster = config_lookup_int(&jdwmlibconf, "jdwm.nmaster");
|
||||
|
||||
/* mwfact */
|
||||
jdwmconf->mwfact = config_lookup_float(&jdwmlibconf, "jdwm.mwfact");
|
||||
|
||||
/* font */
|
||||
initfont(config_lookup_string(&jdwmlibconf, "jdwm.font"), disp, drawcontext);
|
||||
|
||||
/* colors */
|
||||
dc.norm[ColBorder] = initcolor(config_lookup_string(&jdwmlibconf, "jdwm.normal_border_color"),
|
||||
disp, scr);
|
||||
dc.norm[ColBG] = initcolor(config_lookup_string(&jdwmlibconf, "jdwm.normal_bg_color"), disp, scr);
|
||||
dc.norm[ColFG] = initcolor(config_lookup_string(&jdwmlibconf, "jdwm.normal_fg_color"), disp, scr);
|
||||
dc.sel[ColBorder] = initcolor(config_lookup_string(&jdwmlibconf, "jdwm.focus_border_color"),
|
||||
disp, scr);
|
||||
dc.sel[ColBG] = initcolor(config_lookup_string(&jdwmlibconf, "jdwm.focus_bg_color"), disp, scr);
|
||||
dc.sel[ColFG] = initcolor(config_lookup_string(&jdwmlibconf, "jdwm.focus_fg_color"), disp, scr);
|
||||
|
||||
p_delete(&confpath);
|
||||
}
|
||||
|
||||
/** Initialize font from X side and store in draw context
|
||||
* \param fontstr Font name
|
||||
* \param disp Display ref
|
||||
* \param drawcontext Draw context
|
||||
*/
|
||||
static void
|
||||
initfont(const char *fontstr, Display * disp, DC * drawcontext)
|
||||
{
|
||||
char *def, **missing;
|
||||
int i, n;
|
||||
|
||||
missing = NULL;
|
||||
if(drawcontext->font.set)
|
||||
XFreeFontSet(disp, drawcontext->font.set);
|
||||
drawcontext->font.set = XCreateFontSet(disp, fontstr, &missing, &n, &def);
|
||||
if(missing)
|
||||
{
|
||||
while(n--)
|
||||
fprintf(stderr, "jdwm: missing fontset: %s\n", missing[n]);
|
||||
XFreeStringList(missing);
|
||||
}
|
||||
if(drawcontext->font.set)
|
||||
{
|
||||
XFontSetExtents *font_extents;
|
||||
XFontStruct **xfonts;
|
||||
char **font_names;
|
||||
drawcontext->font.ascent = drawcontext->font.descent = 0;
|
||||
font_extents = XExtentsOfFontSet(drawcontext->font.set);
|
||||
n = XFontsOfFontSet(drawcontext->font.set, &xfonts, &font_names);
|
||||
for(i = 0, drawcontext->font.ascent = 0, drawcontext->font.descent = 0; i < n; i++)
|
||||
{
|
||||
if(drawcontext->font.ascent < (*xfonts)->ascent)
|
||||
drawcontext->font.ascent = (*xfonts)->ascent;
|
||||
if(drawcontext->font.descent < (*xfonts)->descent)
|
||||
drawcontext->font.descent = (*xfonts)->descent;
|
||||
xfonts++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(drawcontext->font.xfont)
|
||||
XFreeFont(disp, drawcontext->font.xfont);
|
||||
drawcontext->font.xfont = NULL;
|
||||
if(!(drawcontext->font.xfont = XLoadQueryFont(disp, fontstr)))
|
||||
eprint("error, cannot load font: '%s'\n", fontstr);
|
||||
drawcontext->font.ascent = drawcontext->font.xfont->ascent;
|
||||
drawcontext->font.descent = drawcontext->font.xfont->descent;
|
||||
}
|
||||
drawcontext->font.height = drawcontext->font.ascent + drawcontext->font.descent;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_numlockmask(Display *disp)
|
||||
{
|
||||
XModifierKeymap *modmap;
|
||||
unsigned int mask = 0;
|
||||
int i, j;
|
||||
|
||||
modmap = XGetModifierMapping(disp);
|
||||
for(i = 0; i < 8; i++)
|
||||
for(j = 0; j < modmap->max_keypermod; j++)
|
||||
{
|
||||
if(modmap->modifiermap[i * modmap->max_keypermod + j]
|
||||
== XKeysymToKeycode(disp, XK_Num_Lock))
|
||||
mask = (1 << i);
|
||||
}
|
||||
|
||||
XFreeModifiermap(modmap);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/** Initialize color from X side
|
||||
* \param colorstr Color code
|
||||
* \param disp Display ref
|
||||
* \param scr Screen number
|
||||
* \return XColor pixel
|
||||
*/
|
||||
static unsigned long
|
||||
initcolor(const char *colstr, Display * disp, int scr)
|
||||
{
|
||||
Colormap cmap = DefaultColormap(disp, scr);
|
||||
XColor color;
|
||||
if(!XAllocNamedColor(disp, cmap, colstr, &color, &color))
|
||||
eprint("error, cannot allocate color '%s'\n", colstr);
|
||||
return color.pixel;
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_CONFIG_H
|
||||
#define JDWM_CONFIG_H
|
||||
|
||||
#define JDWM_CONFIG_FILE ".jdwmrc"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
/** Bar possible position */
|
||||
enum
|
||||
{ BarTop, BarBot, BarOff };
|
||||
|
||||
enum
|
||||
{ ColBorder, ColFG, ColBG, ColLast }; /* color */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x, y, w, h;
|
||||
unsigned long norm[ColLast];
|
||||
unsigned long sel[ColLast];
|
||||
Drawable drawable;
|
||||
GC gc;
|
||||
struct
|
||||
{
|
||||
int ascent;
|
||||
int descent;
|
||||
int height;
|
||||
XFontSet set;
|
||||
XFontStruct *xfont;
|
||||
} font;
|
||||
} DC;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *prop;
|
||||
const char *tags;
|
||||
Bool isfloating;
|
||||
} Rule;
|
||||
|
||||
typedef struct jdwm_config jdwm_config;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *symbol;
|
||||
void (*arrange) (Display *, jdwm_config *);
|
||||
} Layout;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long mod;
|
||||
KeySym keysym;
|
||||
void (*func) (Display *, jdwm_config *, const char *);
|
||||
const char *arg;
|
||||
} Key;
|
||||
|
||||
/** Main configuration structure */
|
||||
struct jdwm_config
|
||||
{
|
||||
/** Tag list */
|
||||
const char **tags;
|
||||
/** Number of tags in **tags */
|
||||
int ntags;
|
||||
/** Layout list */
|
||||
Layout *layouts;
|
||||
/** Number of layouts in *layouts */
|
||||
int nlayouts;
|
||||
/** Rules list */
|
||||
Rule *rules;
|
||||
/** Number of rules in *rules */
|
||||
int nrules;
|
||||
/** Keys binding list */
|
||||
Key *keys;
|
||||
/** Number of keys binding in *keys */
|
||||
int nkeys;
|
||||
/** Default modkey */
|
||||
KeySym modkey;
|
||||
/** Numlock mask */
|
||||
unsigned int numlockmask;
|
||||
/** Bar position */
|
||||
int bpos;
|
||||
/** Border size */
|
||||
int borderpx;
|
||||
/** Master width factor */
|
||||
double mwfact;
|
||||
/** Number of pixels to snap windows */
|
||||
int snap;
|
||||
/** Number of master windows */
|
||||
int nmaster;
|
||||
/** Transparency of unfocused clients */
|
||||
int opacity_unfocused;
|
||||
/** Text displayed in bar */
|
||||
char statustext[256];
|
||||
/** Current layout */
|
||||
Layout * current_layout;
|
||||
};
|
||||
|
||||
void parse_config(Display *, int, DC *, jdwm_config *); /* parse configuration file */
|
||||
void uicb_reload(Display *, jdwm_config *, const char *); /* reload configuration file */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
# jdwm version
|
||||
VERSION = 0.0
|
||||
|
||||
# Customize below to fit your system
|
||||
|
||||
# additional layouts beside floating
|
||||
LAYOUTS = layouts/tile.c layouts/grid.c layouts/spiral.c layouts/floating.c
|
||||
|
||||
# paths
|
||||
PREFIX = /usr/local
|
||||
MANPREFIX = ${PREFIX}/share/man
|
||||
|
||||
X11INC = /usr/include/X11
|
||||
X11LIB = /usr/lib/X11
|
||||
|
||||
# includes and libs
|
||||
INCS = -I. -I/usr/include -I${X11INC} `pkg-config --cflags libconfig`
|
||||
LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 `pkg-config --libs libconfig`
|
||||
|
||||
# flags
|
||||
CFLAGS = -fgnu89-inline -std=gnu99 -ggdb3 -pipe -Wall -Wextra -W -Wchar-subscripts -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wsign-compare -Wunused -Wuninitialized -Winit-self -Wpointer-arith -Wredundant-decls -Wno-format-zero-length -Wmissing-prototypes -Wmissing-format-attribute -Wmissing-noreturn -O2 ${INCS} -DVERSION=\"${VERSION}\"
|
||||
LDFLAGS = -ggdb3 ${LIBS}
|
||||
|
||||
# compiler and linker
|
||||
CC = cc
|
|
@ -0,0 +1,160 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "layout.h"
|
||||
|
||||
extern int sw; /* screen geometry */
|
||||
extern int bh, blw; /* bar height, bar layout label width */
|
||||
extern Window barwin;
|
||||
extern DC dc; /* global draw context */
|
||||
extern Client *clients, *sel, *stack; /* global client list and stack */
|
||||
extern Bool *seltags;
|
||||
|
||||
/* static */
|
||||
|
||||
static unsigned int
|
||||
textnw(const char *text, unsigned int len)
|
||||
{
|
||||
XRectangle r;
|
||||
|
||||
if(dc.font.set)
|
||||
{
|
||||
XmbTextExtents(dc.font.set, text, len, NULL, &r);
|
||||
return r.width;
|
||||
}
|
||||
return XTextWidth(dc.font.xfont, text, len);
|
||||
}
|
||||
|
||||
static void
|
||||
drawtext(Display *disp, const char *text, unsigned long col[ColLast])
|
||||
{
|
||||
int x, y, w, h;
|
||||
static char buf[256];
|
||||
unsigned int len, olen;
|
||||
XRectangle r = { dc.x, dc.y, dc.w, dc.h };
|
||||
|
||||
XSetForeground(disp, dc.gc, col[ColBG]);
|
||||
XFillRectangles(disp, dc.drawable, dc.gc, &r, 1);
|
||||
if(!text)
|
||||
return;
|
||||
w = 0;
|
||||
olen = len = strlen(text);
|
||||
if(len >= sizeof buf)
|
||||
len = sizeof buf - 1;
|
||||
memcpy(buf, text, len);
|
||||
buf[len] = 0;
|
||||
h = dc.font.ascent + dc.font.descent;
|
||||
y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
|
||||
x = dc.x + (h / 2);
|
||||
/* shorten text if necessary */
|
||||
while(len && (w = textnw(buf, len)) > dc.w - h)
|
||||
buf[--len] = 0;
|
||||
if(len < olen)
|
||||
{
|
||||
if(len > 1)
|
||||
buf[len - 1] = '.';
|
||||
if(len > 2)
|
||||
buf[len - 2] = '.';
|
||||
if(len > 3)
|
||||
buf[len - 3] = '.';
|
||||
}
|
||||
if(w > dc.w)
|
||||
return; /* too long */
|
||||
XSetForeground(disp, dc.gc, col[ColFG]);
|
||||
if(dc.font.set)
|
||||
XmbDrawString(disp, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
|
||||
else
|
||||
XDrawString(disp, dc.drawable, dc.gc, x, y, buf, len);
|
||||
}
|
||||
|
||||
static void
|
||||
drawsquare(Bool filled, Bool empty, unsigned long col[ColLast], Display *disp)
|
||||
{
|
||||
int x;
|
||||
XGCValues gcv;
|
||||
XRectangle r = { dc.x, dc.y, dc.w, dc.h };
|
||||
|
||||
gcv.foreground = col[ColFG];
|
||||
XChangeGC(disp, dc.gc, GCForeground, &gcv);
|
||||
x = (dc.font.ascent + dc.font.descent + 2) / 4;
|
||||
r.x = dc.x + 1;
|
||||
r.y = dc.y + 1;
|
||||
if(filled)
|
||||
{
|
||||
r.width = r.height = x + 1;
|
||||
XFillRectangles(disp, dc.drawable, dc.gc, &r, 1);
|
||||
}
|
||||
else if(empty)
|
||||
{
|
||||
r.width = r.height = x;
|
||||
XDrawRectangles(disp, dc.drawable, dc.gc, &r, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static Bool
|
||||
isoccupied(unsigned int t)
|
||||
{
|
||||
Client *c;
|
||||
|
||||
for(c = clients; c; c = c->next)
|
||||
if(c->tags[t])
|
||||
return True;
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
/* extern */
|
||||
|
||||
void
|
||||
drawstatus(Display *disp, jdwm_config * jdwmconf)
|
||||
{
|
||||
int x, i;
|
||||
dc.x = dc.y = 0;
|
||||
for(i = 0; i < jdwmconf->ntags; i++)
|
||||
{
|
||||
dc.w = textw(jdwmconf->tags[i]);
|
||||
if(seltags[i])
|
||||
{
|
||||
drawtext(disp, jdwmconf->tags[i], dc.sel);
|
||||
drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel, disp);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawtext(disp, jdwmconf->tags[i], dc.norm);
|
||||
drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm, disp);
|
||||
}
|
||||
dc.x += dc.w;
|
||||
}
|
||||
dc.w = blw;
|
||||
drawtext(disp, jdwmconf->current_layout->symbol, dc.norm);
|
||||
x = dc.x + dc.w;
|
||||
dc.w = textw(jdwmconf->statustext);
|
||||
dc.x = sw - dc.w;
|
||||
if(dc.x < x)
|
||||
{
|
||||
dc.x = x;
|
||||
dc.w = sw - x;
|
||||
}
|
||||
drawtext(disp, jdwmconf->statustext, dc.norm);
|
||||
if((dc.w = dc.x - x) > bh)
|
||||
{
|
||||
dc.x = x;
|
||||
if(sel)
|
||||
{
|
||||
drawtext(disp, sel->name, dc.sel);
|
||||
drawsquare(sel->ismax, sel->isfloating, dc.sel, disp);
|
||||
}
|
||||
else
|
||||
drawtext(disp, NULL, dc.norm);
|
||||
}
|
||||
XCopyArea(disp, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
|
||||
XSync(disp, False);
|
||||
}
|
||||
|
||||
|
||||
inline unsigned int
|
||||
textw(const char *text)
|
||||
{
|
||||
return textnw(text, strlen(text)) + dc.font.height;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_DRAW_H
|
||||
#define JDWM_DRAW_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void drawstatus(Display *, jdwm_config *); /* draw the bar */
|
||||
inline unsigned int textw(const char *text); /* return the width of text in px */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,412 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
#include <stdlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include "jdwm.h"
|
||||
#include "util.h"
|
||||
#include "event.h"
|
||||
#include "layout.h"
|
||||
#include "tag.h"
|
||||
#include "layouts/tile.h"
|
||||
#include "layouts/floating.h"
|
||||
|
||||
/* extern */
|
||||
extern int screen, sw, sh; /* screen geometry */
|
||||
extern int wax, way, wah, waw; /* windowarea geometry */
|
||||
extern int bh, blw; /* bar height, bar layout label width */
|
||||
extern Window barwin;
|
||||
extern DC dc; /* global draw context */
|
||||
extern Cursor cursor[CurLast];
|
||||
extern Client *clients, *sel; /* global client list */
|
||||
extern Bool selscreen;
|
||||
extern Atom netatom[NetLast];
|
||||
void (*handler[LASTEvent]) (XEvent *, jdwm_config *); /* event handler */
|
||||
|
||||
#define CLEANMASK(mask) (mask & ~(jdwmconf->numlockmask | LockMask))
|
||||
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
|
||||
|
||||
static Client *
|
||||
getclient(Window w)
|
||||
{
|
||||
Client *c;
|
||||
|
||||
for(c = clients; c && c->win != w; c = c->next);
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
movemouse(Client * c, jdwm_config *jdwmconf)
|
||||
{
|
||||
int x1, y1, ocx, ocy, di, nx, ny;
|
||||
unsigned int dui;
|
||||
Window dummy;
|
||||
XEvent ev;
|
||||
|
||||
ocx = nx = c->x;
|
||||
ocy = ny = c->y;
|
||||
if(XGrabPointer(c->display, DefaultRootWindow(c->display), False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
None, cursor[CurMove], CurrentTime) != GrabSuccess)
|
||||
return;
|
||||
XQueryPointer(c->display, DefaultRootWindow(c->display), &dummy, &dummy, &x1, &y1, &di, &di, &dui);
|
||||
for(;;)
|
||||
{
|
||||
XMaskEvent(c->display, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
|
||||
switch (ev.type)
|
||||
{
|
||||
case ButtonRelease:
|
||||
XUngrabPointer(c->display, CurrentTime);
|
||||
return;
|
||||
case ConfigureRequest:
|
||||
case Expose:
|
||||
case MapRequest:
|
||||
handler[ev.type] (&ev, jdwmconf);
|
||||
break;
|
||||
case MotionNotify:
|
||||
XSync(c->display, False);
|
||||
nx = ocx + (ev.xmotion.x - x1);
|
||||
ny = ocy + (ev.xmotion.y - y1);
|
||||
if(abs(wax + nx) < jdwmconf->snap)
|
||||
nx = wax;
|
||||
else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < jdwmconf->snap)
|
||||
nx = wax + waw - c->w - 2 * c->border;
|
||||
if(abs(way - ny) < jdwmconf->snap)
|
||||
ny = way;
|
||||
else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < jdwmconf->snap)
|
||||
ny = way + wah - c->h - 2 * c->border;
|
||||
resize(c, nx, ny, c->w, c->h, False);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
resizemouse(Client * c, jdwm_config *jdwmconf)
|
||||
{
|
||||
int ocx, ocy;
|
||||
int nw, nh;
|
||||
XEvent ev;
|
||||
|
||||
ocx = c->x;
|
||||
ocy = c->y;
|
||||
if(XGrabPointer(c->display, DefaultRootWindow(c->display), False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
None, cursor[CurResize], CurrentTime) != GrabSuccess)
|
||||
return;
|
||||
c->ismax = False;
|
||||
XWarpPointer(c->display, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
|
||||
for(;;)
|
||||
{
|
||||
XMaskEvent(c->display, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
|
||||
switch (ev.type)
|
||||
{
|
||||
case ButtonRelease:
|
||||
XWarpPointer(c->display, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
|
||||
XUngrabPointer(c->display, CurrentTime);
|
||||
while(XCheckMaskEvent(c->display, EnterWindowMask, &ev));
|
||||
return;
|
||||
case ConfigureRequest:
|
||||
case Expose:
|
||||
case MapRequest:
|
||||
handler[ev.type] (&ev, jdwmconf);
|
||||
break;
|
||||
case MotionNotify:
|
||||
XSync(c->display, False);
|
||||
if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
|
||||
nw = 1;
|
||||
if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
|
||||
nh = 1;
|
||||
resize(c, c->x, c->y, nw, nh, True);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
buttonpress(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
int i, x;
|
||||
Client *c;
|
||||
XButtonPressedEvent *ev = &e->xbutton;
|
||||
|
||||
if(barwin == ev->window)
|
||||
{
|
||||
x = 0;
|
||||
for(i = 0; i < jdwmconf->ntags; i++)
|
||||
{
|
||||
x += textw(jdwmconf->tags[i]);
|
||||
if(ev->x < x)
|
||||
{
|
||||
if(ev->button == Button1)
|
||||
{
|
||||
if(ev->state & jdwmconf->modkey)
|
||||
uicb_tag(e->xany.display, jdwmconf, jdwmconf->tags[i]);
|
||||
else
|
||||
uicb_view(e->xany.display, jdwmconf, jdwmconf->tags[i]);
|
||||
}
|
||||
else if(ev->button == Button3)
|
||||
{
|
||||
if(ev->state & jdwmconf->modkey)
|
||||
uicb_toggletag(e->xany.display, jdwmconf, jdwmconf->tags[i]);
|
||||
else
|
||||
uicb_toggleview(e->xany.display, jdwmconf, jdwmconf->tags[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if((ev->x < x + blw) && ev->button == Button1)
|
||||
uicb_setlayout(e->xany.display, jdwmconf, NULL);
|
||||
}
|
||||
else if((c = getclient(ev->window)))
|
||||
{
|
||||
focus(c->display, &dc, c, jdwmconf);
|
||||
if(CLEANMASK(ev->state) != jdwmconf->modkey)
|
||||
return;
|
||||
if(ev->button == Button1 && (IS_ARRANGE(floating) || c->isfloating))
|
||||
{
|
||||
restack(e->xany.display, jdwmconf);
|
||||
movemouse(c, jdwmconf);
|
||||
}
|
||||
else if(ev->button == Button2)
|
||||
uicb_zoom(e->xany.display, jdwmconf, NULL);
|
||||
else if(ev->button == Button3 && (IS_ARRANGE(floating) || c->isfloating) && !c->isfixed)
|
||||
{
|
||||
restack(e->xany.display, jdwmconf);
|
||||
resizemouse(c, jdwmconf);
|
||||
}
|
||||
}
|
||||
else if(DefaultRootWindow(e->xany.display) == ev->window && !sel)
|
||||
{
|
||||
if(ev->button == Button4)
|
||||
uicb_tag_viewnext(e->xany.display, jdwmconf, NULL);
|
||||
else if(ev->button == Button5)
|
||||
uicb_tag_viewprev(e->xany.display, jdwmconf, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
configurerequest(XEvent * e, jdwm_config *jdwmconf __attribute__ ((unused)))
|
||||
{
|
||||
Client *c;
|
||||
XConfigureRequestEvent *ev = &e->xconfigurerequest;
|
||||
XWindowChanges wc;
|
||||
|
||||
if((c = getclient(ev->window)))
|
||||
{
|
||||
c->ismax = False;
|
||||
if(ev->value_mask & CWBorderWidth)
|
||||
c->border = ev->border_width;
|
||||
if(c->isfixed || c->isfloating || IS_ARRANGE(floating))
|
||||
{
|
||||
if(ev->value_mask & CWX)
|
||||
c->x = ev->x;
|
||||
if(ev->value_mask & CWY)
|
||||
c->y = ev->y;
|
||||
if(ev->value_mask & CWWidth)
|
||||
c->w = ev->width;
|
||||
if(ev->value_mask & CWHeight)
|
||||
c->h = ev->height;
|
||||
if((c->x + c->w) > sw && c->isfloating)
|
||||
c->x = sw / 2 - c->w / 2; /* center in x direction */
|
||||
if((c->y + c->h) > sh && c->isfloating)
|
||||
c->y = sh / 2 - c->h / 2; /* center in y direction */
|
||||
if((ev->value_mask & (CWX | CWY)) && !(ev->value_mask & (CWWidth | CWHeight)))
|
||||
configure(c);
|
||||
if(isvisible(c, jdwmconf->ntags))
|
||||
XMoveResizeWindow(e->xany.display, c->win, c->x, c->y, c->w, c->h);
|
||||
}
|
||||
else
|
||||
configure(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
wc.x = ev->x;
|
||||
wc.y = ev->y;
|
||||
wc.width = ev->width;
|
||||
wc.height = ev->height;
|
||||
wc.border_width = ev->border_width;
|
||||
wc.sibling = ev->above;
|
||||
wc.stack_mode = ev->detail;
|
||||
XConfigureWindow(e->xany.display, ev->window, ev->value_mask, &wc);
|
||||
}
|
||||
XSync(e->xany.display, False);
|
||||
}
|
||||
|
||||
static void
|
||||
configurenotify(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
XConfigureEvent *ev = &e->xconfigure;
|
||||
|
||||
if(ev->window == DefaultRootWindow(e->xany.display) && (ev->width != sw || ev->height != sh))
|
||||
{
|
||||
sw = ev->width;
|
||||
sh = ev->height;
|
||||
XFreePixmap(e->xany.display, dc.drawable);
|
||||
dc.drawable = XCreatePixmap(e->xany.display, DefaultRootWindow(e->xany.display), sw, bh, DefaultDepth(e->xany.display, screen));
|
||||
XResizeWindow(e->xany.display, barwin, sw, bh);
|
||||
updatebarpos(e->xany.display);
|
||||
arrange(e->xany.display, jdwmconf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroynotify(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
Client *c;
|
||||
XDestroyWindowEvent *ev = &e->xdestroywindow;
|
||||
|
||||
if((c = getclient(ev->window)))
|
||||
unmanage(c, &dc, WithdrawnState, jdwmconf);
|
||||
}
|
||||
|
||||
static void
|
||||
enternotify(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
Client *c;
|
||||
XCrossingEvent *ev = &e->xcrossing;
|
||||
|
||||
if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
|
||||
return;
|
||||
if((c = getclient(ev->window)))
|
||||
focus(c->display, &dc, c, jdwmconf);
|
||||
else if(ev->window == DefaultRootWindow(e->xany.display))
|
||||
{
|
||||
selscreen = True;
|
||||
focus(e->xany.display, &dc, NULL, jdwmconf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
expose(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
XExposeEvent *ev = &e->xexpose;
|
||||
|
||||
if(!ev->count && barwin == ev->window)
|
||||
drawstatus(e->xany.display, jdwmconf);
|
||||
}
|
||||
|
||||
static void
|
||||
keypress(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
int i;
|
||||
KeySym keysym;
|
||||
XKeyEvent *ev = &e->xkey;
|
||||
|
||||
keysym = XKeycodeToKeysym(e->xany.display, (KeyCode) ev->keycode, 0);
|
||||
for(i = 0; i < jdwmconf->nkeys; i++)
|
||||
if(keysym == jdwmconf->keys[i].keysym
|
||||
&& CLEANMASK(jdwmconf->keys[i].mod) == CLEANMASK(ev->state) && jdwmconf->keys[i].func)
|
||||
jdwmconf->keys[i].func(e->xany.display, jdwmconf, jdwmconf->keys[i].arg);
|
||||
}
|
||||
|
||||
static void
|
||||
leavenotify(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
XCrossingEvent *ev = &e->xcrossing;
|
||||
|
||||
if((ev->window == DefaultRootWindow(e->xany.display)) && !ev->same_screen)
|
||||
{
|
||||
selscreen = False;
|
||||
focus(e->xany.display, &dc, NULL, jdwmconf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mappingnotify(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
XMappingEvent *ev = &e->xmapping;
|
||||
|
||||
XRefreshKeyboardMapping(ev);
|
||||
if(ev->request == MappingKeyboard)
|
||||
grabkeys(e->xany.display, jdwmconf);
|
||||
}
|
||||
|
||||
static void
|
||||
maprequest(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
static XWindowAttributes wa;
|
||||
XMapRequestEvent *ev = &e->xmaprequest;
|
||||
|
||||
if(!XGetWindowAttributes(e->xany.display, ev->window, &wa))
|
||||
return;
|
||||
if(wa.override_redirect)
|
||||
return;
|
||||
if(!getclient(ev->window))
|
||||
manage(e->xany.display, &dc, ev->window, &wa, jdwmconf);
|
||||
}
|
||||
|
||||
static void
|
||||
propertynotify(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
Client *c;
|
||||
Window trans;
|
||||
XPropertyEvent *ev = &e->xproperty;
|
||||
|
||||
if(ev->state == PropertyDelete)
|
||||
return; /* ignore */
|
||||
if((c = getclient(ev->window)))
|
||||
{
|
||||
switch (ev->atom)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case XA_WM_TRANSIENT_FOR:
|
||||
XGetTransientForHint(e->xany.display, c->win, &trans);
|
||||
if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
|
||||
arrange(e->xany.display, jdwmconf);
|
||||
break;
|
||||
case XA_WM_NORMAL_HINTS:
|
||||
updatesizehints(c);
|
||||
break;
|
||||
}
|
||||
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName])
|
||||
{
|
||||
updatetitle(c);
|
||||
if(c == sel)
|
||||
drawstatus(e->xany.display, jdwmconf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unmapnotify(XEvent * e, jdwm_config *jdwmconf)
|
||||
{
|
||||
Client *c;
|
||||
XUnmapEvent *ev = &e->xunmap;
|
||||
|
||||
if((c = getclient(ev->window)) && ev->event == DefaultRootWindow(e->xany.display) && (ev->send_event || !c->unmapped--))
|
||||
unmanage(c, &dc, WithdrawnState, jdwmconf);
|
||||
}
|
||||
|
||||
/* extern */
|
||||
|
||||
void (*handler[LASTEvent]) (XEvent *, jdwm_config *) =
|
||||
{
|
||||
[ButtonPress] = buttonpress,
|
||||
[ConfigureRequest] = configurerequest,
|
||||
[ConfigureNotify] = configurenotify,
|
||||
[DestroyNotify] = destroynotify,
|
||||
[EnterNotify] = enternotify,
|
||||
[LeaveNotify] = leavenotify,
|
||||
[Expose] = expose,
|
||||
[KeyPress] = keypress,
|
||||
[MappingNotify] = mappingnotify,
|
||||
[MapRequest] = maprequest,[PropertyNotify] = propertynotify,[UnmapNotify] = unmapnotify};
|
||||
|
||||
void
|
||||
grabkeys(Display *disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
int i;
|
||||
KeyCode code;
|
||||
|
||||
XUngrabKey(disp, AnyKey, AnyModifier, DefaultRootWindow(disp));
|
||||
for(i = 0; i < jdwmconf->nkeys; i++)
|
||||
{
|
||||
code = XKeysymToKeycode(disp, jdwmconf->keys[i].keysym);
|
||||
XGrabKey(disp, code, jdwmconf->keys[i].mod, DefaultRootWindow(disp), True, GrabModeAsync, GrabModeAsync);
|
||||
XGrabKey(disp, code, jdwmconf->keys[i].mod | LockMask, DefaultRootWindow(disp), True, GrabModeAsync, GrabModeAsync);
|
||||
XGrabKey(disp, code, jdwmconf->keys[i].mod | jdwmconf->numlockmask, DefaultRootWindow(disp), True, GrabModeAsync, GrabModeAsync);
|
||||
XGrabKey(disp, code, jdwmconf->keys[i].mod | jdwmconf->numlockmask | LockMask, DefaultRootWindow(disp), True,
|
||||
GrabModeAsync, GrabModeAsync);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_EVENT_H
|
||||
#define JDWM_EVENT_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void grabkeys(Display *, jdwm_config *); /* grab all keys defined in config */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,153 @@
|
|||
.TH DWM 1 dwm\-VERSION
|
||||
.SH NAME
|
||||
dwm \- dynamic window manager
|
||||
.SH SYNOPSIS
|
||||
.B dwm
|
||||
.RB [ \-v ]
|
||||
.SH DESCRIPTION
|
||||
dwm is a dynamic window manager for X. It manages windows in tiled and
|
||||
floating layouts. Either layout can be applied dynamically, optimizing the
|
||||
environment for the application in use and the task performed.
|
||||
.P
|
||||
In tiled layout windows are managed in a master and stacking area. The master
|
||||
area contains the window which currently needs most attention, whereas the
|
||||
stacking area contains all other windows. In floating layout windows can be
|
||||
resized and moved freely. Dialog windows are always managed floating,
|
||||
regardless of the layout applied.
|
||||
.P
|
||||
Windows are grouped by tags. Each window can be tagged with one or multiple
|
||||
tags. Selecting certain tags displays all windows with these tags.
|
||||
.P
|
||||
dwm contains a small status bar which displays all available tags, the layout,
|
||||
the title of the focused window, and the text read from standard input. A
|
||||
floating window is indicated with an empty square and a maximized
|
||||
floating window is indicated with a filled square before the windows
|
||||
title. The selected tags are indicated with a different color. The tags of
|
||||
the focused window are indicated with a filled square in the top left
|
||||
corner. The tags which are applied to one or more windows are indicated
|
||||
with an empty square in the top left corner.
|
||||
.P
|
||||
dwm draws a small border around windows to indicate the focus state.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-v
|
||||
prints version information to standard output, then exits.
|
||||
.SH USAGE
|
||||
.SS Status bar
|
||||
.TP
|
||||
.B Standard input
|
||||
is read and displayed in the status text area.
|
||||
.TP
|
||||
.B Button1
|
||||
click on a tag label to display all windows with that tag, click on the layout
|
||||
label toggles between tiled and floating layout.
|
||||
.TP
|
||||
.B Button3
|
||||
click on a tag label adds/removes all windows with that tag to/from the view.
|
||||
.TP
|
||||
.B Mod1\-Button1
|
||||
click on a tag label applies that tag to the focused window.
|
||||
.TP
|
||||
.B Mod1\-Button3
|
||||
click on a tag label adds/removes that tag to/from the focused window.
|
||||
.SS Keyboard commands
|
||||
.TP
|
||||
.B Mod1\-Shift\-Return
|
||||
Start
|
||||
.BR xterm.
|
||||
.TP
|
||||
.B Mod1\-Return
|
||||
Zooms/cycles current window to/from master area (tiled layout only).
|
||||
.TP
|
||||
.B Mod1\-b
|
||||
Shows/hides the status bar.
|
||||
.TP
|
||||
.B Mod1\-h
|
||||
Decreases the master area width about 5% (tiled layout only).
|
||||
.TP
|
||||
.B Mod1\-j
|
||||
Focus next window.
|
||||
.TP
|
||||
.B Mod1\-k
|
||||
Focus previous window.
|
||||
.TP
|
||||
.B Mod1\-l
|
||||
Increases the master area width about 5% (tiled layout only).
|
||||
.TP
|
||||
.B Mod1\-m
|
||||
Toggles maximization of current window (floating layout only).
|
||||
.TP
|
||||
.B Mod1\-Shift\-[1..n]
|
||||
Apply
|
||||
.RB nth
|
||||
tag to current window.
|
||||
.TP
|
||||
.B Mod1\-Shift\-0
|
||||
Apply all tags to current window.
|
||||
.TP
|
||||
.B Mod1\-Control\-Shift\-[1..n]
|
||||
Add/remove
|
||||
.B nth
|
||||
tag to/from current window.
|
||||
.TP
|
||||
.B Mod1\-Shift\-c
|
||||
Close focused window.
|
||||
.TP
|
||||
.B Mod1\-space
|
||||
Toggle between tiled and floating layout (affects all windows).
|
||||
.TP
|
||||
.B Mod1\-Shift\-space
|
||||
Toggle focused window between tiled and floating state (tiled layout only).
|
||||
.TP
|
||||
.B Mod1\-[1..n]
|
||||
View all windows with
|
||||
.BR nth
|
||||
tag.
|
||||
.TP
|
||||
.B Mod1\-0
|
||||
View all windows with any tag.
|
||||
.TP
|
||||
.B Mod1\-Control\-[1..n]
|
||||
Add/remove all windows with
|
||||
.BR nth
|
||||
tag to/from the view.
|
||||
.TP
|
||||
.B Mod1\-Shift\-q
|
||||
Quit dwm.
|
||||
.SS Mouse commands
|
||||
.TP
|
||||
.B Mod1\-Button1
|
||||
Move current window while dragging (floating layout only).
|
||||
.TP
|
||||
.B Mod1\-Button2
|
||||
Zooms/cycles current window to/from master area (tiled layout only).
|
||||
.TP
|
||||
.B Mod1\-Button3
|
||||
Resize current window while dragging (floating layout only).
|
||||
.SH CUSTOMIZATION
|
||||
dwm is customized by creating a custom config.h and (re)compiling the source
|
||||
code. This keeps it fast, secure and simple.
|
||||
.SH SEE ALSO
|
||||
.BR dmenu (1)
|
||||
.SH BUGS
|
||||
The status bar may display
|
||||
.BR "EOF"
|
||||
when dwm has been started by an X session manager like
|
||||
.BR xdm (1),
|
||||
because those close standard output before executing dwm.
|
||||
.P
|
||||
Java applications which use the XToolkit/XAWT backend may draw grey windows
|
||||
only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early
|
||||
JDK 1.6 versions, because it assumes a reparenting window manager. As a workaround
|
||||
you can use JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or you
|
||||
can set the following environment variable (to use the older Motif
|
||||
backend instead):
|
||||
.BR AWT_TOOLKIT=MToolkit .
|
||||
.P
|
||||
Recent GTK 2.10.9+ versions contain a broken
|
||||
.BR Save\-As
|
||||
file dialog implementation,
|
||||
which requests to reconfigure its window size in an endless loop. However, its
|
||||
window is still respondable during this state, so you can simply ignore the flicker
|
||||
until a new GTK version appears, which will fix this bug, approximately
|
||||
GTK 2.10.12+ versions.
|
|
@ -0,0 +1,379 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <X11/cursorfont.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include "jdwm.h"
|
||||
#include "util.h"
|
||||
#include "event.h"
|
||||
#include "layout.h"
|
||||
#include "tag.h"
|
||||
|
||||
/* extern */
|
||||
extern int bpos; /* bar position */
|
||||
extern void (*handler[LASTEvent]) (XEvent *, jdwm_config *); /* event handler */
|
||||
|
||||
int screen, sx, sy, sw, sh, wax, way, waw, wah;
|
||||
int bh;
|
||||
Atom jdwmprops, wmatom[WMLast], netatom[NetLast];
|
||||
Bool *seltags, *prevtags;;
|
||||
Bool selscreen = True;
|
||||
Client *clients = NULL;
|
||||
Client *sel = NULL;
|
||||
Client *stack = NULL;
|
||||
Cursor cursor[CurLast];
|
||||
DC dc;
|
||||
Window barwin;
|
||||
Layout ** taglayouts;
|
||||
|
||||
/* static */
|
||||
|
||||
static int (*xerrorxlib) (Display *, XErrorEvent *);
|
||||
static Bool otherwm = False, readin = True;
|
||||
static Bool running = True;
|
||||
|
||||
|
||||
Bool
|
||||
gettextprop(Display *disp, Window w, Atom atom, char *text, unsigned int size)
|
||||
{
|
||||
char **list = NULL;
|
||||
int n;
|
||||
|
||||
XTextProperty name;
|
||||
|
||||
if(!text || size == 0)
|
||||
return False;
|
||||
|
||||
text[0] = '\0';
|
||||
XGetTextProperty(disp, w, &name, atom);
|
||||
|
||||
if(!name.nitems)
|
||||
return False;
|
||||
|
||||
if(name.encoding == XA_STRING)
|
||||
strncpy(text, (char *) name.value, size - 1);
|
||||
else if(XmbTextPropertyToTextList(disp, &name, &list, &n) >= Success && n > 0 && *list)
|
||||
{
|
||||
strncpy(text, *list, size - 1);
|
||||
XFreeStringList(list);
|
||||
}
|
||||
|
||||
text[size - 1] = '\0';
|
||||
XFree(name.value);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
cleanup(Display *disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
close(STDIN_FILENO);
|
||||
while(stack)
|
||||
{
|
||||
unban(stack);
|
||||
unmanage(stack, &dc, NormalState, jdwmconf);
|
||||
}
|
||||
if(dc.font.set)
|
||||
XFreeFontSet(disp, dc.font.set);
|
||||
else
|
||||
XFreeFont(disp, dc.font.xfont);
|
||||
XUngrabKey(disp, AnyKey, AnyModifier, DefaultRootWindow(disp));
|
||||
XFreePixmap(disp, dc.drawable);
|
||||
XFreeGC(disp, dc.gc);
|
||||
XDestroyWindow(disp, barwin);
|
||||
XFreeCursor(disp, cursor[CurNormal]);
|
||||
XFreeCursor(disp, cursor[CurResize]);
|
||||
XFreeCursor(disp, cursor[CurMove]);
|
||||
XSetInputFocus(disp, PointerRoot, RevertToPointerRoot, CurrentTime);
|
||||
XSync(disp, False);
|
||||
p_delete(&seltags);
|
||||
p_delete(&prevtags);
|
||||
p_delete(&taglayouts);
|
||||
}
|
||||
|
||||
static long
|
||||
getstate(Display *disp, Window w)
|
||||
{
|
||||
int format, status;
|
||||
long result = -1;
|
||||
unsigned char *p = NULL;
|
||||
unsigned long n, extra;
|
||||
Atom real;
|
||||
status = XGetWindowProperty(disp, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
|
||||
&real, &format, &n, &extra, (unsigned char **) &p);
|
||||
if(status != Success)
|
||||
return -1;
|
||||
if(n != 0)
|
||||
result = *p;
|
||||
XFree(p);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
scan(Display *disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
unsigned int i, num;
|
||||
Window *wins, d1, d2;
|
||||
XWindowAttributes wa;
|
||||
|
||||
wins = NULL;
|
||||
if(XQueryTree(disp, DefaultRootWindow(disp), &d1, &d2, &wins, &num))
|
||||
for(i = 0; i < num; i++)
|
||||
{
|
||||
if(!XGetWindowAttributes(disp, wins[i], &wa)
|
||||
|| wa.override_redirect || XGetTransientForHint(disp, wins[i], &d1))
|
||||
continue;
|
||||
if(wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState)
|
||||
manage(disp, &dc, wins[i], &wa, jdwmconf);
|
||||
}
|
||||
/* now the transients */
|
||||
for(i = 0; i < num; i++)
|
||||
{
|
||||
if(!XGetWindowAttributes(disp, wins[i], &wa))
|
||||
continue;
|
||||
if(XGetTransientForHint(disp, wins[i], &d1)
|
||||
&& (wa.map_state == IsViewable || getstate(disp, wins[i]) == IconicState))
|
||||
manage(disp, &dc, wins[i], &wa, jdwmconf);
|
||||
}
|
||||
if(wins)
|
||||
XFree(wins);
|
||||
}
|
||||
|
||||
static void
|
||||
setup(Display *disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
int i;
|
||||
unsigned int mask;
|
||||
Window w;
|
||||
XSetWindowAttributes wa;
|
||||
|
||||
/* init atoms */
|
||||
jdwmprops = XInternAtom(disp, "_JDWM_PROPERTIES", False);
|
||||
wmatom[WMProtocols] = XInternAtom(disp, "WM_PROTOCOLS", False);
|
||||
wmatom[WMDelete] = XInternAtom(disp, "WM_DELETE_WINDOW", False);
|
||||
wmatom[WMName] = XInternAtom(disp, "WM_NAME", False);
|
||||
wmatom[WMState] = XInternAtom(disp, "WM_STATE", False);
|
||||
netatom[NetSupported] = XInternAtom(disp, "_NET_SUPPORTED", False);
|
||||
netatom[NetWMName] = XInternAtom(disp, "_NET_WM_NAME", False);
|
||||
XChangeProperty(disp, DefaultRootWindow(disp), netatom[NetSupported], XA_ATOM, 32,
|
||||
PropModeReplace, (unsigned char *) netatom, NetLast);
|
||||
/* init cursors */
|
||||
cursor[CurNormal] = XCreateFontCursor(disp, XC_left_ptr);
|
||||
cursor[CurResize] = XCreateFontCursor(disp, XC_sizing);
|
||||
cursor[CurMove] = XCreateFontCursor(disp, XC_fleur);
|
||||
/* select for events */
|
||||
wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
|
||||
| EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
|
||||
wa.cursor = cursor[CurNormal];
|
||||
XChangeWindowAttributes(disp, DefaultRootWindow(disp), CWEventMask | CWCursor, &wa);
|
||||
XSelectInput(disp, DefaultRootWindow(disp), wa.event_mask);
|
||||
grabkeys(disp, jdwmconf);
|
||||
compileregs(jdwmconf);
|
||||
seltags = p_new(Bool, jdwmconf->ntags);
|
||||
seltags[0] = True;
|
||||
prevtags = p_new(Bool, jdwmconf->ntags);
|
||||
prevtags[0] = True;
|
||||
/* geometry */
|
||||
sx = sy = 0;
|
||||
sw = DisplayWidth(disp, screen);
|
||||
sh = DisplayHeight(disp, screen);
|
||||
initlayouts(jdwmconf);
|
||||
/* bar */
|
||||
dc.h = bh = dc.font.height + 2;
|
||||
wa.override_redirect = 1;
|
||||
wa.background_pixmap = ParentRelative;
|
||||
wa.event_mask = ButtonPressMask | ExposureMask;
|
||||
barwin = XCreateWindow(disp, DefaultRootWindow(disp), sx, sy, sw, bh, 0,
|
||||
DefaultDepth(disp, screen), CopyFromParent,
|
||||
DefaultVisual(disp, screen),
|
||||
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
|
||||
XDefineCursor(disp, barwin, cursor[CurNormal]);
|
||||
updatebarpos(disp);
|
||||
XMapRaised(disp, barwin);
|
||||
/* pixmap for everything */
|
||||
dc.drawable = XCreatePixmap(disp, DefaultRootWindow(disp), sw, bh, DefaultDepth(disp, screen));
|
||||
dc.gc = XCreateGC(disp, DefaultRootWindow(disp), 0, 0);
|
||||
XSetLineAttributes(disp, dc.gc, 1, LineSolid, CapButt, JoinMiter);
|
||||
if(!dc.font.set)
|
||||
XSetFont(disp, dc.gc, dc.font.xfont->fid);
|
||||
/* multihead support */
|
||||
selscreen = XQueryPointer(disp, DefaultRootWindow(disp), &w, &w, &i, &i, &i, &i, &mask);
|
||||
loadjdwmprops(disp, jdwmconf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Startup Error handler to check if another window manager
|
||||
* is already running.
|
||||
*/
|
||||
static int
|
||||
xerrorstart(Display * dsply __attribute__ ((unused)), XErrorEvent * ee __attribute__ ((unused)))
|
||||
{
|
||||
otherwm = True;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
|
||||
void
|
||||
uicb_quit(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config *jdwmconf __attribute__((unused)),
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
readin = running = False;
|
||||
}
|
||||
|
||||
void
|
||||
updatebarpos(Display *disp)
|
||||
{
|
||||
XEvent ev;
|
||||
|
||||
wax = sx;
|
||||
way = sy;
|
||||
wah = sh;
|
||||
waw = sw;
|
||||
switch (bpos)
|
||||
{
|
||||
default:
|
||||
wah -= bh;
|
||||
way += bh;
|
||||
XMoveWindow(disp, barwin, sx, sy);
|
||||
break;
|
||||
case BarBot:
|
||||
wah -= bh;
|
||||
XMoveWindow(disp, barwin, sx, sy + wah);
|
||||
break;
|
||||
case BarOff:
|
||||
XMoveWindow(disp, barwin, sx, sy - bh);
|
||||
break;
|
||||
}
|
||||
XSync(disp, False);
|
||||
while(XCheckMaskEvent(disp, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
/* There's no way to check accesses to destroyed windows, thus those cases are
|
||||
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
|
||||
* default error handler, which may call exit.
|
||||
*/
|
||||
int
|
||||
xerror(Display * edpy, XErrorEvent * ee)
|
||||
{
|
||||
if(ee->error_code == BadWindow
|
||||
|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
|
||||
|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
|
||||
|| (ee->request_code == X_PolyFillRectangle
|
||||
&& ee->error_code == BadDrawable)
|
||||
|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
|
||||
|| (ee->request_code == X_ConfigureWindow
|
||||
&& ee->error_code == BadMatch) || (ee->request_code == X_GrabKey
|
||||
&& ee->error_code == BadAccess)
|
||||
|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
|
||||
return 0;
|
||||
fprintf(stderr, "jdwm: fatal error: request code=%d, error code=%d\n",
|
||||
ee->request_code, ee->error_code);
|
||||
|
||||
return xerrorxlib(edpy, ee); /* may call exit */
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *p;
|
||||
int r, xfd;
|
||||
fd_set rd;
|
||||
XEvent ev;
|
||||
Display * dpy;
|
||||
Window root;
|
||||
jdwm_config jdwmconf;
|
||||
|
||||
if(argc == 2 && !strcmp("-v", argv[1]))
|
||||
eprint("jdwm-" VERSION " © 2007 Julien Danjou\n");
|
||||
else if(argc != 1)
|
||||
eprint("usage: jdwm [-v]\n");
|
||||
setlocale(LC_CTYPE, "");
|
||||
|
||||
|
||||
if(!(dpy = XOpenDisplay(NULL)))
|
||||
eprint("jdwm: cannot open display\n");
|
||||
xfd = ConnectionNumber(dpy);
|
||||
screen = DefaultScreen(dpy);
|
||||
root = RootWindow(dpy, screen);
|
||||
XSetErrorHandler(xerrorstart);
|
||||
|
||||
/* this causes an error if some other window manager is running */
|
||||
XSelectInput(dpy, root, SubstructureRedirectMask);
|
||||
XSync(dpy, False);
|
||||
|
||||
if(otherwm)
|
||||
eprint("jdwm: another window manager is already running\n");
|
||||
|
||||
XSync(dpy, False);
|
||||
XSetErrorHandler(NULL);
|
||||
xerrorxlib = XSetErrorHandler(xerror);
|
||||
XSync(dpy, False);
|
||||
parse_config(dpy, screen, &dc, &jdwmconf);
|
||||
setup(dpy, &jdwmconf);
|
||||
drawstatus(dpy, &jdwmconf);
|
||||
scan(dpy, &jdwmconf);
|
||||
XSync(dpy, False);
|
||||
|
||||
/* main event loop, also reads status text from stdin */
|
||||
while(running)
|
||||
{
|
||||
FD_ZERO(&rd);
|
||||
if(readin)
|
||||
FD_SET(STDIN_FILENO, &rd);
|
||||
FD_SET(xfd, &rd);
|
||||
if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
eprint("select failed\n");
|
||||
}
|
||||
if(FD_ISSET(STDIN_FILENO, &rd))
|
||||
{
|
||||
switch (r = read(STDIN_FILENO, jdwmconf.statustext, sizeof(jdwmconf.statustext) - 1))
|
||||
{
|
||||
case -1:
|
||||
strncpy(jdwmconf.statustext, strerror(errno), sizeof(jdwmconf.statustext) - 1);
|
||||
jdwmconf.statustext[sizeof(jdwmconf.statustext) - 1] = '\0';
|
||||
readin = False;
|
||||
break;
|
||||
case 0:
|
||||
strncpy(jdwmconf.statustext, "EOF", 4);
|
||||
readin = False;
|
||||
break;
|
||||
default:
|
||||
for(jdwmconf.statustext[r] = '\0', p = jdwmconf.statustext + strlen(jdwmconf.statustext) - 1;
|
||||
p >= jdwmconf.statustext && *p == '\n'; *p-- = '\0');
|
||||
for(; p >= jdwmconf.statustext && *p != '\n'; --p);
|
||||
if(p > jdwmconf.statustext)
|
||||
strncpy(jdwmconf.statustext, p + 1, sizeof(jdwmconf.statustext));
|
||||
}
|
||||
drawstatus(dpy, &jdwmconf);
|
||||
}
|
||||
|
||||
while(XPending(dpy))
|
||||
{
|
||||
XNextEvent(dpy, &ev);
|
||||
if(handler[ev.type])
|
||||
(handler[ev.type]) (&ev, &jdwmconf); /* call handler */
|
||||
}
|
||||
}
|
||||
cleanup(dpy, &jdwmconf);
|
||||
XCloseDisplay(dpy);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = jdwm
|
||||
PROJECT_NUMBER = 0.0
|
||||
OUTPUT_DIRECTORY = doc
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = YES
|
||||
EXTRACT_ANON_NSPACES = YES
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = .
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.d \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.idl \
|
||||
*.odl \
|
||||
*.cs \
|
||||
*.php \
|
||||
*.php3 \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.mm \
|
||||
*.dox \
|
||||
*.py \
|
||||
*.C \
|
||||
*.CC \
|
||||
*.C++ \
|
||||
*.II \
|
||||
*.I++ \
|
||||
*.H \
|
||||
*.HH \
|
||||
*.H++ \
|
||||
*.CS \
|
||||
*.PHP \
|
||||
*.PHP3 \
|
||||
*.M \
|
||||
*.MM \
|
||||
*.PY
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = YES
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = YES
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
|
@ -0,0 +1,49 @@
|
|||
/* See LICENSE file for copyright and license details.
|
||||
*
|
||||
* Julien's dynamic window manager is designed like any other X client as well.
|
||||
* It is driven through handling X events. In contrast to other X clients, a
|
||||
* window manager selects for SubstructureRedirectMask on the root window, to
|
||||
* receive events about window (dis-)appearance. Only one X connection at a
|
||||
* time is allowed to select for this event mask.
|
||||
*
|
||||
* Calls to fetch an X event from the event queue are blocking. Due reading
|
||||
* status text from standard input, a select()-driven main loop has been
|
||||
* implemented which selects for reads on the X connection and STDIN_FILENO to
|
||||
* handle all data smoothly. The event handlers of jdwm are organized in an
|
||||
* array which is accessed whenever a new event has been fetched. This allows
|
||||
* event dispatching in O(1) time.
|
||||
*
|
||||
* Each child of the root window is called a client, except windows which have
|
||||
* set the override_redirect flag. Clients are organized in a global
|
||||
* doubly-linked client list, the focus history is remembered through a global
|
||||
* stack list. Each client contains an array of Bools of the same size as the
|
||||
* global tags array to indicate the tags of a client. For each client jdwm
|
||||
* creates a small title window, which is resized whenever the (_NET_)WM_NAME
|
||||
* properties are updated or the client is moved/resized.
|
||||
*
|
||||
* Keys and tagging rules are organized as arrays and defined in the config.h
|
||||
* file. These arrays are kept static in event.o and tag.o respectively,
|
||||
* because no other part of jdwm needs access to them. The current layout is
|
||||
* represented by the lt pointer.
|
||||
*
|
||||
* To understand everything else, start reading main.c:main().
|
||||
*/
|
||||
|
||||
#ifndef JDWM_JDWM_H
|
||||
#define JDWM_JDWM_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
enum
|
||||
{ CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum
|
||||
{ NetSupported, NetWMName, NetLast }; /* EWMH atoms */
|
||||
enum
|
||||
{ WMProtocols, WMDelete, WMName, WMState, WMLast }; /* default atoms */
|
||||
|
||||
Bool gettextprop(Display *, Window, Atom, char *, unsigned int); /* return text property, UTF-8 compliant */
|
||||
void updatebarpos(Display *disp); /* updates the bar position */
|
||||
void uicb_quit(Display *, jdwm_config *, const char *); /* quit jdwm nicely */
|
||||
int xerror(Display *, XErrorEvent *); /* jdwm's X error handler */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,111 @@
|
|||
# Configuration file for jdwm
|
||||
|
||||
jdwm:
|
||||
{
|
||||
barpos = "BarTop";
|
||||
borderpx = 1;
|
||||
snap = 8;
|
||||
mwfact = 0.6;
|
||||
font = "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*";
|
||||
tags = ( "1", "2", "3", "4", "5", "6", "7", "8", "9" );
|
||||
normal_border_color = "#dddddd";
|
||||
normal_bg_color = "#000000";
|
||||
normal_fg_color = "#ffffff";
|
||||
focus_border_color = "#008b8b";
|
||||
focus_bg_color = "#008b8b";
|
||||
focus_fg_color = "#ffffff";
|
||||
|
||||
layouts = (("[]=", "tile"),
|
||||
("=[]", "tileleft"),
|
||||
("+++", "grid"),
|
||||
# ("(@)", "spiral"),
|
||||
("[\]", "dwindle"),
|
||||
("><>", "floating"),
|
||||
("TTT", "bstack"),
|
||||
("===", "bstackportrait")
|
||||
);
|
||||
|
||||
nmaster = 2;
|
||||
|
||||
rules = ({ name = "Gimp";
|
||||
tags = "";
|
||||
float = true;
|
||||
},
|
||||
{ name = "MPlayer";
|
||||
tags = "";
|
||||
float = true;
|
||||
},
|
||||
{ name = "Acroread";
|
||||
tags = "";
|
||||
float = true;
|
||||
},
|
||||
{ name = "VLC";
|
||||
tags = "";
|
||||
float = true;
|
||||
},
|
||||
{ name = "pinentry";
|
||||
tags = "";
|
||||
float = true;
|
||||
});
|
||||
|
||||
modkey = "Mod4";
|
||||
|
||||
keys = ((("Mod4"), "Return", "spawn", "exec urxvt"),
|
||||
(("Mod4"), "space", "setlayout"),
|
||||
(("Mod4"), "b", "togglebar"),
|
||||
(("Mod4"), "j", "focusnext"),
|
||||
(("Mod4"), "k", "focusprev"),
|
||||
(("Mod4"), "h", "setmwfact", "-0.05"),
|
||||
(("Mod4"), "l", "setmwfact", "+0.05"),
|
||||
(("Mod4", "Shift"), "h", "incnmaster", "1"),
|
||||
(("Mod4", "Shift"), "l", "incnmaster", "-1"),
|
||||
(("Mod4"), "m", "togglemax"),
|
||||
(("Mod4"), "Escape", "viewprevtags"),
|
||||
(("Mod4", "Control"), "Return", "zoom"),
|
||||
(("Mod4", "Control"), "space", "togglefloating"),
|
||||
(("Mod4", "Shift"), "c", "killclient"),
|
||||
(("Mod4", "Shift"), "q", "quit"),
|
||||
(("Mod4", "Shift"), "r", "reload"),
|
||||
(("Mod4"), "0", "view"),
|
||||
(("Mod4"), "1", "view", "1"),
|
||||
(("Mod4"), "2", "view", "2"),
|
||||
(("Mod4"), "3", "view", "3"),
|
||||
(("Mod4"), "4", "view", "4"),
|
||||
(("Mod4"), "5", "view", "5"),
|
||||
(("Mod4"), "6", "view", "6"),
|
||||
(("Mod4"), "7", "view", "7"),
|
||||
(("Mod4"), "8", "view", "8"),
|
||||
(("Mod4"), "9", "view", "9"),
|
||||
(("Mod4", "Control"), "0", "toggleview"),
|
||||
(("Mod4", "Control"), "1", "toggleview", "1"),
|
||||
(("Mod4", "Control"), "2", "toggleview", "2"),
|
||||
(("Mod4", "Control"), "3", "toggleview", "3"),
|
||||
(("Mod4", "Control"), "4", "toggleview", "4"),
|
||||
(("Mod4", "Control"), "5", "toggleview", "5"),
|
||||
(("Mod4", "Control"), "6", "toggleview", "6"),
|
||||
(("Mod4", "Control"), "7", "toggleview", "7"),
|
||||
(("Mod4", "Control"), "8", "toggleview", "8"),
|
||||
(("Mod4", "Control"), "9", "toggleview", "9"),
|
||||
(("Mod4", "Control"), "0", "toggleview"),
|
||||
(("Mod4", "Shift"), "0", "tag"),
|
||||
(("Mod4", "Shift"), "1", "tag", "1"),
|
||||
(("Mod4", "Shift"), "2", "tag", "2"),
|
||||
(("Mod4", "Shift"), "3", "tag", "3"),
|
||||
(("Mod4", "Shift"), "4", "tag", "4"),
|
||||
(("Mod4", "Shift"), "5", "tag", "5"),
|
||||
(("Mod4", "Shift"), "6", "tag", "6"),
|
||||
(("Mod4", "Shift"), "7", "tag", "7"),
|
||||
(("Mod4", "Shift"), "8", "tag", "8"),
|
||||
(("Mod4", "Shift"), "9", "tag", "9"),
|
||||
(("Mod4", "Shift", "Control"), "0", "toggletag"),
|
||||
(("Mod4", "Shift", "Control"), "1", "toggletag", "1"),
|
||||
(("Mod4", "Shift", "Control"), "2", "toggletag", "2"),
|
||||
(("Mod4", "Shift", "Control"), "3", "toggletag", "3"),
|
||||
(("Mod4", "Shift", "Control"), "4", "toggletag", "4"),
|
||||
(("Mod4", "Shift", "Control"), "5", "toggletag", "5"),
|
||||
(("Mod4", "Shift", "Control"), "6", "toggletag", "6"),
|
||||
(("Mod4", "Shift", "Control"), "7", "toggletag", "7"),
|
||||
(("Mod4", "Shift", "Control"), "8", "toggletag", "8"),
|
||||
(("Mod4", "Shift", "Control"), "9", "toggletag", "9")
|
||||
);
|
||||
};
|
|
@ -0,0 +1,280 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include "jdwm.h"
|
||||
#include "layout.h"
|
||||
#include "tag.h"
|
||||
#include "layouts/floating.h"
|
||||
#include "util.h"
|
||||
|
||||
int blw = 0;
|
||||
|
||||
/* static */
|
||||
|
||||
static char prop[128];
|
||||
|
||||
/* extern */
|
||||
extern Layout ** taglayouts;
|
||||
extern int wax, way, wah, waw; /* windowarea geometry */
|
||||
extern int bpos; /* bar position */
|
||||
extern Window barwin;
|
||||
extern Client *clients, *sel; /* global client list */
|
||||
extern Bool *seltags;
|
||||
extern Atom jdwmprops;
|
||||
extern DC dc;
|
||||
|
||||
void
|
||||
arrange(Display * disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
Client *c;
|
||||
|
||||
for(c = clients; c; c = c->next)
|
||||
if(isvisible(c, jdwmconf->ntags))
|
||||
unban(c);
|
||||
else
|
||||
ban(c);
|
||||
jdwmconf->current_layout->arrange(disp, jdwmconf);
|
||||
focus(disp, &dc, NULL, jdwmconf);
|
||||
restack(disp, jdwmconf);
|
||||
}
|
||||
|
||||
void
|
||||
uicb_focusnext(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config * jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
Client *c;
|
||||
|
||||
if(!sel)
|
||||
return;
|
||||
for(c = sel->next; c && !isvisible(c, jdwmconf->ntags); c = c->next);
|
||||
if(!c)
|
||||
for(c = clients; c && !isvisible(c, jdwmconf->ntags); c = c->next);
|
||||
if(c)
|
||||
{
|
||||
focus(c->display, &dc, c, jdwmconf);
|
||||
restack(c->display, jdwmconf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uicb_focusprev(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
Client *c;
|
||||
|
||||
if(!sel)
|
||||
return;
|
||||
for(c = sel->prev; c && !isvisible(c, jdwmconf->ntags); c = c->prev);
|
||||
if(!c)
|
||||
{
|
||||
for(c = clients; c && c->next; c = c->next);
|
||||
for(; c && !isvisible(c, jdwmconf->ntags); c = c->prev);
|
||||
}
|
||||
if(c)
|
||||
{
|
||||
focus(c->display, &dc, c, jdwmconf);
|
||||
restack(c->display, jdwmconf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initlayouts(jdwm_config * jdwmconf)
|
||||
{
|
||||
int w, i;
|
||||
|
||||
for(blw = i = 0; i < jdwmconf->nlayouts; i++)
|
||||
{
|
||||
w = textw(jdwmconf->layouts[i].symbol);
|
||||
if(w > blw)
|
||||
blw = w;
|
||||
}
|
||||
|
||||
taglayouts = p_new(Layout *, jdwmconf->ntags);
|
||||
for(i = 0; i < jdwmconf->ntags; i++)
|
||||
taglayouts[i] = jdwmconf->layouts;
|
||||
}
|
||||
|
||||
void
|
||||
loadjdwmprops(Display *disp, jdwm_config * jdwmconf)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(gettextprop(disp, DefaultRootWindow(disp), jdwmprops, prop, sizeof(prop)))
|
||||
{
|
||||
for(i = 0; i < jdwmconf->ntags && i < ssizeof(prop) - 1 && prop[i] != '\0'; i++)
|
||||
seltags[i] = prop[i] == '1';
|
||||
}
|
||||
}
|
||||
|
||||
inline Client *
|
||||
nexttiled(Client * c, int ntags)
|
||||
{
|
||||
for(; c && (c->isfloating || !isvisible(c, ntags)); c = c->next);
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
restack(Display * disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
Client *c;
|
||||
XEvent ev;
|
||||
XWindowChanges wc;
|
||||
|
||||
drawstatus(disp, jdwmconf);
|
||||
if(!sel)
|
||||
return;
|
||||
if(sel->isfloating || IS_ARRANGE(floating))
|
||||
XRaiseWindow(disp, sel->win);
|
||||
if(!IS_ARRANGE(floating))
|
||||
{
|
||||
wc.stack_mode = Below;
|
||||
wc.sibling = barwin;
|
||||
if(!sel->isfloating)
|
||||
{
|
||||
XConfigureWindow(disp, sel->win, CWSibling | CWStackMode, &wc);
|
||||
wc.sibling = sel->win;
|
||||
}
|
||||
for(c = nexttiled(clients, jdwmconf->ntags); c; c = nexttiled(c->next, jdwmconf->ntags))
|
||||
{
|
||||
if(c == sel)
|
||||
continue;
|
||||
XConfigureWindow(disp, c->win, CWSibling | CWStackMode, &wc);
|
||||
wc.sibling = c->win;
|
||||
}
|
||||
}
|
||||
XSync(disp, False);
|
||||
while(XCheckMaskEvent(disp, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
void
|
||||
savejdwmprops(Display *disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < jdwmconf->ntags && i < ssizeof(prop) - 1; i++)
|
||||
prop[i] = seltags[i] ? '1' : '0';
|
||||
prop[i] = '\0';
|
||||
XChangeProperty(disp, DefaultRootWindow(disp), jdwmprops, XA_STRING, 8, PropModeReplace, (unsigned char *) prop, i);
|
||||
}
|
||||
|
||||
void
|
||||
uicb_setlayout(Display *disp, jdwm_config * jdwmconf, const char *arg)
|
||||
{
|
||||
int i, j;
|
||||
Client *c;
|
||||
|
||||
if(!arg)
|
||||
{
|
||||
if(!(++jdwmconf->current_layout)->symbol)
|
||||
jdwmconf->current_layout = &jdwmconf->layouts[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
i = strtol(arg, NULL, 10);
|
||||
if(i < 0 || i >= jdwmconf->nlayouts)
|
||||
return;
|
||||
jdwmconf->current_layout = &jdwmconf->layouts[i];
|
||||
}
|
||||
|
||||
for(c = clients; c; c = c->next)
|
||||
c->ftview = True;
|
||||
|
||||
if(sel)
|
||||
arrange(disp, jdwmconf);
|
||||
else
|
||||
drawstatus(disp, jdwmconf);
|
||||
|
||||
savejdwmprops(disp, jdwmconf);
|
||||
|
||||
for(j = 0; j < jdwmconf->ntags; j++)
|
||||
if (seltags[j])
|
||||
taglayouts[j] = jdwmconf->current_layout;
|
||||
}
|
||||
|
||||
void
|
||||
uicb_togglebar(Display *disp,
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
if(bpos == BarOff)
|
||||
bpos = (jdwmconf->bpos == BarOff) ? BarTop : jdwmconf->bpos;
|
||||
else
|
||||
bpos = BarOff;
|
||||
updatebarpos(disp);
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
static void
|
||||
maximize(int x, int y, int w, int h, jdwm_config *jdwmconf)
|
||||
{
|
||||
XEvent ev;
|
||||
|
||||
if(!sel)
|
||||
return;
|
||||
|
||||
if((sel->ismax = !sel->ismax))
|
||||
{
|
||||
sel->wasfloating = sel->isfloating;
|
||||
sel->isfloating = True;
|
||||
sel->rx = sel->x;
|
||||
sel->ry = sel->y;
|
||||
sel->rw = sel->w;
|
||||
sel->rh = sel->h;
|
||||
resize(sel, x, y, w, h, True);
|
||||
}
|
||||
else if(sel->isfloating)
|
||||
resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
|
||||
else
|
||||
sel->isfloating = False;
|
||||
|
||||
drawstatus(sel->display, jdwmconf);
|
||||
|
||||
while(XCheckMaskEvent(sel->display, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
void
|
||||
uicb_togglemax(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
maximize(wax, way, waw - 2 * jdwmconf->borderpx, wah - 2 * jdwmconf->borderpx, jdwmconf);
|
||||
}
|
||||
|
||||
void
|
||||
uicb_toggleverticalmax(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
if(sel)
|
||||
maximize(sel->x, way, sel->w, wah - 2 * jdwmconf->borderpx, jdwmconf);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
uicb_togglehorizontalmax(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
if(sel)
|
||||
maximize(wax, sel->y, waw - 2 * jdwmconf->borderpx, sel->h, jdwmconf);
|
||||
}
|
||||
|
||||
void
|
||||
uicb_zoom(Display *disp __attribute__ ((unused)),
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
Client *c;
|
||||
if(!sel || ((c = sel) == nexttiled(clients, jdwmconf->ntags) && !(c = nexttiled(c->next, jdwmconf->ntags))))
|
||||
return;
|
||||
detach(c);
|
||||
attach(c);
|
||||
focus(c->display, &dc, c, jdwmconf);
|
||||
arrange(c->display, jdwmconf);
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_LAYOUT_H
|
||||
#define JDWM_LAYOUT_H
|
||||
|
||||
#include "client.h"
|
||||
|
||||
#define IS_ARRANGE(layout) (layout == jdwmconf->current_layout->arrange)
|
||||
|
||||
void arrange(Display *, jdwm_config *); /* arranges all windows depending on the layout in use */
|
||||
void initlayouts(jdwm_config *); /* initialize layout array */
|
||||
Client *nexttiled(Client *, int); /* returns tiled successor of c */
|
||||
void restack(Display *, jdwm_config *); /* restores z layers of all clients */
|
||||
void uicb_focusnext(Display *, jdwm_config *, const char *); /* focuses next visible client */
|
||||
void uicb_focusprev(Display *, jdwm_config *, const char *); /* focuses prev visible client */
|
||||
void uicb_setlayout(Display *, jdwm_config *, const char *); /* sets layout, NULL means next layout */
|
||||
void uicb_togglebar(Display *, jdwm_config *, const char *); /* shows/hides the bar */
|
||||
void uicb_togglemax(Display *, jdwm_config *, const char *); /* toggles maximization of floating client */
|
||||
void uicb_toggleverticalmax(Display *, jdwm_config *, const char *);
|
||||
void uicb_togglehorizontalmax(Display *, jdwm_config *, const char *);
|
||||
void uicb_zoom(Display *, jdwm_config *, const char *); /* set current window first in stack */
|
||||
void loadjdwmprops(Display *, jdwm_config *);
|
||||
void savejdwmprops(Display *disp, jdwm_config *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include "tag.h"
|
||||
#include "layouts/floating.h"
|
||||
|
||||
/* extern */
|
||||
extern Client *clients; /* global client */
|
||||
|
||||
void
|
||||
floating(Display *disp __attribute__ ((unused)), jdwm_config *jdwmconf)
|
||||
{ /* default floating layout */
|
||||
Client *c;
|
||||
|
||||
for(c = clients; c; c = c->next)
|
||||
if(isvisible(c, jdwmconf->ntags))
|
||||
{
|
||||
if(c->ftview)
|
||||
{
|
||||
resize(c, c->rx, c->ry, c->rw, c->rh, True);
|
||||
c->ftview = False;
|
||||
}
|
||||
else
|
||||
resize(c, c->x, c->y, c->w, c->h, True);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_FLOATING_H
|
||||
#define JDWM_FLOATING_H
|
||||
|
||||
void floating(Display *, jdwm_config *); /* floating layout */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include "grid.h"
|
||||
#include "layout.h"
|
||||
#include "tag.h"
|
||||
|
||||
extern int wah, waw; /* windowarea geometry */
|
||||
extern int bh, bpos; /* bar height, bar position */
|
||||
extern Client *clients; /* global client list and stack */
|
||||
extern DC dc;
|
||||
|
||||
void
|
||||
grid(Display *disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
unsigned int i, n, cx, cy, cw, ch, aw, ah, cols, rows;
|
||||
Client *c;
|
||||
|
||||
for(n = 0, c = nexttiled(clients, jdwmconf->ntags); c; c = nexttiled(c->next, jdwmconf->ntags))
|
||||
n++;
|
||||
|
||||
/* grid dimensions */
|
||||
for(rows = 0; rows <= n / 2; rows++)
|
||||
if(rows * rows >= n)
|
||||
break;
|
||||
cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
|
||||
|
||||
/* window geoms (cell height/width) */
|
||||
ch = wah / (rows ? rows : 1);
|
||||
cw = waw / (cols ? cols : 1);
|
||||
|
||||
for(i = 0, c = clients; c; c = c->next)
|
||||
if(isvisible(c, jdwmconf->ntags))
|
||||
{
|
||||
unban(c);
|
||||
if(c->isfloating)
|
||||
continue;
|
||||
c->ismax = False;
|
||||
cx = (i / rows) * cw;
|
||||
cy = (i % rows) * ch + (bpos == BarTop ? bh : 0); // bh? adjust
|
||||
/* adjust height/width of last row/column's windows */
|
||||
ah = ((i + 1) % rows == 0) ? wah - ch * rows : 0;
|
||||
aw = (i >= rows * (cols - 1)) ? waw - cw * cols : 0;
|
||||
resize(c, cx, cy, cw - 2 * c->border + aw, ch - 2 * c->border + ah, False);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
ban(c);
|
||||
focus(disp, &dc, NULL, jdwmconf);
|
||||
restack(disp, jdwmconf);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_GRID_H
|
||||
#define JDWM_GRID_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* grid.c */
|
||||
void grid(Display *, jdwm_config *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,77 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include "layout.h"
|
||||
#include "tag.h"
|
||||
#include "spiral.h"
|
||||
|
||||
extern int wax, way, wah, waw; /* windowarea geometry */
|
||||
extern Client *clients; /* global client list */
|
||||
extern DC dc;
|
||||
|
||||
static void
|
||||
fibonacci(Display *disp, jdwm_config *jdwmconf, int shape)
|
||||
{
|
||||
int n, nx, ny, nh, nw, i;
|
||||
Client *c;
|
||||
|
||||
nx = wax;
|
||||
ny = 0;
|
||||
nw = waw;
|
||||
nh = wah;
|
||||
for(n = 0, c = nexttiled(clients, jdwmconf->ntags); c; c = nexttiled(c->next, jdwmconf->ntags))
|
||||
n++;
|
||||
for(i = 0, c = clients; c; c = c->next)
|
||||
{
|
||||
c->ismax = False;
|
||||
if((i % 2 && nh / 2 > 2 * c->border)
|
||||
|| (!(i % 2) && nw / 2 > 2 * c->border))
|
||||
{
|
||||
if(i < n - 1)
|
||||
{
|
||||
if(i % 2)
|
||||
nh /= 2;
|
||||
else
|
||||
nw /= 2;
|
||||
if((i % 4) == 2 && !shape)
|
||||
ny += nh;
|
||||
}
|
||||
if((i % 4) == 0)
|
||||
{
|
||||
if(shape)
|
||||
ny += nh;
|
||||
else
|
||||
ny -= nh;
|
||||
}
|
||||
else if((i % 4) == 1)
|
||||
nx += nw;
|
||||
else if((i % 4) == 2)
|
||||
ny += nh;
|
||||
else if((i % 4) == 3)
|
||||
{
|
||||
if(shape)
|
||||
nx += nw;
|
||||
else
|
||||
nx -= nw;
|
||||
}
|
||||
if(i == 0)
|
||||
ny = way;
|
||||
i++;
|
||||
}
|
||||
resize(c, nx, ny, nw - 2 * c->border, nh - 2 * c->border, False);
|
||||
}
|
||||
focus(disp, &dc, NULL, jdwmconf);
|
||||
restack(disp, jdwmconf);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dwindle(Display *disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
fibonacci(disp, jdwmconf, 1);
|
||||
}
|
||||
|
||||
void
|
||||
spiral(Display *disp, jdwm_config *jdwmconf)
|
||||
{
|
||||
fibonacci(disp, jdwmconf, 0);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_SPIRAL_H
|
||||
#define JDWM_SPIRAL_H
|
||||
|
||||
void dwindle(Display *, jdwm_config *); /* dwindle windows */
|
||||
void spiral(Display *, jdwm_config *); /* spiral windows */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,201 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "layout.h"
|
||||
#include "layouts/tile.h"
|
||||
|
||||
/* extern */
|
||||
extern int wax, way, wah, waw; /* windowarea geometry */
|
||||
extern int bh; /* bar height */
|
||||
extern Client *sel, *clients;
|
||||
|
||||
/* static */
|
||||
|
||||
static double mwfact = 0.6;
|
||||
static void _tile(jdwm_config *, const Bool); /* arranges all windows tiled */
|
||||
|
||||
static int nmaster = 2;
|
||||
|
||||
void
|
||||
uicb_incnmaster(Display *disp,
|
||||
jdwm_config *jdwmconf,
|
||||
const char * arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!IS_ARRANGE(tile) && !IS_ARRANGE(tileleft) && !IS_ARRANGE(bstack) && !IS_ARRANGE(bstackportrait))
|
||||
return;
|
||||
if(!arg)
|
||||
nmaster = jdwmconf->nmaster;
|
||||
else
|
||||
{
|
||||
i = strtol(arg, (char **) NULL, 10);
|
||||
if((nmaster + i) < 1 || wah / (nmaster + i) <= 2 * jdwmconf->borderpx)
|
||||
return;
|
||||
nmaster += i;
|
||||
}
|
||||
if(sel)
|
||||
arrange(disp, jdwmconf);
|
||||
else
|
||||
drawstatus(disp, jdwmconf);
|
||||
}
|
||||
|
||||
void
|
||||
uicb_setmwfact(Display *disp,
|
||||
jdwm_config * jdwmconf,
|
||||
const char *arg)
|
||||
{
|
||||
double delta;
|
||||
|
||||
if(!IS_ARRANGE(tile) && !IS_ARRANGE(tileleft) && !IS_ARRANGE(bstack) && !IS_ARRANGE(bstackportrait))
|
||||
return;
|
||||
|
||||
/* arg handling, manipulate mwfact */
|
||||
if(!arg)
|
||||
mwfact = jdwmconf->mwfact;
|
||||
else if(1 == sscanf(arg, "%lf", &delta))
|
||||
{
|
||||
if(arg[0] != '+' && arg[0] != '-')
|
||||
mwfact = delta;
|
||||
else
|
||||
mwfact += delta;
|
||||
if(mwfact < 0.1)
|
||||
mwfact = 0.1;
|
||||
else if(mwfact > 0.9)
|
||||
mwfact = 0.9;
|
||||
}
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
static void
|
||||
_tile(jdwm_config *jdwmconf, const Bool right)
|
||||
{
|
||||
unsigned int nx, ny, nw, nh, mw;
|
||||
int n, th, i, mh;
|
||||
Client *c;
|
||||
|
||||
for(n = 0, c = nexttiled(clients, jdwmconf->ntags); c; c = nexttiled(c->next, jdwmconf->ntags))
|
||||
n++;
|
||||
|
||||
/* window geoms */
|
||||
mh = (n <= nmaster) ? wah / (n > 0 ? n : 1) : wah / nmaster;
|
||||
mw = (n <= nmaster) ? waw : mwfact * waw;
|
||||
th = (n > nmaster) ? wah / (n - nmaster) : 0;
|
||||
if(n > nmaster && th < bh)
|
||||
th = wah;
|
||||
|
||||
nx = wax;
|
||||
ny = way;
|
||||
for(i = 0, c = nexttiled(clients, jdwmconf->ntags); c; c = nexttiled(c->next, jdwmconf->ntags), i++)
|
||||
{
|
||||
c->ismax = False;
|
||||
if(i < nmaster)
|
||||
{ /* master */
|
||||
ny = way + i * mh;
|
||||
if(!right && i == 0)
|
||||
nx += (waw - mw);
|
||||
nw = mw - 2 * c->border;
|
||||
nh = mh;
|
||||
if(i + 1 == (n < nmaster ? n : nmaster)) /* remainder */
|
||||
nh = wah - mh * i;
|
||||
nh -= 2 * c->border;
|
||||
}
|
||||
else
|
||||
{ /* tile window */
|
||||
if(i == nmaster)
|
||||
{
|
||||
ny = way;
|
||||
if(right)
|
||||
nx += mw;
|
||||
else
|
||||
nx = 0;
|
||||
}
|
||||
nw = waw - mw - 2 * c->border;
|
||||
if(i + 1 == n) /* remainder */
|
||||
nh = (way + wah) - ny - 2 * c->border;
|
||||
else
|
||||
nh = th - 2 * c->border;
|
||||
}
|
||||
resize(c, nx, ny, nw, nh, False);
|
||||
if(n > nmaster && th != wah)
|
||||
ny += nh + 2 * c->border;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tile(Display *disp __attribute__ ((unused)), jdwm_config *jdwmconf)
|
||||
{
|
||||
_tile(jdwmconf, True);
|
||||
}
|
||||
|
||||
void
|
||||
tileleft(Display *disp __attribute__ ((unused)), jdwm_config *jdwmconf)
|
||||
{
|
||||
_tile(jdwmconf, False);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_bstack(jdwm_config *jdwmconf, Bool portrait)
|
||||
{
|
||||
int i, n, nx, ny, nw, nh, mw, mh, tw, th;
|
||||
Client *c;
|
||||
|
||||
for(n = 0, c = nexttiled(clients, jdwmconf->ntags); c; c = nexttiled(c->next, jdwmconf->ntags))
|
||||
n++;
|
||||
|
||||
/* window geoms */
|
||||
mh = (n > nmaster) ? (wah * mwfact) / nmaster : wah / (n > 0 ? n : 1);
|
||||
mw = waw;
|
||||
th = (n > nmaster) ? (wah * (1 - mwfact)) / (portrait ? 1 : n - nmaster) : 0;
|
||||
tw = (n > nmaster) ? waw / (portrait ? n - nmaster : 1) : 0;
|
||||
|
||||
for(i = 0, c = nexttiled(clients, jdwmconf->ntags); c; c = nexttiled(c->next, jdwmconf->ntags), i++)
|
||||
{
|
||||
c->ismax = False;
|
||||
nx = wax;
|
||||
ny = way;
|
||||
if(i < nmaster)
|
||||
{
|
||||
ny += i * mh;
|
||||
nw = mw - 2 * c->border;
|
||||
nh = mh - 2 * c->border;
|
||||
}
|
||||
else if(portrait)
|
||||
{
|
||||
nx += (i - nmaster) * tw;
|
||||
ny += mh * nmaster;
|
||||
nw = tw - 2 * c->border;
|
||||
nh = th - 2 * c->border + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ny += mh * nmaster;
|
||||
nw = tw - 2 * c->border;
|
||||
if(th > 2 * c->border)
|
||||
{
|
||||
ny += (i - nmaster) * th;
|
||||
nh = th - 2 * c->border;
|
||||
if (i == n - 1)
|
||||
nh += (n > nmaster) ? wah - mh - th * (n - nmaster) : 0;
|
||||
}
|
||||
else
|
||||
nh = wah - 2 * c->border;
|
||||
}
|
||||
resize(c, nx, ny, nw, nh, False);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bstack(Display *disp __attribute__ ((unused)), jdwm_config *jdwmconf)
|
||||
{
|
||||
_bstack(jdwmconf, False);
|
||||
}
|
||||
|
||||
void
|
||||
bstackportrait(Display *disp __attribute__ ((unused)), jdwm_config *jdwmconf)
|
||||
{
|
||||
_bstack(jdwmconf, True);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_TILE_H
|
||||
#define JDWM_TILE_H
|
||||
|
||||
void uicb_incnmaster(Display *, jdwm_config *, const char *); /* change number of master windows */
|
||||
void uicb_setmwfact(Display *, jdwm_config *, const char *); /* sets master width factor */
|
||||
void tile(Display *, jdwm_config *);
|
||||
void tileleft(Display *, jdwm_config *);
|
||||
void bstack(Display *, jdwm_config *);
|
||||
void bstackportrait(Display *, jdwm_config *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,313 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "layout.h"
|
||||
#include "tag.h"
|
||||
|
||||
extern Client *sel; /* global client list */
|
||||
extern Bool *seltags, *prevtags;
|
||||
extern Layout ** taglayouts;
|
||||
|
||||
static Regs *regs = NULL;
|
||||
static char prop[512];
|
||||
|
||||
/** This function returns the index of
|
||||
* the tag given un argument in *tags
|
||||
* \param tag_to_find tag name
|
||||
* \return index of tag
|
||||
*/
|
||||
static int
|
||||
idxoftag(const char *tag_to_find, const char **tags, int ntags)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!tag_to_find)
|
||||
return 0;
|
||||
|
||||
for(i = 0; i < ntags; i++)
|
||||
if(!strcmp(tags[i], tag_to_find))
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
applyrules(Client * c, jdwm_config *jdwmconf)
|
||||
{
|
||||
int i, j;
|
||||
regmatch_t tmp;
|
||||
Bool matched = False;
|
||||
XClassHint ch = { 0, 0 };
|
||||
|
||||
/* rule matching */
|
||||
XGetClassHint(c->display, c->win, &ch);
|
||||
snprintf(prop, sizeof(prop), "%s:%s:%s",
|
||||
ch.res_class ? ch.res_class : "", ch.res_name ? ch.res_name : "", c->name);
|
||||
for(i = 0; i < jdwmconf->nrules; i++)
|
||||
if(regs[i].propregex && !regexec(regs[i].propregex, prop, 1, &tmp, 0))
|
||||
{
|
||||
c->isfloating = jdwmconf->rules[i].isfloating;
|
||||
for(j = 0; regs[i].tagregex && j < jdwmconf->ntags; j++)
|
||||
if(!regexec(regs[i].tagregex, jdwmconf->tags[j], 1, &tmp, 0))
|
||||
{
|
||||
matched = True;
|
||||
c->tags[j] = True;
|
||||
}
|
||||
}
|
||||
if(ch.res_class)
|
||||
XFree(ch.res_class);
|
||||
if(ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
if(!matched)
|
||||
for(i = 0; i < jdwmconf->ntags; i++)
|
||||
c->tags[i] = seltags[i];
|
||||
}
|
||||
|
||||
void
|
||||
compileregs(jdwm_config * jdwmconf)
|
||||
{
|
||||
int i;
|
||||
regex_t *reg;
|
||||
|
||||
if(regs)
|
||||
return;
|
||||
regs = p_new(Regs, jdwmconf->nrules);
|
||||
for(i = 0; i < jdwmconf->nrules; i++)
|
||||
{
|
||||
if(jdwmconf->rules[i].prop)
|
||||
{
|
||||
reg = p_new(regex_t, 1);
|
||||
if(regcomp(reg, jdwmconf->rules[i].prop, REG_EXTENDED))
|
||||
p_delete(®);
|
||||
else
|
||||
regs[i].propregex = reg;
|
||||
}
|
||||
if(jdwmconf->rules[i].tags)
|
||||
{
|
||||
reg = p_new(regex_t, 1);
|
||||
if(regcomp(reg, jdwmconf->rules[i].tags, REG_EXTENDED))
|
||||
p_delete(®);
|
||||
else
|
||||
regs[i].tagregex = reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Returns True if a client is visible on
|
||||
* one of the currently selected tag, false otherwise.
|
||||
* \param c Client
|
||||
* \return True or False
|
||||
*/
|
||||
Bool
|
||||
isvisible(Client * c, int ntags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < ntags; i++)
|
||||
if(c->tags[i] && seltags[i])
|
||||
return True;
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
/** Tag selected window with tag
|
||||
* \param disp Display ref
|
||||
* \param arg Tag name
|
||||
* \ingroup ui_callback
|
||||
*/
|
||||
void
|
||||
uicb_tag(Display *disp, jdwm_config *jdwmconf, const char *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!sel)
|
||||
return;
|
||||
for(i = 0; i < jdwmconf->ntags; i++)
|
||||
sel->tags[i] = arg == NULL;
|
||||
i = idxoftag(arg, jdwmconf->tags, jdwmconf->ntags);
|
||||
if(i >= 0 && i < jdwmconf->ntags)
|
||||
sel->tags[i] = True;
|
||||
saveprops(sel, jdwmconf->ntags);
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
/** Toggle floating state of a client
|
||||
* \param disp Display ref
|
||||
* \param arg unused
|
||||
* \ingroup ui_callback
|
||||
*/
|
||||
void
|
||||
uicb_togglefloating(Display *disp,
|
||||
jdwm_config * jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
if(!sel)
|
||||
return;
|
||||
sel->isfloating = !sel->isfloating;
|
||||
if(sel->isfloating)
|
||||
/*restore last known float dimensions*/
|
||||
resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
|
||||
else
|
||||
{
|
||||
/*save last known float dimensions*/
|
||||
sel->rx = sel->x;
|
||||
sel->ry = sel->y;
|
||||
sel->rw = sel->w;
|
||||
sel->rh = sel->h;
|
||||
}
|
||||
saveprops(sel, jdwmconf->ntags);
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
/** Toggle tag view
|
||||
* \param disp Display ref
|
||||
* \param arg Tag name
|
||||
* \ingroup ui_callback
|
||||
*/
|
||||
void
|
||||
uicb_toggletag(Display *disp,
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg)
|
||||
{
|
||||
unsigned int i;
|
||||
int j;
|
||||
|
||||
if(!sel)
|
||||
return;
|
||||
i = idxoftag(arg, jdwmconf->tags, jdwmconf->ntags);
|
||||
sel->tags[i] = !sel->tags[i];
|
||||
for(j = 0; j < jdwmconf->ntags && !sel->tags[j]; j++);
|
||||
if(j == jdwmconf->ntags)
|
||||
sel->tags[i] = True;
|
||||
saveprops(sel, jdwmconf->ntags);
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
/** Add a tag to viewed tags
|
||||
* \param disp Display ref
|
||||
* \param arg Tag name
|
||||
* \ingroup ui_callback
|
||||
*/
|
||||
void
|
||||
uicb_toggleview(Display *disp,
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg)
|
||||
{
|
||||
unsigned int i;
|
||||
int j;
|
||||
|
||||
i = idxoftag(arg, jdwmconf->tags, jdwmconf->ntags);
|
||||
seltags[i] = !seltags[i];
|
||||
for(j = 0; j < jdwmconf->ntags && !seltags[j]; j++);
|
||||
if(j == jdwmconf->ntags)
|
||||
seltags[i] = True; /* cannot toggle last view */
|
||||
savejdwmprops(disp, jdwmconf);
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param disp Display ref
|
||||
* \param arg
|
||||
* \ingroup ui_callback
|
||||
*/
|
||||
void
|
||||
uicb_view(Display *disp,
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < jdwmconf->ntags; i++)
|
||||
{
|
||||
prevtags[i] = seltags[i];
|
||||
seltags[i] = arg == NULL;
|
||||
}
|
||||
i = idxoftag(arg, jdwmconf->tags, jdwmconf->ntags);
|
||||
if(i >= 0 && i < jdwmconf->ntags)
|
||||
{
|
||||
seltags[i] = True;
|
||||
jdwmconf->current_layout = taglayouts[i];
|
||||
}
|
||||
savejdwmprops(disp, jdwmconf);
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
/** View previously selected tags
|
||||
* \param disp Display ref
|
||||
* \param arg unused
|
||||
* \ingroup ui_callback
|
||||
*/
|
||||
void
|
||||
uicb_viewprevtags(Display * disp,
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
int i;
|
||||
Bool t;
|
||||
|
||||
for(i = 0; i < jdwmconf->ntags; i++)
|
||||
{
|
||||
t = seltags[i];
|
||||
seltags[i] = prevtags[i];
|
||||
prevtags[i] = t;
|
||||
}
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
/** View next tag
|
||||
* \param disp Display ref
|
||||
* \param arg unused
|
||||
* \ingroup ui_callback
|
||||
*/
|
||||
void
|
||||
uicb_tag_viewnext(Display *disp,
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
int i;
|
||||
int firsttag = -1;
|
||||
|
||||
for(i = 0; i < jdwmconf->ntags; i++)
|
||||
{
|
||||
if(firsttag < 0 && seltags[i])
|
||||
firsttag = i;
|
||||
seltags[i] = False;
|
||||
}
|
||||
if(++firsttag >= jdwmconf->ntags)
|
||||
firsttag = 0;
|
||||
seltags[firsttag] = True;
|
||||
savejdwmprops(disp, jdwmconf);
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
||||
|
||||
/** View previous tag
|
||||
* \param disp Display ref
|
||||
* \param arg unused
|
||||
* \ingroup ui_callback
|
||||
*/
|
||||
void
|
||||
uicb_tag_viewprev(Display *disp,
|
||||
jdwm_config *jdwmconf,
|
||||
const char *arg __attribute__ ((unused)))
|
||||
{
|
||||
int i;
|
||||
int firsttag = -1;
|
||||
|
||||
for(i = jdwmconf->ntags - 1; i >= 0; i--)
|
||||
{
|
||||
if(firsttag < 0 && seltags[i])
|
||||
firsttag = i;
|
||||
seltags[i] = False;
|
||||
}
|
||||
if(--firsttag < 0)
|
||||
firsttag = jdwmconf->ntags - 1;
|
||||
seltags[firsttag] = True;
|
||||
savejdwmprops(disp, jdwmconf);
|
||||
arrange(disp, jdwmconf);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_TAG_H
|
||||
#define JDWM_TAG_H
|
||||
|
||||
#include <regex.h>
|
||||
#include "client.h"
|
||||
|
||||
void compileregs(jdwm_config *); /* initialize regexps of rules defined in config.h */
|
||||
Bool isvisible(Client *, int); /* returns True if client is visible */
|
||||
void applyrules(Client * c, jdwm_config *); /* applies rules to c */
|
||||
void uicb_tag(Display *, jdwm_config *, const char *); /* tags sel with arg's index */
|
||||
void uicb_togglefloating(Display *, jdwm_config *, const char *); /* toggles sel between floating/tiled state */
|
||||
void uicb_toggletag(Display *, jdwm_config *, const char *); /* toggles sel tags with arg's index */
|
||||
void uicb_toggleview(Display *, jdwm_config *, const char *); /* toggles the tag with arg's index (in)visible */
|
||||
void uicb_view(Display *, jdwm_config *, const char *); /* views the tag with arg's index */
|
||||
void uicb_viewprevtags(Display *, jdwm_config *, const char *);
|
||||
void uicb_tag_viewnext(Display *, jdwm_config *, const char *); /* view only tag just after the first selected */
|
||||
void uicb_tag_viewprev(Display *, jdwm_config *, const char *); /* view only tag just before the first selected */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
regex_t *propregex;
|
||||
regex_t *tagregex;
|
||||
} Regs;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
void
|
||||
eprint(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void
|
||||
spawn(Display * disp,
|
||||
jdwm_config * jdwmconf __attribute__ ((unused)),
|
||||
const char *arg)
|
||||
{
|
||||
static char *shell = NULL;
|
||||
|
||||
if(!shell && !(shell = getenv("SHELL")))
|
||||
shell = strdup("/bin/sh");
|
||||
if(!arg)
|
||||
return;
|
||||
/* The double-fork construct avoids zombie processes and keeps the code
|
||||
* * clean from stupid signal handlers. */
|
||||
if(fork() == 0)
|
||||
{
|
||||
if(fork() == 0)
|
||||
{
|
||||
if(disp)
|
||||
close(ConnectionNumber(disp));
|
||||
setsid();
|
||||
execl(shell, shell, "-c", arg, (char *) NULL);
|
||||
fprintf(stderr, "jdwm: execl '%s -c %s'", shell, arg);
|
||||
perror(" failed");
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
wait(0);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef JDWM_MEM_H
|
||||
#define JDWM_MEM_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define ssizeof(foo) (ssize_t)sizeof(foo)
|
||||
#define countof(foo) (ssizeof(foo) / ssizeof(foo[0]))
|
||||
|
||||
#define p_new(type, count) ((type *)xmalloc(sizeof(type) * (count)))
|
||||
#define p_clear(p, count) ((void)memset((p), 0, sizeof(*(p)) * (count)))
|
||||
#define p_realloc(pp, count) xrealloc((void*)(pp) sizeof(**(pp) * (count)))
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#define p_delete(mem_pp) \
|
||||
do { \
|
||||
typeof(**(mem_pp)) **__ptr = (mem_pp); \
|
||||
free(*__ptr); \
|
||||
*__ptr = NULL; \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
|
||||
#define p_delete(mem_p) \
|
||||
do { \
|
||||
void *__ptr = (mem_p); \
|
||||
free(*__ptr); \
|
||||
*(void **)__ptr = NULL; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
static inline void * __attribute__ ((malloc)) xmalloc(ssize_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if(size <= 0)
|
||||
return NULL;
|
||||
|
||||
ptr = calloc(1, size);
|
||||
|
||||
if(!ptr)
|
||||
abort();
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xrealloc(void **ptr, ssize_t newsize)
|
||||
{
|
||||
if(newsize <= 0)
|
||||
p_delete(ptr);
|
||||
else
|
||||
{
|
||||
*ptr = realloc(*ptr, newsize);
|
||||
if(!*ptr)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void eprint(const char *, ...) __attribute__ ((noreturn)) __attribute__ ((format(printf, 1, 2)));
|
||||
void spawn(Display *, jdwm_config *, const char *);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue