You are not logged in.
Offline
dwm <3
Only some small changes in status bar since last month. Menu is mygtkmenu.
Clean
Busy
Right-click menu
Last edited by OK100 (2011-05-01 17:45:15)
Offline
dwm <3
Only some small changes in status bar since last month. Menu is mygtkmenu.
Clean
Busy
Right-click menu
Like it
I'm trying to get the hang of dwm. Still trying to figure what to do with the systray patch
Offline
Giving an amateurish shot at making a tiling window manager.
I center the window manager around “items." Items can both be windows and containers of other items.
It actually look just like the wm i am looking for , do you have a link to it source ?
Offline
Nichollan wrote:Giving an amateurish shot at making a tiling window manager.
I center the window manager around “items." Items can both be windows and containers of other items.
It actually look just like the wm i am looking for , do you have a link to it source ?
It really isn’t usable. Currently it is difficult/impossible to know what item is selected, and you can’t move items anywhere – only allocate them in the nearest container or delete them. I copy a lot of dwm’s source code while omitting things that I don’t understand or care much about for now. I have resorted to using goto for tree recursion.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#define BARWIDTH 3
/* item attributes */
#define ADOPTIVE 1
/* Whether the item takes child items */
enum type { none, window, container };
typedef struct Item Item;
struct Item {
enum type type; // container, window
void *typedata;
int x, y;
unsigned w, h;
Item *parent; /* NULL if top */
int attributes;
Item *next;
};
typedef struct Framepart Framepart;
struct Framepart {
Window window;
Framepart *next;
GC gc;
};
typedef struct Arranger Arranger;
struct Arranger {
void (*arrange)(Item *);
void (*interact)(Item *, XEvent *);
Framepart *parts;
void *data;
};
typedef struct Container Container;
struct Container {
Arranger arranger;
Item *children;
};
typedef struct Key Key;
struct Key {
unsigned int mod;
KeySym keysym;
void (*func)(const void *);
void *arg;
};
/* prototypes */
static int addchild(Item *parent, Item *child);
static void maprequest(XEvent *e);
static void mappingnotify(XEvent *e);
//static void setframecolor(Item *item, const char *colstr);
static void enternotify(XEvent *e);
static void selectitem(Item *item, Bool destroyed);
static void destroynotify(XEvent *e);
static void keypress(XEvent *e);
static void setup(void);
static void removeitem(Item *item, Bool destroyed);
static void grabkeys(void);
static Item *locatewindow(Window w, Item *from);
static void scan(void);
static void placeitem(Item *item, int x, int y, int w, int h);
static void manage(Window w);
static void killitem(const void *arg);
static void spawn(const void *arg);
static void traverse(const void *arg);
static void applyarranger(const void *arg);
static void verticaltile(Item *item);
static void horizontaltile(Item *item);
static Container *getcon(Item *item);
static Item *seekadoptive(Item *item, int up);
static void newcon(Item *item, Arranger *arranger, void *arrangedata);
static void tocontainer(Item *item, Arranger *arranger, void *arrangedata);
static Window createframepart(void);
static void adjustpartnumber(Item *item, int num);
static int haschildren(Item *item);
static void printitemtree(const void *arg);
static XColor selcol;
static Display *dpy;
static int screen;
static Window root;
static Item *top; /* Item on top of the hierarchy */
static Item *sel; /* Selected item */
static Item *pri; /* Prioritized item for adoption */
static int sw, sh;
static void (*handler[LASTEvent]) (XEvent *) = {
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[KeyPress] = keypress,
[MapRequest] = maprequest,
[MappingNotify] = mappingnotify
};
static Arranger vertical
= { verticaltile, NULL, NULL, NULL };
static Arranger horizontal
= { horizontaltile, NULL, NULL, NULL };
static const char *termcmd[] = { "xterm", NULL };
static Key keys[] = {
{ Mod1Mask, XK_c, killitem, NULL },
{ Mod1Mask, XK_o, spawn, termcmd },
{ Mod1Mask, XK_Tab, traverse, NULL },
{ Mod1Mask, XK_n, applyarranger, &vertical },
{ Mod1Mask, XK_t, applyarranger, &horizontal },
{ Mod1Mask, XK_g, printitemtree, NULL }
};
void mappingnotify(XEvent *e)
{
XRefreshKeyboardMapping(&e->xmapping);
if(e->xmapping.request == MappingKeyboard)
grabkeys();
}
void killitem(const void *arg)
{
puts("Killing item");
if(arg)
removeitem((Item *)arg, False);
else
removeitem(sel, False);
}
void enternotify(XEvent *e)
{
puts("Enternotify");
Item *item = locatewindow(e->xcrossing.window, top);
if(item)
selectitem(item, False);
}
void selectitem(Item *item, Bool destroyed)
{
if(item->type == window)
printf("Selecting window %d\n", *(int *)item->typedata);
else
puts("Selecting a non-window item");
Container *con;
if(!destroyed) {
Item *previous = sel;
if((con = getcon(previous == top ? top : previous->parent))) {
con->arranger.arrange(previous);
}
}
sel = item;
if((con = getcon(sel == top ? top : sel->parent))) {
con->arranger.arrange(sel == top ? top : sel->parent);
}
}
void verticaltile(Item *it)
{
puts("tiling vertically");
int i;
int childnum;
Container *con = getcon(it);
Item *item;
if(con == NULL)
return;
for(childnum = 0, item = con->children;
item != NULL;
childnum++, item = item->next);
adjustpartnumber(it, childnum - 1);
Framepart *part = con->arranger.parts;
for(i = 0, item = con->children; i < childnum; i++, item = item->next) {
placeitem(item,
it->x + it->w / childnum * i,
it->y,
it->w / childnum - BARWIDTH,
it->h);
if(part) {
XMoveResizeWindow(dpy, part->window,
it->x + (it->w / childnum) * (i + 1) - BARWIDTH,
it->y,
BARWIDTH,
it->h);
XClearWindow(dpy, part->window);
if(item == sel || item->next == sel) {
puts("*** shmix ***");
XFillRectangle(dpy, part->window, part->gc,
1,
0,
1,
it->h);
}
part = part->next;
}
}
}
void horizontaltile(Item *it)
{
puts("tiling horizontally");
int i;
int childnum;
Container *con = getcon(it);
Item *item;
if(con == NULL)
return;
for(childnum = 0, item = con->children;
item != NULL;
childnum++, item = item->next);
adjustpartnumber(it, childnum - 1);
Framepart *part = con->arranger.parts;
for(i = 0, item = con->children;
i < childnum; i++, item = item->next) {
placeitem(item,
it->x,
it->y + it->h / childnum * i,
it->w,
it->h / childnum - BARWIDTH);
if(part) {
XMoveResizeWindow(dpy, part->window,
it->x,
it->y + (it->h / childnum) * (i + 1) - BARWIDTH,
it->w,
BARWIDTH);
XClearWindow(dpy, part->window);
if(item == sel || item->next == sel) {
XFillRectangle(dpy, part->window, part->gc,
0,
1,
it->w,
1);
}
part = part->next;
}
}
}
void adjustpartnumber(Item *item, int num)
{
unsigned partnum;
XGCValues gcv;
Framepart *part, *newpart;
Framepart **partp;
Container *con = getcon(item);
if(num < 0) {
num = 0;
}
if(con->arranger.parts == NULL)
partnum = 0;
else {
for(partnum = 0, part = con->arranger.parts;
part != NULL;
partnum++, part = part->next);
}
if(partnum == num)
return;
/* Get pointer to pointer of last item on list. Either
* the one to be removed or the one to be created. */
partp = &con->arranger.parts;
while(partnum > num ?
(*partp)->next : *partp) {
partp = &(*partp)->next;
}
if(partnum > num) {
while(partnum > num) {
/* Removing last item of list */
XFreeGC(dpy, (*partp)->gc);
XDestroyWindow(dpy, (*partp)->window);
free(*partp);
*partp = NULL;
partnum--;
}
} else if(partnum < num) {
gcv.foreground = selcol.pixel;
while(partnum < num) {
newpart = malloc(sizeof(Framepart));
*partp = newpart;
newpart->window = createframepart();
newpart->gc = XCreateGC(dpy, newpart->window, GCForeground, &gcv);
newpart->next = NULL;
partnum++;
}
}
}
Window createframepart()
{
XSetWindowAttributes wa;
wa.event_mask = ButtonPressMask|ExposureMask;
wa.background_pixel = WhitePixel(dpy, screen);
Window w = XCreateWindow(dpy, root,
0, 0, 1, 1, 0,
DefaultDepth(dpy, screen),
InputOutput,
DefaultVisual(dpy, screen),
CWEventMask|CWBackPixel, &wa);
XGrabServer(dpy);
XMapWindow(dpy, w);
XUngrabServer(dpy);
return w;
}
static void manage(Window w)
{
puts("Managing a window");
XSelectInput(dpy, w, EnterWindowMask
|FocusChangeMask
|PropertyChangeMask
|StructureNotifyMask);
Item *item = malloc(sizeof(Item));
item->type = window;
item->typedata = malloc(sizeof(Window));
item->next = NULL;
// createframe(item);
*(Window *)(item->typedata) = w;
item->attributes = 0;
addchild(seekadoptive(sel, 0), item);
}
int setarranger(Item *item, Arranger *arranger, void *data)
{
puts("Setting arranger");
Container *con;
if(item->type == window) {
tocontainer(item, arranger, data);
con = getcon(item);
} else if((con = getcon(item))) {
adjustpartnumber(item, 0);
con->arranger = *arranger;
if(data)
con->arranger.data = data;
}
con->arranger.arrange(item);
return 0;
}
void tocontainer(Item *item, Arranger *arranger, void *arrangedata)
{
if(item->type != window)
return;
Container *con;
Item *windowitem = malloc(sizeof(Item));
windowitem->parent = item;
windowitem->next = NULL;
windowitem->attributes = 0;
windowitem->typedata = item->typedata;
windowitem->type = window;
//createframe(windowitem);
//newcon(item, arranger, arrangedata);
item->typedata = malloc(sizeof(Container));
con = (Container *)(item->typedata);
con->arranger = *arranger;
item->type = container;
item->attributes |= ADOPTIVE;
con->children = windowitem;
}
void newcon(Item *item, Arranger *arranger, void *arrangedata)
{
puts("setting up a new container");
item->typedata = malloc(sizeof(Container));
((Container *)(item->typedata))->arranger = *arranger;
item->type = container;
item->attributes |= ADOPTIVE;
if(arrangedata) {
((Container *)(item->typedata))->arranger.data = arrangedata;
}
((Container *)(item->typedata))->children = NULL;
}
Container *getcon(Item *item)
{
if(!item)
return NULL;
if(item->type != container) {
return NULL;
}
return (Container *)(item->typedata);
}
int addchild(Item *parent, Item *child)
{
puts("adding child");
Container *con;
if((con = getcon(parent)) == NULL)
return 1;
child->next = con->children;
con->children = child;
child->parent = parent;
con->arranger.arrange(parent);
return 0;
}
Item *seekadoptive(Item *from, int up)
{
puts("Seeking adoptive");
Item *citem;
Container *con;
if((from->attributes & ADOPTIVE) || (from == top)) {
puts("this is true");
return from;
}
con = getcon(from);
if(con) {
for(citem = con->children; citem != NULL; citem = citem->next) {
return seekadoptive(citem, 0);
}
}
if(up || ((from->type == window) && !up)) {
puts("Huzzah!");
return seekadoptive(from->parent, 1);
}
return NULL;
}
void placeitem(Item *item, int x, int y, int w, int h)
{
puts("placing item");
Container *con;
item->x = x;
item->y = y;
item->w = w;
item->h = h;
// adjustframe(item);
switch(item->type) {
case window:
XMoveResizeWindow(dpy, *(Window *)(item->typedata), x, y, w, h);
break;
case container:
con = (Container *)item->typedata;
con->arranger.arrange(item);
break;
default:
break;
}
}
void maprequest(XEvent *e)
{
puts("Maprequest");
Window w = e->xmaprequest.window;
static XWindowAttributes wa;
if(!XGetWindowAttributes(dpy, w, &wa))
return;
if(wa.override_redirect)
return;
XSelectInput(dpy, w, EnterWindowMask
|FocusChangeMask
|PropertyChangeMask
|StructureNotifyMask);
manage(w);
XMapWindow(dpy, w);
}
void destroynotify(XEvent *e)
{
puts("Destroynotify");
Window w = e->xdestroywindow.window;
Item *item = locatewindow(w, top);
if(item != NULL) {
removeitem(item, True);
}
}
void removeitem(Item *item, Bool destroyed)
{
puts("removing item");
Item *citem;
Item *parent;
Container *con;
if(item == top) {
puts("Can't remove top item");
return;
}
if(item->type == container) {
con = getcon(item);
for(citem = con->children; citem; citem = citem->next) {
removeitem(citem, destroyed);
}
free(con->arranger.data);
} else if(item->type == window && !destroyed) {
XGrabServer(dpy);
XSetCloseDownMode(dpy, DestroyAll);
XKillClient(dpy, *(Window *)(item->typedata));
XSync(dpy, False);
XUngrabServer(dpy);
}
/*
XDestroyWindow(dpy, item->frame.top);
XDestroyWindow(dpy, item->frame.right);
XDestroyWindow(dpy, item->frame.bottom);
XDestroyWindow(dpy, item->frame.left);
*/
parent = item->parent;
con = getcon(parent);
Item **tc;
for(tc = &con->children; *tc && *tc != item; tc = &(*tc)->next);
*tc = item->next;
free(item->typedata);
free(item);
if(item == sel)
selectitem(top, True);
}
Item *locatewindow(Window w, Item *from)
{
puts("locating window");
Item *item = NULL;
Item *citem = NULL;
Container *con;
if(from->type == window) {
if(*(Window *)(from->typedata) == w) {
return from;
} else {
return NULL;
}
} else {
if((con = getcon(from)) == NULL)
return NULL;
for(citem = con->children; citem != NULL && item == NULL; citem = citem->next) {
item = locatewindow(w, citem);
}
}
return item;
}
void keypress(XEvent *e) {
puts("Keypress");
XKeyEvent *ev;
ev = &e->xkey;
KeySym keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
printf("this = %hu\n", e->xkey.keycode);
int i;
for(i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
if(keysym == keys[i].keysym) {
keys[i].func(keys[i].arg);
}
}
}
void setup(void) {
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen);
/* (updategeom) */
XSetWindowAttributes wa;
wa.event_mask = SubstructureRedirectMask
|SubstructureNotifyMask
|ButtonPressMask
|EnterWindowMask
|LeaveWindowMask
|StructureNotifyMask
|PropertyChangeMask;
XChangeWindowAttributes(dpy, root, CWEventMask, &wa);
XSelectInput(dpy, root, wa.event_mask);
top = malloc(sizeof(Item));
top->parent = NULL;
top->attributes = 0;
top->next = NULL;
//createframe(top);
newcon(top, &vertical, NULL);
placeitem(top, 0, 0, sw, sh);
sel = top;
pri = top;
grabkeys();
Colormap cmap = DefaultColormap(dpy, screen);
XAllocNamedColor(dpy, cmap, "#0000FF", &selcol, &selcol);
}
unsigned getnumlockmask(void)
{
unsigned int i, j;
XModifierKeymap *modmap;
unsigned numlockmask = 0;
modmap = XGetModifierMapping(dpy);
for(i = 0; i < 8; i++)
for(j = 0; j < modmap->max_keypermod; j++)
if(modmap->modifiermap[i * modmap->max_keypermod + j]
== XKeysymToKeycode(dpy, XK_Num_Lock))
numlockmask = (1 << i);
XFreeModifiermap(modmap);
return numlockmask;
}
void grabkeys(void)
{
unsigned i, j;
KeyCode code;
unsigned numlockmask = getnumlockmask();
unsigned modifiers[]
= { 0, LockMask, numlockmask, numlockmask | LockMask };
XUngrabKey(dpy, AnyKey, AnyModifier, root);
for(i = 0; i < sizeof(keys) / sizeof(Key); i++) {
if((code = XKeysymToKeycode(dpy, keys[i].keysym))) {
printf("grabbing keycode %hu\n", code);
for(j = 0; j < sizeof(modifiers) / sizeof(modifiers[0]); j++) {
XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
True, GrabModeAsync, GrabModeAsync);
}
}
}
}
void scan(void) {
/* use XQueryTree to discover existing windows */
}
void dummyhandler(XEvent *e)
{
switch(e->type) {
case ButtonPress:
puts("ButtonPress");
break;
case ConfigureRequest:
puts("ConfigureRequest");
break;
case ConfigureNotify:
puts("ConfigureNotify");
break;
case DestroyNotify:
puts("DestroyNotify");
break;
case EnterNotify:
puts("EnterNotify");
break;
case Expose:
puts("Expose");
break;
case FocusIn:
puts("FocusIn");
break;
case KeyPress:
puts("KeyPress");
break;
case MappingNotify:
puts("MappingNotify");
break;
case MapRequest:
puts("MapRequest");
break;
case PropertyNotify:
puts("PropertyNotify");
break;
case UnmapNotify:
puts("UnmapNotify");
break;
default:
break;
}
}
void run(void)
{
XEvent ev;
XSync(dpy, False);
while(!XNextEvent(dpy, &ev)) {
if(handler[ev.type])
handler[ev.type](&ev);
else
dummyhandler(&ev);
}
}
/* things I have skipped for now
* - Scanning existing windows
* - Xinerama
* - Whatever concern dwm has for how numlock
* affects modifier masks
* - EWMH, atoms, cursor and appearance
*/
void spawn(const void *arg)
{
puts("spawning");
if(fork() == 0) {
if(dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(((char **)arg)[0], (char **)arg);
fprintf(stderr, "dwm: execvp %s", ((char **)arg)[0]);
perror(" failed");
exit(0);
}
}
/* This procedure uses goto for its recursion requirements */
void traverse(const void *arg)
{
Item *item = sel;
Container *con;
puts("Traversing");
if(item->type == container) {
con = getcon(item);
if(con->children) {
selectitem(con->children, False);
} else {
goto nextitem;
}
} else {
nextitem:
if(item->next) {
selectitem(item->next, False);
} else {
if(item == top)
return;
if(item->parent == top) {
selectitem(top, False);
} else {
item = item->parent;
goto nextitem;
}
}
}
}
void applyarranger(const void *arg)
{
puts("applying arranger");
setarranger(sel, (Arranger *)arg, NULL);
}
void printitemtree(const void *arg)
{
Item *citem = top;
int depth = 0;
char *indentation = malloc(sizeof(char) * 26);
print:
memset(indentation, ' ', depth * 2);
indentation[depth * 2] = '\0';
printf("%s%p\n", indentation, citem);
if(haschildren(citem)) {
citem = getcon(citem)->children;
depth++;
goto print;
}
nextitem:
if(citem->next)
citem = citem->next;
else if(citem->parent == top) {
free(indentation);
return;
} else {
citem = citem->parent;
depth--;
goto nextitem;
}
goto print;
}
int haschildren(Item *item) {
Container *con = getcon(item);
if(con)
if(con->children)
return 1;
return 0;
}
int main(int argc, char* argv[])
{
if(!(dpy = XOpenDisplay(NULL))) {
fprintf(stderr, "Failed to connect to the X server.\n");
}
setup();
scan();
run();
return 0;
}
If you save it as wman.c, you should be able to compile it with
gcc -o wman -lX11 wman.c
The current key bindings are
Alt+O
Start xterm
Alt+Tab
Select next item. I don’t think this gives focus to a window at the moment.
Alt+N
Apply vertical tiling to the children of the current item, or create a new container with the selected window as its child item.
Alt+T
Apply horizontal tiling.
Offline
I'm trying to get the hang of dwm. Still trying to figure what to do with the systray patch
i have an idea: do nothing. you'll get used.
Arch64/DWM || My Dropbox referral link
Offline
Meh, I'm feeling too lazy to resize it.
I suppose I should have been using alsi instead of installing something with yaourt, so sorry.
Last edited by Austin25 (2011-05-01 20:37:50)
Huh, that actually worked. Neat-o.
Offline
Openbox + pytyle <3
I absolutely love that colour scheme. Mind sharing your ~/.Xresources, or whatever you used to set it? :>
Arch 64 + xmonad.
hey nice wallpaper ;)
don't save us from the flames
Offline
Offline
Offline
Offline
nice shot for a console screenshot, btw what font is that?
Offline
Giving an amateurish shot at making a tiling window manager.[
I center the window manager around “items." Items can both be windows and containers of other items.
Sounds like once you get it to a usable state it could be really neat! Containers sounds like a recursiv wm (the real Plan9 Rio comes to mind).
I'm using Rio from Plan9Port (copied /opt/plan9/bin/rio to /usr/bin/rio and -R'd plan9port) and some dzens for useful info (sysload, bitrates, and dropbox status). Nitrogen sets the walpaper, which is a newer work from redjuice999. Xcompmgr for some shadows.
http://i.imgur.com/IWInD.jpg
roxterm (cause urxvt doesn't play well with rio anymore and aterm doesn't like utf8)
irssi
ff4+pentadactyl
mplayer
nano
alpine
Last edited by dwindle (2011-05-02 15:20:57)
[nil]
[exists]
Offline
Are you using dzen2 to put images in to your bar?
Offline
unfortunately yes, but you can take a look at -sprinkless source if you don't want to use dzen.
Arch64/DWM || My Dropbox referral link
Offline