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