You are not logged in.

#176 2010-12-24 21:39:43

markbabc
Member
Registered: 2010-11-06
Posts: 157

Re: The dwm thread

inch wrote:

Hi! Just started with my first arch experience and tried to get into dwm - and already hit the first barrier. I installed dwm via the wiki and everything went fine, edited the xinitrc (contains the sh header and exec dwm). dwm starts and everything is fine until I want to do something (like opening a terminal), ALT + Shift + Enter doesn't open anything, ALT + Shift + Q doesn't exit dwm and so on. (config.h wasn't changed by me)

No keybinds work at all, what am I doing wrong?

Can you move your mouse?
try re-installing xf86-input-<whatever yours is>

Offline

#177 2010-12-24 22:10:12

inch
Member
Registered: 2010-12-21
Posts: 49

Re: The dwm thread

The touchpad works and the keyboard too (without X).

edit: will make a new thread - thanks for the input!

Last edited by inch (2010-12-25 01:44:16)

Offline

#178 2010-12-24 22:58:51

markbabc
Member
Registered: 2010-11-06
Posts: 157

Re: The dwm thread

inch wrote:

The touchpad works and the keyboard too (without X).

still re-install it. I had the same problem when going into x i couldn't use my touchpad or keyboard
you will need

pacman -S xf86-input-synaptics

and maybe xf86-input-keyboard and xf86-input-mouse

Offline

#179 2010-12-25 03:34:10

steve___
Member
Registered: 2008-02-24
Posts: 452

Re: The dwm thread

Does alt-p bring up dmenu?  Do you have xterm installed?


**edit: as noted below, dmenu is run with alt-p not alt-z

Last edited by steve___ (2010-12-25 04:01:17)

Offline

#180 2010-12-25 03:57:01

markbabc
Member
Registered: 2010-11-06
Posts: 157

Re: The dwm thread

steve___ wrote:

Does alt-z bring up dmenu?  Do you have xterm installed?

alt-z? isnt it alt-p?

Offline

#181 2010-12-25 04:00:07

steve___
Member
Registered: 2008-02-24
Posts: 452

Re: The dwm thread

err yeah I was just about to update that mistake.  Sorry about that -- too much turkey :-/

Offline

#182 2010-12-25 04:03:46

c00kiemon5ter
Member
From: Greece
Registered: 2010-06-01
Posts: 562
Website

Re: The dwm thread

markbabc wrote:
steve___ wrote:

Does alt-z bring up dmenu?  Do you have xterm installed?

alt-z? isnt it alt-p?

yes, alt+p, does it work ?
if it does then Alt+<num> should also work and change tags

if so the problem is probably Alt+Shift is already reserved for something else like switching kbd layouts.
If so either change your MODKEY to something different than Alt(Mod1Mask) say the windows key(Mod4Mask)
or disable that rule so that you can use Alt+Shift.


.:[ git me! ] :.

Offline

#183 2010-12-25 04:22:34

steve___
Member
Registered: 2008-02-24
Posts: 452

Re: The dwm thread

If none of hat prove fruitful, here is my xorg.conf:

Section "ServerFlags"
    Option      "AutoAddDevices"        "false"
    Option      "AllowMouseOpenFail"    "true"
EndSection

Section "Files"
    FontPath     "/usr/share/fonts/local"
EndSection

I had problems with my keyboard and/or mouse working a year or so ago and this was the fix.  I've never bothered to remove the settings and test with the newer versions of xorg.

Offline

#184 2011-01-12 20:52:07

cabrey
Member
Registered: 2009-08-15
Posts: 29

Re: The dwm thread

I'm trying to configure my media keys (Vol up/down/mute, MPD play/pause/next/prev) and to that I'm just making DWM spawn a small script everytime one of the buttons is pressed. The keys are setup fine and everything, but no matter what I put in the script, DWM always gives me an error:

dwm: execvp mpc next failed: No such file or directory

Anybody know what this means?

Offline

#185 2011-01-12 21:05:29

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 30,424
Website

Re: The dwm thread

Moved to the DWM thread - the other thread is for hacks.

You'll need to post the relevant part of your config.h and script to help nail it down...


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#186 2011-01-12 21:11:18

c00kiemon5ter
Member
From: Greece
Registered: 2010-06-01
Posts: 562
Website

Re: The dwm thread

Here is how I do it. Eg for mpc next:

/* commands */
static const char *mnext[]     = { "mpc", "next", NULL };
....

static Key keys[] = {
    { MODKEY,                       XK_equal,  spawn,          {.v = mnext } },
    ....
}

.:[ git me! ] :.

Offline

#187 2011-01-13 00:03:46

cabrey
Member
Registered: 2009-08-15
Posts: 29

Re: The dwm thread

@jasonwryan: Thanks (you were right, I was over-complicating it, but I have it figured out now)

@c00kiemon5ter: I knew it would be something stupid & simple like that. I wasn't separating out the parameters which was causing the error.

Offline

#188 2011-01-13 06:44:44

hellnest
Member
From: $ dmesg | grep ATA
Registered: 2010-11-11
Posts: 194
Website

Re: The dwm thread

Hello, i need help with leanertagbar.patch. I can't get urgent tags change it color. Even there were an activity in other task like irssi / pidgin. Which other patch i must apply first? i was try to patch the statusbarcolor but it breaks my dwm.c Here' s some info for my dwm.c and config.h
dwm.c

/* See LICENSE file for copyright and license details.
 *
 * 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.
 *
 * The event handlers of dwm 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 linked client
 * list on each monitor, the focus history is remembered through a stack list
 * on each monitor. Each client contains a bit array to indicate the tags of a
 * client.
 *
 * Keys and tagging rules are organized as arrays and defined in config.h.
 *
 * To understand everything else, start reading main().
 */
#include <errno.h>
#include <locale.h>
#include <stdarg.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */

/* macros */
#define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask))
#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
#define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X)               (sizeof X / sizeof X[0])
#define MAX(A, B)               ((A) > (B) ? (A) : (B))
#define MIN(A, B)               ((A) < (B) ? (A) : (B))
#define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
#define WIDTH(X)                ((X)->w + 2 * (X)->bw)
#define HEIGHT(X)               ((X)->h + 2 * (X)->bw)
#define TAGMASK                 ((1 << LENGTH(tags)) - 1)
#define TEXTW(X)                (textnw(X, strlen(X)) + dc.font.height)

/* enums */
enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
enum { NetSupported, NetWMName, NetWMState,
       NetWMFullscreen, NetLast };                      /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMLast };        /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
       ClkClientWin, ClkRootWin, ClkLast };             /* clicks */

typedef union {
    int i;
    unsigned int ui;
    float f;
    const void *v;
} Arg;

typedef struct {
    unsigned int click;
    unsigned int mask;
    unsigned int button;
    void (*func)(const Arg *arg);
    const Arg arg;
} Button;

typedef struct Monitor Monitor;
typedef struct Client Client;
struct Client {
    char name[256];
    float mina, maxa;
    int x, y, w, h;
    int oldx, oldy, oldw, oldh;
    int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    int bw, oldbw;
    unsigned int tags;
    Bool isfixed, isfloating, isurgent, oldstate;
    Client *next;
    Client *snext;
    Monitor *mon;
    Window win;
};

typedef struct {
    int x, y, w, h;
    unsigned long norm[ColLast];
    unsigned long sel[ColLast];
    unsigned long urg[ColLast];
    Drawable drawable;
    GC gc;
    struct {
        int ascent;
        int descent;
        int height;
        XFontSet set;
        XFontStruct *xfont;
    } font;
} DC; /* draw context */

typedef struct {
    unsigned int mod;
    KeySym keysym;
    void (*func)(const Arg *);
    const Arg arg;
} Key;

typedef struct {
    const char *symbol;
    void (*arrange)(Monitor *);
} Layout;

typedef struct {
    const char *class;
    const char *instance;
    const char *title;
    unsigned int tags;
    Bool isfloating;
    int monitor;
} Rule;

/* function declarations */
static void applyrules(Client *c);
static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
static void arrange(Monitor *m);
static void arrangemon(Monitor *m);
static void attach(Client *c);
static void attachstack(Client *c);
static void bstack(Monitor *m);
static void buttonpress(XEvent *e);
static void checkotherwm(void);
static void cleanup(void);
static void cleanupmon(Monitor *mon);
static void clearurgent(Client *c);
static void clientmessage(XEvent *e);
static void configure(Client *c);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
static Monitor *createmon(void);
static void destroynotify(XEvent *e);
static void detach(Client *c);
static void detachstack(Client *c);
static void die(const char *errstr, ...);
static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
static void drawbars(void);
static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
static void drawtext(const char *text, unsigned long col[ColLast], Bool invert);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
static unsigned long getcolor(const char *colstr);
static Bool getrootptr(int *x, int *y);
static long getstate(Window w);
static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, Bool focused);
static void grabkeys(void);
static void initfont(const char *fontstr);
static Bool isprotodel(Client *c);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(Monitor *m);
static void movemouse(const Arg *arg);
static Client *nexttiled(Client *c);
static Monitor *ptrtomon(int x, int y);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
static void resize(Client *c, int x, int y, int w, int h, Bool interact);
static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
static void scan(void);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static int textnw(const char *text, unsigned int len);
static void tile(Monitor *);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, Bool setfocus);
static void unmanage(Client *c, Bool destroyed);
static void unmapnotify(XEvent *e);
static Bool updategeom(void);
static void updatebarpos(Monitor *m);
static void updatebars(void);
static void updatenumlockmask(void);
static void updatesizehints(Client *c);
static void updatestatus(void);
static void updatetitle(Client *c);
static void updatewmhints(Client *c);
static void view(const Arg *arg);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
static void grid(Monitor*m);
static int shiftag(int dist);
static void cycle(const Arg *arg);
static void tagcycle(const Arg *arg);
static void pidgin(Monitor *m);

/* variables */
static const char broken[] = "broken";
static char stext[256];
static int screen;
static int sw, sh;           /* X display screen geometry width, height */
static int bh, blw = 0;      /* bar geometry */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
static void (*handler[LASTEvent]) (XEvent *) = {
    [ButtonPress] = buttonpress,
    [ClientMessage] = clientmessage,
    [ConfigureRequest] = configurerequest,
    [ConfigureNotify] = configurenotify,
    [DestroyNotify] = destroynotify,
    [EnterNotify] = enternotify,
    [Expose] = expose,
    [FocusIn] = focusin,
    [KeyPress] = keypress,
    [MappingNotify] = mappingnotify,
    [MapRequest] = maprequest,
    [PropertyNotify] = propertynotify,
    [UnmapNotify] = unmapnotify
};
static Atom wmatom[WMLast], netatom[NetLast];
static Bool otherwm;
static Bool running = True;
static Cursor cursor[CurLast];
static Display *dpy;
static DC dc;
static Monitor *mons = NULL, *selmon = NULL;
static Window root;

/* configuration, allows nested code to access above variables */
#include "config.h"

struct Monitor {
    char ltsymbol[16];
    float mfact;
    int num;
    int by;               /* bar geometry */
    int mx, my, mw, mh;   /* screen size */
    int wx, wy, ww, wh;   /* window area  */
    unsigned int seltags;
    unsigned int sellt;
    unsigned int tagset[2];
    Bool showbar;
    Bool topbar;
    Client *clients;
    Client *sel;
    Client *stack;
    Monitor *next;
    Window barwin;
    const Layout *lt[2];
    int curtag;
    int prevtag;
    const Layout *lts[LENGTH(tags) + 1];
    double mfacts[LENGTH(tags) + 1];
    Bool showbars[LENGTH(tags) + 1];
};

/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };

/* function implementations */
void
applyrules(Client *c) {
    const char *class, *instance;
    unsigned int i;
    const Rule *r;
    Monitor *m;
    XClassHint ch = { 0 };

    /* rule matching */
    c->isfloating = c->tags = 0;
    if(XGetClassHint(dpy, c->win, &ch)) {
        class = ch.res_class ? ch.res_class : broken;
        instance = ch.res_name ? ch.res_name : broken;
        for(i = 0; i < LENGTH(rules); i++) {
            r = &rules[i];
            if((!r->title || strstr(c->name, r->title))
            && (!r->class || strstr(class, r->class))
            && (!r->instance || strstr(instance, r->instance)))
            {
                c->isfloating = r->isfloating;
                c->tags |= r->tags;
                for(m = mons; m && m->num != r->monitor; m = m->next);
                if(m)
                    c->mon = m;
            }
        }
        if(ch.res_class)
            XFree(ch.res_class);
        if(ch.res_name)
            XFree(ch.res_name);
    }
    c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
}

Bool
applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
    Bool baseismin;
    Monitor *m = c->mon;

    /* set minimum possible */
    *w = MAX(1, *w);
    *h = MAX(1, *h);
    if(interact) {
        if(*x > sw)
            *x = sw - WIDTH(c);
        if(*y > sh)
            *y = sh - HEIGHT(c);
        if(*x + *w + 2 * c->bw < 0)
            *x = 0;
        if(*y + *h + 2 * c->bw < 0)
            *y = 0;
    }
    else {
        if(*x > m->mx + m->mw)
            *x = m->mx + m->mw - WIDTH(c);
        if(*y > m->my + m->mh)
            *y = m->my + m->mh - HEIGHT(c);
        if(*x + *w + 2 * c->bw < m->mx)
            *x = m->mx;
        if(*y + *h + 2 * c->bw < m->my)
            *y = m->my;
    }
    if(*h < bh)
        *h = bh;
    if(*w < bh)
        *w = bh;
    if(resizehints || c->isfloating) {
        /* see last two sentences in ICCCM 4.1.2.3 */
        baseismin = c->basew == c->minw && c->baseh == c->minh;
        if(!baseismin) { /* temporarily remove base dimensions */
            *w -= c->basew;
            *h -= c->baseh;
        }
        /* adjust for aspect limits */
        if(c->mina > 0 && c->maxa > 0) {
            if(c->maxa < (float)*w / *h)
                *w = *h * c->maxa + 0.5;
            else if(c->mina < (float)*h / *w)
                *h = *w * c->mina + 0.5;
        }
        if(baseismin) { /* increment calculation requires this */
            *w -= c->basew;
            *h -= c->baseh;
        }
        /* adjust for increment value */
        if(c->incw)
            *w -= *w % c->incw;
        if(c->inch)
            *h -= *h % c->inch;
        /* restore base dimensions */
        *w += c->basew;
        *h += c->baseh;
        *w = MAX(*w, c->minw);
        *h = MAX(*h, c->minh);
        if(c->maxw)
            *w = MIN(*w, c->maxw);
        if(c->maxh)
            *h = MIN(*h, c->maxh);
    }
    return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
}

void
arrange(Monitor *m) {
    if(m)
        showhide(m->stack);
    else for(m = mons; m; m = m->next)
        showhide(m->stack);
    focus(NULL);
    if(m)
        arrangemon(m);
    else for(m = mons; m; m = m->next)
        arrangemon(m);
}

void
arrangemon(Monitor *m) {
    strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
    if(m->lt[m->sellt]->arrange)
        m->lt[m->sellt]->arrange(m);
    restack(m);
}

void
attach(Client *c) {
    c->next = c->mon->clients;
    c->mon->clients = c;
}

void
attachstack(Client *c) {
    c->snext = c->mon->stack;
    c->mon->stack = c;
}

static void
bstack(Monitor *m) {
    int x, y, h, w, mh;
    unsigned int i, n;
    Client *c;

    for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
    if(n == 0)
        return;
    /* master */
    c = nexttiled(m->clients);
    mh = m->mfact * m->wh;
    resize(c, m->wx, m->wy, m->ww - 2 * c->bw, (n == 1 ? m->wh : mh) - 2 * c->bw, False);
    if(--n == 0)
        return;
    /* tile stack */
    x = m->wx;
    y = (m->wy + mh > c->y + c->h) ? c->y + c->h + 2 * c->bw : m->wy + mh;
    w = m->ww / n;
    h = (m->wy + mh > c->y + c->h) ? m->wy + m->wh - y : m->wh - mh;
    if(w < bh)
        w = m->ww;
    for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
        resize(c, x, y, /* remainder */ ((i + 1 == n)
               ? m->wx + m->ww - x - 2 * c->bw : w - 2 * c->bw), h - 2 * c->bw, False);
        if(w != m->ww)
            x = c->x + WIDTH(c);
    }
}

void
buttonpress(XEvent *e) {
    unsigned int i, x, click;
    Arg arg = {0};
    Client *c;
    Monitor *m;
    XButtonPressedEvent *ev = &e->xbutton;

    click = ClkRootWin;
    /* focus monitor if necessary */
    if((m = wintomon(ev->window)) && m != selmon) {
        unfocus(selmon->sel, True);
        selmon = m;
        focus(NULL);
    }
    if(ev->window == selmon->barwin) {
        i = x = 0;
        do {
            x += TEXTW(tags[i]);
        } while(ev->x >= x && ++i < LENGTH(tags));
        if(i < LENGTH(tags)) {
            click = ClkTagBar;
            arg.ui = 1 << i;
        }
        else if(ev->x < x + blw)
            click = ClkLtSymbol;
        else if(ev->x > selmon->wx + selmon->ww - TEXTW(stext))
            click = ClkStatusText;
        else
            click = ClkWinTitle;
    }
    else if((c = wintoclient(ev->window))) {
        focus(c);
        click = ClkClientWin;
    }
    for(i = 0; i < LENGTH(buttons); i++)
        if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
        && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
            buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
}

void
checkotherwm(void) {
    otherwm = False;
    xerrorxlib = XSetErrorHandler(xerrorstart);
    /* this causes an error if some other window manager is running */
    XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
    XSync(dpy, False);
    if(otherwm)
        die("dwm: another window manager is already running\n");
    XSetErrorHandler(xerror);
    XSync(dpy, False);
}

void
cleanup(void) {
    Arg a = {.ui = ~0};
    Layout foo = { "", NULL };
    Monitor *m;

    view(&a);
    selmon->lt[selmon->sellt] = &foo;
    for(m = mons; m; m = m->next)
        while(m->stack)
            unmanage(m->stack, False);
    if(dc.font.set)
        XFreeFontSet(dpy, dc.font.set);
    else
        XFreeFont(dpy, dc.font.xfont);
    XUngrabKey(dpy, AnyKey, AnyModifier, root);
    XFreePixmap(dpy, dc.drawable);
    XFreeGC(dpy, dc.gc);
    XFreeCursor(dpy, cursor[CurNormal]);
    XFreeCursor(dpy, cursor[CurResize]);
    XFreeCursor(dpy, cursor[CurMove]);
    while(mons)
        cleanupmon(mons);
    XSync(dpy, False);
    XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
}

void
cleanupmon(Monitor *mon) {
    Monitor *m;

    if(mon == mons)
        mons = mons->next;
    else {
        for(m = mons; m && m->next != mon; m = m->next);
        m->next = mon->next;
    }
    XUnmapWindow(dpy, mon->barwin);
    XDestroyWindow(dpy, mon->barwin);
    free(mon);
}

void
clearurgent(Client *c) {
    XWMHints *wmh;

    c->isurgent = False;
    if(!(wmh = XGetWMHints(dpy, c->win)))
        return;
    wmh->flags &= ~XUrgencyHint;
    XSetWMHints(dpy, c->win, wmh);
    XFree(wmh);
}

void
configure(Client *c) {
    XConfigureEvent ce;

    ce.type = ConfigureNotify;
    ce.display = dpy;
    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->bw;
    ce.above = None;
    ce.override_redirect = False;
    XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
}

void
configurenotify(XEvent *e) {
    Monitor *m;
    XConfigureEvent *ev = &e->xconfigure;

    if(ev->window == root) {
        sw = ev->width;
        sh = ev->height;
        if(updategeom()) {
            if(dc.drawable != 0)
                XFreePixmap(dpy, dc.drawable);
            dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
            updatebars();
            for(m = mons; m; m = m->next)
                XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
            arrange(NULL);
        }
    }
}

void
configurerequest(XEvent *e) {
    Client *c;
    Monitor *m;
    XConfigureRequestEvent *ev = &e->xconfigurerequest;
    XWindowChanges wc;

    if((c = wintoclient(ev->window))) {
        if(ev->value_mask & CWBorderWidth)
            c->bw = ev->border_width;
        else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
            m = c->mon;
            if(ev->value_mask & CWX)
                c->x = m->mx + ev->x;
            if(ev->value_mask & CWY)
                c->y = m->my + 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) > m->mx + m->mw && c->isfloating)
                c->x = m->mx + (m->mw / 2 - c->w / 2); /* center in x direction */
            if((c->y + c->h) > m->my + m->mh && c->isfloating)
                c->y = m->my + (m->mh / 2 - c->h / 2); /* center in y direction */
            if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
                configure(c);
            if(ISVISIBLE(c))
                XMoveResizeWindow(dpy, 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(dpy, ev->window, ev->value_mask, &wc);
    }
    XSync(dpy, False);
}

Monitor *
createmon(void) {
    Monitor *m;
    unsigned int i;

    if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
        die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
    m->tagset[0] = m->tagset[1] = 1;
    m->mfact = mfact;
    m->showbar = showbar;
    m->topbar = topbar;
    m->lt[0] = &layouts[0];
    m->lt[1] = &layouts[1 % LENGTH(layouts)];
    strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);

    /* pertag init */
    m->curtag = m->prevtag = 1;
    for(i=0; i < LENGTH(tags) + 1 ; i++) {
        m->mfacts[i] = mfact;
        m->lts[i] = &layouts[0];
        m->showbars[i] = m->showbar;
    }

    return m;
}

void
destroynotify(XEvent *e) {
    Client *c;
    XDestroyWindowEvent *ev = &e->xdestroywindow;

    if((c = wintoclient(ev->window)))
        unmanage(c, True);
}

void
detach(Client *c) {
    Client **tc;

    for(tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
    *tc = c->next;
}

void
detachstack(Client *c) {
    Client **tc, *t;

    for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
    *tc = c->snext;

    if(c == c->mon->sel) {
        for(t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
        c->mon->sel = t;
    }
}

void
die(const char *errstr, ...) {
    va_list ap;

    va_start(ap, errstr);
    vfprintf(stderr, errstr, ap);
    va_end(ap);
    exit(EXIT_FAILURE);
}

Monitor *
dirtomon(int dir) {
    Monitor *m = NULL;

    if(dir > 0) {
        if(!(m = selmon->next))
            m = mons;
    }
    else {
        if(selmon == mons)
            for(m = mons; m->next; m = m->next);
        else
            for(m = mons; m->next != selmon; m = m->next);
    }
    return m;
}

void
drawbar(Monitor *m) {
    int x;
  unsigned int w, tw;
    unsigned int i, occ = 0, urg = 0;
    unsigned long *col;
    Client *c;
  char stag[32];
  Bool hasurgent;

    for(c = m->clients; c; c = c->next) {
        occ |= c->tags;
        if(c->isurgent)
            urg |= c->tags;
    }
    dc.x = 0;
    for(i = 0; i < LENGTH(tags); i++) {
        col = (hasurgent = urg & 1 << i) ? dc.urg : dc.norm;
    if(m->tagset[m->seltags] & 1 << i) {
      snprintf(stag, sizeof stag, "[%s]", tags[i]);
      dc.w = TEXTW(stag);
      drawtext(stag, col, hasurgent);
    }
    else {
      dc.w = TEXTW(tags[i]);
      drawtext(tags[i], col, hasurgent);
    }
        dc.x += dc.w;
    }
    dc.w = blw = TEXTW(m->ltsymbol);
    drawtext(m->ltsymbol, dc.norm, False);
    dc.x += dc.w;
    x = dc.x;
    if(m == selmon) { /* status is only drawn on selected monitor */
        dc.w = TEXTW(stext);
        dc.x = m->ww - dc.w;
        if(dc.x < x) {
            dc.x = x;
            dc.w = m->ww - x;
        }
        drawtext(stext, dc.norm, False);
    }
    else
        dc.x = m->ww;
    if((dc.w = dc.x - x) > bh) {
        dc.x = x;
        if(m->sel) {
            col = m == selmon ? dc.sel : dc.norm;
      tw = MIN((w = dc.w), MIN(titlemaxw, TEXTW(m->sel->name)));
      dc.w = tw;
            drawtext(m->sel->name, col, False);
            drawsquare(m->sel->isfixed, m->sel->isfloating, False, col);
      if(w > tw) {
        dc.x += tw;
        dc.w = w - tw;
        drawtext(NULL, dc.norm, False);
      }
        }
        else
            drawtext(NULL, dc.norm, False);
    }
    XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0);
    XSync(dpy, False);
}

void
drawbars(void) {
    Monitor *m;

    for(m = mons; m; m = m->next)
        drawbar(m);
}

void
drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
    int x;
    XGCValues gcv;
    XRectangle r = { dc.x, dc.y, dc.w, dc.h };

    gcv.foreground = col[invert ? ColBG : ColFG];
    XChangeGC(dpy, 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(dpy, dc.drawable, dc.gc, &r, 1);
    }
    else if(empty) {
        r.width = r.height = x;
        XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
    }
}

void
drawtext(const char *text, unsigned long col[ColLast], Bool invert) {
    char buf[256];
    int i, x, y, h, len, olen;
    XRectangle r = { dc.x, dc.y, dc.w, dc.h };

    XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
    XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
    if(!text)
        return;
    olen = strlen(text);
    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 */
    for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
    if(!len)
        return;
    memcpy(buf, text, len);
    if(len < olen)
        for(i = len; i && i > len - 3; buf[--i] = '.');
    XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
    if(dc.font.set)
        XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
    else
        XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
}

void
enternotify(XEvent *e) {
    Client *c;
    Monitor *m;
    XCrossingEvent *ev = &e->xcrossing;

    if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
        return;
    if((m = wintomon(ev->window)) && m != selmon) {
        unfocus(selmon->sel, True);
        selmon = m;
    }
    if((c = wintoclient(ev->window)))
        focus(c);
    else
        focus(NULL);
}

void
expose(XEvent *e) {
    Monitor *m;
    XExposeEvent *ev = &e->xexpose;

    if(ev->count == 0 && (m = wintomon(ev->window)))
        drawbar(m);
}

void
focus(Client *c) {
    if(!c || !ISVISIBLE(c))
        for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
    /* was if(selmon->sel) */
    if(selmon->sel && selmon->sel != c)
        unfocus(selmon->sel, False);
    if(c) {
        if(c->mon != selmon)
            selmon = c->mon;
        if(c->isurgent)
            clearurgent(c);
        detachstack(c);
        attachstack(c);
        grabbuttons(c, True);
        XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
        XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
    }
    else
        XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
    selmon->sel = c;
    drawbars();
}

void
focusin(XEvent *e) { /* there are some broken focus acquiring clients */
    XFocusChangeEvent *ev = &e->xfocus;

    if(selmon->sel && ev->window != selmon->sel->win)
        XSetInputFocus(dpy, selmon->sel->win, RevertToPointerRoot, CurrentTime);
}

void
focusmon(const Arg *arg) {
    Monitor *m = NULL;

    if(!mons->next)
        return;
    if((m = dirtomon(arg->i)) == selmon)
        return;
    unfocus(selmon->sel, True);
    selmon = m;
    focus(NULL);
}

void
focusstack(const Arg *arg) {
    Client *c = NULL, *i;

    if(!selmon->sel)
        return;
    if(arg->i > 0) {
        for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
        if(!c)
            for(c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
    }
    else {
        for(i = selmon->clients; i != selmon->sel; i = i->next)
            if(ISVISIBLE(i))
                c = i;
        if(!c)
            for(; i; i = i->next)
                if(ISVISIBLE(i))
                    c = i;
    }
    if(c) {
        focus(c);
        restack(selmon);
    }
}

unsigned long
getcolor(const char *colstr) {
    Colormap cmap = DefaultColormap(dpy, screen);
    XColor color;

    if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
        die("error, cannot allocate color '%s'\n", colstr);
    return color.pixel;
}

Bool
getrootptr(int *x, int *y) {
    int di;
    unsigned int dui;
    Window dummy;

    return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
}

long
getstate(Window w) {
    int format;
    long result = -1;
    unsigned char *p = NULL;
    unsigned long n, extra;
    Atom real;

    if(XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
                          &real, &format, &n, &extra, (unsigned char **)&p) != Success)
        return -1;
    if(n != 0)
        result = *p;
    XFree(p);
    return result;
}

Bool
gettextprop(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(dpy, w, &name, atom);
    if(!name.nitems)
        return False;
    if(name.encoding == XA_STRING)
        strncpy(text, (char *)name.value, size - 1);
    else {
        if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
            strncpy(text, *list, size - 1);
            XFreeStringList(list);
        }
    }
    text[size - 1] = '\0';
    XFree(name.value);
    return True;
}

void
grabbuttons(Client *c, Bool focused) {
    updatenumlockmask();
    {
        unsigned int i, j;
        unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
        XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
        if(focused) {
            for(i = 0; i < LENGTH(buttons); i++)
                if(buttons[i].click == ClkClientWin)
                    for(j = 0; j < LENGTH(modifiers); j++)
                        XGrabButton(dpy, buttons[i].button,
                                    buttons[i].mask | modifiers[j],
                                    c->win, False, BUTTONMASK,
                                    GrabModeAsync, GrabModeSync, None, None);
        }
        else
            XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
                        BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
    }
}

void
grabkeys(void) {
    updatenumlockmask();
    {
        unsigned int i, j;
        unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
        KeyCode code;

        XUngrabKey(dpy, AnyKey, AnyModifier, root);
        for(i = 0; i < LENGTH(keys); i++) {
            if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
                for(j = 0; j < LENGTH(modifiers); j++)
                    XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
                         True, GrabModeAsync, GrabModeAsync);
        }
    }
}

void
initfont(const char *fontstr) {
    char *def, **missing;
    int i, n;

    missing = NULL;
    dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
    if(missing) {
        while(n--)
            fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
        XFreeStringList(missing);
    }
    if(dc.font.set) {
        XFontSetExtents *font_extents;
        XFontStruct **xfonts;
        char **font_names;

        dc.font.ascent = dc.font.descent = 0;
        font_extents = XExtentsOfFontSet(dc.font.set);
        n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
        for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
            dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent);
            dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent);
            xfonts++;
        }
    }
    else {
        if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
        && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
            die("error, cannot load font: '%s'\n", fontstr);
        dc.font.ascent = dc.font.xfont->ascent;
        dc.font.descent = dc.font.xfont->descent;
    }
    dc.font.height = dc.font.ascent + dc.font.descent;
}

Bool
isprotodel(Client *c) {
    int i, n;
    Atom *protocols;
    Bool ret = False;

    if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
        for(i = 0; !ret && i < n; i++)
            if(protocols[i] == wmatom[WMDelete])
                ret = True;
        XFree(protocols);
    }
    return ret;
}

#ifdef XINERAMA
static Bool
isuniquegeom(XineramaScreenInfo *unique, size_t len, XineramaScreenInfo *info) {
    unsigned int i;

    for(i = 0; i < len; i++)
        if(unique[i].x_org == info->x_org && unique[i].y_org == info->y_org
        && unique[i].width == info->width && unique[i].height == info->height)
            return False;
    return True;
}
#endif /* XINERAMA */

void
keypress(XEvent *e) {
    unsigned int i;
    KeySym keysym;
    XKeyEvent *ev;

    ev = &e->xkey;
    keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
    for(i = 0; i < LENGTH(keys); i++)
        if(keysym == keys[i].keysym
        && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
        && keys[i].func)
            keys[i].func(&(keys[i].arg));
}

void
killclient(const Arg *arg) {
    XEvent ev;

    if(!selmon->sel)
        return;
    if(isprotodel(selmon->sel)) {
        ev.type = ClientMessage;
        ev.xclient.window = selmon->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(dpy, selmon->sel->win, False, NoEventMask, &ev);
    }
    else {
        XGrabServer(dpy);
        XSetErrorHandler(xerrordummy);
        XSetCloseDownMode(dpy, DestroyAll);
        XKillClient(dpy, selmon->sel->win);
        XSync(dpy, False);
        XSetErrorHandler(xerror);
        XUngrabServer(dpy);
    }
}

void
manage(Window w, XWindowAttributes *wa) {
    static Client cz;
    Client *c, *t = NULL;
    Window trans = None;
    XWindowChanges wc;

    if(!(c = malloc(sizeof(Client))))
        die("fatal: could not malloc() %u bytes\n", sizeof(Client));
    *c = cz;
    c->win = w;
    updatetitle(c);
    if(XGetTransientForHint(dpy, w, &trans))
        t = wintoclient(trans);
    if(t) {
        c->mon = t->mon;
        c->tags = t->tags;
    }
    else {
        c->mon = selmon;
        applyrules(c);
    }
    /* geometry */
    c->x = c->oldx = wa->x + c->mon->wx;
    c->y = c->oldy = wa->y + c->mon->wy;
    c->w = c->oldw = wa->width;
    c->h = c->oldh = wa->height;
    c->oldbw = wa->border_width;
    if(c->w == c->mon->mw && c->h == c->mon->mh) {
        c->isfloating = 1;
        c->x = c->mon->mx;
        c->y = c->mon->my;
        c->bw = 0;
    }
    else {
        if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
            c->x = c->mon->mx + c->mon->mw - WIDTH(c);
        if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
            c->y = c->mon->my + c->mon->mh - HEIGHT(c);
        c->x = MAX(c->x, c->mon->mx);
        /* only fix client y-offset, if the client center might cover the bar */
        c->y = MAX(c->y, ((c->mon->by == 0) && (c->x + (c->w / 2) >= c->mon->wx)
                   && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
        c->bw = borderpx;
    }
    wc.border_width = c->bw;
    XConfigureWindow(dpy, w, CWBorderWidth, &wc);
    XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
    configure(c); /* propagates border_width, if size doesn't change */
    updatesizehints(c);
    XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
    grabbuttons(c, False);
    if(!c->isfloating)
        c->isfloating = c->oldstate = trans != None || c->isfixed;
    if(c->isfloating)
        XRaiseWindow(dpy, c->win);
    attach(c);
    attachstack(c);
    XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
    XMapWindow(dpy, c->win);
    setclientstate(c, NormalState);
    arrange(c->mon);
}

void
mappingnotify(XEvent *e) {
    XMappingEvent *ev = &e->xmapping;

    XRefreshKeyboardMapping(ev);
    if(ev->request == MappingKeyboard)
        grabkeys();
}

void
maprequest(XEvent *e) {
    static XWindowAttributes wa;
    XMapRequestEvent *ev = &e->xmaprequest;

    if(!XGetWindowAttributes(dpy, ev->window, &wa))
        return;
    if(wa.override_redirect)
        return;
    if(!wintoclient(ev->window))
        manage(ev->window, &wa);
}

void
monocle(Monitor *m) {
    unsigned int n = 0;
    Client *c;

    for(c = m->clients; c; c = c->next)
        if(ISVISIBLE(c))
            n++;
    if(n > 0) /* override layout symbol */
        snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
    for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
        resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
}

void
movemouse(const Arg *arg) {
    int x, y, ocx, ocy, nx, ny;
    Client *c;
    Monitor *m;
    XEvent ev;

    if(!(c = selmon->sel))
        return;
    restack(selmon);
    ocx = c->x;
    ocy = c->y;
    if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
    None, cursor[CurMove], CurrentTime) != GrabSuccess)
        return;
    if(!getrootptr(&x, &y))
        return;
    do {
        XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
        switch (ev.type) {
        case ConfigureRequest:
        case Expose:
        case MapRequest:
            handler[ev.type](&ev);
            break;
        case MotionNotify:
            nx = ocx + (ev.xmotion.x - x);
            ny = ocy + (ev.xmotion.y - y);
            if(snap && nx >= selmon->wx && nx <= selmon->wx + selmon->ww
            && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
                if(abs(selmon->wx - nx) < snap)
                    nx = selmon->wx;
                else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
                    nx = selmon->wx + selmon->ww - WIDTH(c);
                if(abs(selmon->wy - ny) < snap)
                    ny = selmon->wy;
                else if(abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
                    ny = selmon->wy + selmon->wh - HEIGHT(c);
                if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
                && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
                    togglefloating(NULL);
            }
            if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
                resize(c, nx, ny, c->w, c->h, True);
            break;
        }
    } while(ev.type != ButtonRelease);
    XUngrabPointer(dpy, CurrentTime);
    if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) {
        sendmon(c, m);
        selmon = m;
        focus(NULL);
    }
}

Client *
nexttiled(Client *c) {
    for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
    return c;
}

Monitor *
ptrtomon(int x, int y) {
    Monitor *m;

    for(m = mons; m; m = m->next)
        if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh))
            return m;
    return selmon;
}

void
propertynotify(XEvent *e) {
    Client *c;
    Window trans;
    XPropertyEvent *ev = &e->xproperty;

    if((ev->window == root) && (ev->atom == XA_WM_NAME))
        updatestatus();
    else if(ev->state == PropertyDelete)
        return; /* ignore */
    else if((c = wintoclient(ev->window))) {
        switch (ev->atom) {
        default: break;
        case XA_WM_TRANSIENT_FOR:
            XGetTransientForHint(dpy, c->win, &trans);
            if(!c->isfloating && (c->isfloating = (wintoclient(trans) != NULL)))
                arrange(c->mon);
            break;
        case XA_WM_NORMAL_HINTS:
            updatesizehints(c);
            break;
        case XA_WM_HINTS:
            updatewmhints(c);
            drawbars();
            break;
        }
        if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
            updatetitle(c);
            if(c == c->mon->sel)
                drawbar(c->mon);
        }
    }
}

void
clientmessage(XEvent *e) {
    XClientMessageEvent *cme = &e->xclient;
    Client *c;

    if((c = wintoclient(cme->window))
    && (cme->message_type == netatom[NetWMState] && cme->data.l[1] == netatom[NetWMFullscreen]))
    {
        if(cme->data.l[0]) {
            XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32,
                            PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
            c->oldstate = c->isfloating;
            c->oldbw = c->bw;
            c->bw = 0;
            c->isfloating = 1;
            resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
            XRaiseWindow(dpy, c->win);
        }
        else {
            XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32,
                            PropModeReplace, (unsigned char*)0, 0);
            c->isfloating = c->oldstate;
            c->bw = c->oldbw;
            c->x = c->oldx;
            c->y = c->oldy;
            c->w = c->oldw;
            c->h = c->oldh;
            resizeclient(c, c->x, c->y, c->w, c->h);
            arrange(c->mon);
        }
    }
}

void
quit(const Arg *arg) {
    running = False;
}

void
resize(Client *c, int x, int y, int w, int h, Bool interact) {
    if(applysizehints(c, &x, &y, &w, &h, interact))
        resizeclient(c, x, y, w, h);
}

void
resizeclient(Client *c, int x, int y, int w, int h) {
    XWindowChanges wc;

    c->oldx = c->x; c->x = wc.x = x;
    c->oldy = c->y; c->y = wc.y = y;
    c->oldw = c->w; c->w = wc.width = w;
    c->oldh = c->h; c->h = wc.height = h;
    wc.border_width = c->bw;
    XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
    configure(c);
    XSync(dpy, False);
}

void
resizemouse(const Arg *arg) {
    int ocx, ocy;
    int nw, nh;
    Client *c;
    Monitor *m;
    XEvent ev;

    if(!(c = selmon->sel))
        return;
    restack(selmon);
    ocx = c->x;
    ocy = c->y;
    if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
                    None, cursor[CurResize], CurrentTime) != GrabSuccess)
        return;
    XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
    do {
        XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
        switch(ev.type) {
        case ConfigureRequest:
        case Expose:
        case MapRequest:
            handler[ev.type](&ev);
            break;
        case MotionNotify:
            nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
            nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
            if(snap && nw >= selmon->wx && nw <= selmon->wx + selmon->ww
            && nh >= selmon->wy && nh <= selmon->wy + selmon->wh)
            {
                if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
                && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
                    togglefloating(NULL);
            }
            if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
                resize(c, c->x, c->y, nw, nh, True);
            break;
        }
    } while(ev.type != ButtonRelease);
    XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
    XUngrabPointer(dpy, CurrentTime);
    while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
    if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) {
        sendmon(c, m);
        selmon = m;
        focus(NULL);
    }
}

void
restack(Monitor *m) {
    Client *c;
    XEvent ev;
    XWindowChanges wc;

    drawbar(m);
    if(!m->sel)
        return;
    if(m->sel->isfloating || !m->lt[m->sellt]->arrange)
        XRaiseWindow(dpy, m->sel->win);
    if(m->lt[m->sellt]->arrange) {
        wc.stack_mode = Below;
        wc.sibling = m->barwin;
        for(c = m->stack; c; c = c->snext)
            if(!c->isfloating && ISVISIBLE(c)) {
                XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
                wc.sibling = c->win;
            }
    }
    XSync(dpy, False);
    while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}

void
run(void) {
    XEvent ev;
    /* main event loop */
    XSync(dpy, False);
    while(running && !XNextEvent(dpy, &ev)) {
        if(handler[ev.type])
            handler[ev.type](&ev); /* call handler */
    }
}

void
scan(void) {
    unsigned int i, num;
    Window d1, d2, *wins = NULL;
    XWindowAttributes wa;

    if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
        for(i = 0; i < num; i++) {
            if(!XGetWindowAttributes(dpy, wins[i], &wa)
            || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
                continue;
            if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
                manage(wins[i], &wa);
        }
        for(i = 0; i < num; i++) { /* now the transients */
            if(!XGetWindowAttributes(dpy, wins[i], &wa))
                continue;
            if(XGetTransientForHint(dpy, wins[i], &d1)
            && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
                manage(wins[i], &wa);
        }
        if(wins)
            XFree(wins);
    }
}

void
sendmon(Client *c, Monitor *m) {
    if(c->mon == m)
        return;
    unfocus(c, True);
    detach(c);
    detachstack(c);
    c->mon = m;
    c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
    attach(c);
    attachstack(c);
    focus(NULL);
    arrange(NULL);
}

void
setclientstate(Client *c, long state) {
    long data[] = { state, None };

    XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
            PropModeReplace, (unsigned char *)data, 2);
}

void
setlayout(const Arg *arg) {
    if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
        selmon->sellt ^= 1;
    if(arg && arg->v)
        selmon->lt[selmon->sellt] = selmon->lts[selmon->curtag] = (Layout *)arg->v;
    strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
    if(selmon->sel)
        arrange(selmon);
    else
        drawbar(selmon);
}

/* arg > 1.0 will set mfact absolutly */
void
setmfact(const Arg *arg) {
    float f;

    if(!arg || !selmon->lt[selmon->sellt]->arrange)
        return;
    f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
    if(f < 0.1 || f > 0.9)
        return;
    selmon->mfact = selmon->mfacts[selmon->curtag] = f;
    arrange(selmon);
}

void
setup(void) {
    XSetWindowAttributes wa;

    /* clean up any zombies immediately */
    sigchld(0);

    /* init screen */
    screen = DefaultScreen(dpy);
    root = RootWindow(dpy, screen);
    initfont(font);
    sw = DisplayWidth(dpy, screen);
    sh = DisplayHeight(dpy, screen);
    bh = dc.h = dc.font.height + 2;
    updategeom();
    /* init atoms */
    wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
    wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
    wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
    netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
    netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
    netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
    netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
    /* init cursors */
    cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
    cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
    cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
    /* init appearance */
    dc.norm[ColBorder] = getcolor(normbordercolor);
    dc.norm[ColBG] = getcolor(normbgcolor);
    dc.norm[ColFG] = getcolor(normfgcolor);
    dc.sel[ColBorder] = getcolor(selbordercolor);
    dc.sel[ColBG] = getcolor(selbgcolor);
    dc.sel[ColFG] = getcolor(selfgcolor);
  dc.urg[ColBorder] = getcolor(urgbordercolor);
  dc.urg[ColBG] = getcolor(urgbgcolor);
  dc.urg[ColFG] = getcolor(urgfgcolor);
    dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen));
    dc.gc = XCreateGC(dpy, root, 0, NULL);
    XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
    if(!dc.font.set)
        XSetFont(dpy, dc.gc, dc.font.xfont->fid);
    updatebars();
    updatestatus();
    /* EWMH support per view */
    XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
            PropModeReplace, (unsigned char *) netatom, NetLast);
    /* select for events */
    wa.cursor = cursor[CurNormal];
    wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask
                    |EnterWindowMask|LeaveWindowMask|StructureNotifyMask
                    |PropertyChangeMask;
    XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
    XSelectInput(dpy, root, wa.event_mask);
    grabkeys();
}

void
showhide(Client *c) {
    if(!c)
        return;
    if(ISVISIBLE(c)) { /* show clients top down */
        XMoveWindow(dpy, c->win, c->x, c->y);
        if(!c->mon->lt[c->mon->sellt]->arrange || c->isfloating)
            resize(c, c->x, c->y, c->w, c->h, False);
        showhide(c->snext);
    }
    else { /* hide clients bottom up */
        showhide(c->snext);
        XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
    }
}


void
sigchld(int unused) {
    if(signal(SIGCHLD, sigchld) == SIG_ERR)
        die("Can't install SIGCHLD handler");
    while(0 < waitpid(-1, NULL, WNOHANG));
}

void
spawn(const Arg *arg) {
    if(fork() == 0) {
        if(dpy)
            close(ConnectionNumber(dpy));
        setsid();
        execvp(((char **)arg->v)[0], (char **)arg->v);
        fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
        perror(" failed");
        exit(0);
    }
}

void
tag(const Arg *arg) {
    if(selmon->sel && arg->ui & TAGMASK) {
        selmon->sel->tags = arg->ui & TAGMASK;
        arrange(selmon);
    }
}

void
tagmon(const Arg *arg) {
    if(!selmon->sel || !mons->next)
        return;
    sendmon(selmon->sel, dirtomon(arg->i));
}

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);
}

void
tile(Monitor *m) {
    int x, y, h, w, mw;
    unsigned int i, n;
    Client *c;

    for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
    if(n == 0)
        return;
    /* master */
    c = nexttiled(m->clients);
    mw = m->mfact * m->ww;
    resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw, False);
    if(--n == 0)
        return;
    /* tile stack */
    x = (m->wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : m->wx + mw;
    y = m->wy;
    w = (m->wx + mw > c->x + c->w) ? m->wx + m->ww - x : m->ww - mw;
    h = m->wh / n;
    if(h < bh)
        h = m->wh;
    for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
        resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n)
               ? m->wy + m->wh - y - 2 * c->bw : h - 2 * c->bw), False);
        if(h != m->wh)
            y = c->y + HEIGHT(c);
    }
}

void
togglebar(const Arg *arg) {
    selmon->showbar = selmon->showbars[selmon->curtag] = !selmon->showbar;
    updatebarpos(selmon);
    XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
    arrange(selmon);
}

void
togglefloating(const Arg *arg) {
    if(!selmon->sel)
        return;
    selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
    if(selmon->sel->isfloating)
        resize(selmon->sel, selmon->sel->x, selmon->sel->y,
               selmon->sel->w, selmon->sel->h, False);
    arrange(selmon);
}

void
toggletag(const Arg *arg) {
    unsigned int newtags;
    unsigned int i;

    if(!selmon->sel)
        return;
    newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
    if(newtags) {
        selmon->sel->tags = newtags;
        if(newtags == ~0) {
            selmon->prevtag = selmon->curtag;
            selmon->curtag = 0;
        }
        if(!(newtags & 1 << (selmon->curtag - 1))) {
            selmon->prevtag = selmon->curtag;
            for (i=0; !(newtags & 1 << i); i++);
            selmon->curtag = i + 1;
        }
        selmon->sel->tags = newtags;
        selmon->lt[selmon->sellt] = selmon->lts[selmon->curtag];
        selmon->mfact = selmon->mfacts[selmon->curtag];
        if (selmon->showbar != selmon->showbars[selmon->curtag])
            togglebar(NULL);
        arrange(selmon);
    }
}

void
toggleview(const Arg *arg) {
    unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);

    if(newtagset) {
        selmon->tagset[selmon->seltags] = newtagset;
        arrange(selmon);
    }
}

void
unfocus(Client *c, Bool setfocus) {
    if(!c)
        return;
    grabbuttons(c, False);
    XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
    if(setfocus)
        XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
}

void
unmanage(Client *c, Bool destroyed) {
    Monitor *m = c->mon;
    XWindowChanges wc;

    /* The server grab construct avoids race conditions. */
    detach(c);
    detachstack(c);
    if(!destroyed) {
        wc.border_width = c->oldbw;
        XGrabServer(dpy);
        XSetErrorHandler(xerrordummy);
        XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
        XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
        setclientstate(c, WithdrawnState);
        XSync(dpy, False);
        XSetErrorHandler(xerror);
        XUngrabServer(dpy);
    }
    free(c);
    focus(NULL);
    arrange(m);
}

void
unmapnotify(XEvent *e) {
    Client *c;
    XUnmapEvent *ev = &e->xunmap;

    if((c = wintoclient(ev->window)))
        unmanage(c, False);
}

void
updatebars(void) {
    Monitor *m;
    XSetWindowAttributes wa;

    wa.override_redirect = True;
    wa.background_pixmap = ParentRelative;
    wa.event_mask = ButtonPressMask|ExposureMask;
    for(m = mons; m; m = m->next) {
        m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
                                  CopyFromParent, DefaultVisual(dpy, screen),
                                  CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
        XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
        XMapRaised(dpy, m->barwin);
    }
}

void
updatebarpos(Monitor *m) {
    m->wy = m->my;
    m->wh = m->mh;
    if(m->showbar) {
        m->wh -= bh;
        m->by = m->topbar ? m->wy : m->wy + m->wh;
        m->wy = m->topbar ? m->wy + bh : m->wy;
    }
    else
        m->by = -bh;
}

Bool
updategeom(void) {
    Bool dirty = False;

#ifdef XINERAMA
    if(XineramaIsActive(dpy)) {
        int i, j, n, nn;
        Client *c;
        Monitor *m;
        XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
        XineramaScreenInfo *unique = NULL;

        info = XineramaQueryScreens(dpy, &nn);
        for(n = 0, m = mons; m; m = m->next, n++);
        /* only consider unique geometries as separate screens */
        if(!(unique = (XineramaScreenInfo *)malloc(sizeof(XineramaScreenInfo) * nn)))
            die("fatal: could not malloc() %u bytes\n", sizeof(XineramaScreenInfo) * nn);
        for(i = 0, j = 0; i < nn; i++)
            if(isuniquegeom(unique, j, &info[i]))
                memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
        XFree(info);
        nn = j;
        if(n <= nn) {
            for(i = 0; i < (nn - n); i++) { /* new monitors available */
                for(m = mons; m && m->next; m = m->next);
                if(m)
                    m->next = createmon();
                else
                    mons = createmon();
            }
            for(i = 0, m = mons; i < nn && m; m = m->next, i++)
                if(i >= n
                || (unique[i].x_org != m->mx || unique[i].y_org != m->my
                    || unique[i].width != m->mw || unique[i].height != m->mh))
                {
                    dirty = True;
                    m->num = i;
                    m->mx = m->wx = unique[i].x_org;
                    m->my = m->wy = unique[i].y_org;
                    m->mw = m->ww = unique[i].width;
                    m->mh = m->wh = unique[i].height;
                    updatebarpos(m);
                }
        }
        else { /* less monitors available nn < n */
            for(i = nn; i < n; i++) {
                for(m = mons; m && m->next; m = m->next);
                while(m->clients) {
                    dirty = True;
                    c = m->clients;
                    m->clients = c->next;
                    detachstack(c);
                    c->mon = mons;
                    attach(c);
                    attachstack(c);
                }
                if(m == selmon)
                    selmon = mons;
                cleanupmon(m);
            }
        }
        free(unique);
    }
    else
#endif /* XINERAMA */
    /* default monitor setup */
    {
        if(!mons)
            mons = createmon();
        if(mons->mw != sw || mons->mh != sh) {
            dirty = True;
            mons->mw = mons->ww = sw;
            mons->mh = mons->wh = sh;
            updatebarpos(mons);
        }
    }
    if(dirty) {
        selmon = mons;
        selmon = wintomon(root);
    }
    return dirty;
}

void
updatenumlockmask(void) {
    unsigned int i, j;
    XModifierKeymap *modmap;

    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);
}

void
updatesizehints(Client *c) {
    long msize;
    XSizeHints size;

    if(!XGetWMNormalHints(dpy, c->win, &size, &msize))
        /* size is uninitialized, ensure that size.flags aren't used */
        size.flags = PSize;
    if(size.flags & PBaseSize) {
        c->basew = size.base_width;
        c->baseh = size.base_height;
    }
    else if(size.flags & PMinSize) {
        c->basew = size.min_width;
        c->baseh = size.min_height;
    }
    else
        c->basew = c->baseh = 0;
    if(size.flags & PResizeInc) {
        c->incw = size.width_inc;
        c->inch = size.height_inc;
    }
    else
        c->incw = c->inch = 0;
    if(size.flags & PMaxSize) {
        c->maxw = size.max_width;
        c->maxh = size.max_height;
    }
    else
        c->maxw = c->maxh = 0;
    if(size.flags & PMinSize) {
        c->minw = size.min_width;
        c->minh = size.min_height;
    }
    else if(size.flags & PBaseSize) {
        c->minw = size.base_width;
        c->minh = size.base_height;
    }
    else
        c->minw = c->minh = 0;
    if(size.flags & PAspect) {
        c->mina = (float)size.min_aspect.y / size.min_aspect.x;
        c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
    }
    else
        c->maxa = c->mina = 0.0;
    c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
                 && c->maxw == c->minw && c->maxh == c->minh);
}

void
updatetitle(Client *c) {
    if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
        gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
    if(c->name[0] == '\0') /* hack to mark broken clients */
        strcpy(c->name, broken);
}

void
updatestatus(void) {
    if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
        strcpy(stext, "dwm-"VERSION);
    drawbar(selmon);
}

void
updatewmhints(Client *c) {
    XWMHints *wmh;

    if((wmh = XGetWMHints(dpy, c->win))) {
        if(c == selmon->sel && wmh->flags & XUrgencyHint) {
            wmh->flags &= ~XUrgencyHint;
            XSetWMHints(dpy, c->win, wmh);
        }
   else {
      c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
      if(c->isurgent)
        XSetWindowBorder(dpy, c->win, dc.urg[ColBorder]);
      }
        XFree(wmh);
    }
}

void
view(const Arg *arg) {
    unsigned int i;

    if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
        return;
    selmon->seltags ^= 1; /* toggle sel tagset */
    if(arg->ui & TAGMASK) {
        selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
        selmon->prevtag = selmon->curtag;
        if(arg->ui == ~0)
            selmon->curtag = 0;
        else {
            for (i=0; !(arg->ui & 1 << i); i++);
            selmon->curtag = i + 1;
        }
    } else {
        selmon->prevtag= selmon->curtag ^ selmon->prevtag;
        selmon->curtag^= selmon->prevtag;
        selmon->prevtag= selmon->curtag ^ selmon->prevtag;
    }
    selmon->lt[selmon->sellt]= selmon->lts[selmon->curtag];
    selmon->mfact = selmon->mfacts[selmon->curtag];
    if(selmon->showbar != selmon->showbars[selmon->curtag])
        togglebar(NULL);
    arrange(selmon);
}

Client *
wintoclient(Window w) {
    Client *c;
    Monitor *m;

    for(m = mons; m; m = m->next)
        for(c = m->clients; c; c = c->next)
            if(c->win == w)
                return c;
    return NULL;
}

Monitor *
wintomon(Window w) {
    int x, y;
    Client *c;
    Monitor *m;

    if(w == root && getrootptr(&x, &y))
        return ptrtomon(x, y);
    for(m = mons; m; m = m->next)
        if(w == m->barwin)
            return m;
    if((c = wintoclient(w)))
        return c->mon;
    return selmon;
}

/* 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 *dpy, 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_GrabButton && ee->error_code == BadAccess)
    || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
    || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
        return 0;
    fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
            ee->request_code, ee->error_code);
    return xerrorxlib(dpy, ee); /* may call exit */
}

int
xerrordummy(Display *dpy, XErrorEvent *ee) {
    return 0;
}

/* Startup Error handler to check if another window manager
 * is already running. */
int
xerrorstart(Display *dpy, XErrorEvent *ee) {
    otherwm = True;
    return -1;
}

void
zoom(const Arg *arg) {
    Client *c = selmon->sel;

    if(!selmon->lt[selmon->sellt]->arrange
    || selmon->lt[selmon->sellt]->arrange == monocle
    || (selmon->sel && selmon->sel->isfloating))
        return;
    if(c == nexttiled(selmon->clients))
        if(!c || !(c = nexttiled(c->next)))
            return;
    detach(c);
    attach(c);
    focus(c);
    arrange(c->mon);
}

int
main(int argc, char *argv[]) {
    if(argc == 2 && !strcmp("-v", argv[1]))
        die("dwm-"VERSION", © 2006-2010 dwm engineers, see LICENSE for details\n");
    else if(argc != 1)
        die("usage: dwm [-v]\n");
    if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
        fputs("warning: no locale support\n", stderr);
    if(!(dpy = XOpenDisplay(NULL)))
        die("dwm: cannot open display\n");
    checkotherwm();
    setup();
    scan();
    run();
    cleanup();
    XCloseDisplay(dpy);
    return 0;
}

void
grid(Monitor *m) {
    unsigned int i, n, cx, cy, cw, ch, aw, ah, cols, rows;
    Client *c;

    for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next))
        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 = m->wh / (rows ? rows : 1);
    cw = m->ww / (cols ? cols : 1);
    for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
        cx = m->wx + (i / rows) * cw;
        cy = m->wy + (i % rows) * ch;
        /* adjust height/width of last row/column's windows */
        ah = ((i + 1) % rows == 0) ? m->wh - ch * rows : 0;
        aw = (i >= rows * (cols - 1)) ? m->ww - cw * cols : 0;
        resize(c, cx, cy, cw - 2 * c->bw + aw, ch - 2 * c->bw + ah, False);
        i++;
    }
}

static const char wmname[] = "Buddy List";

static void
pidgin(Monitor *m) {
    int x, y, h, w, ww;
    unsigned int i, n;
    Client *c, *mk = 0;

    for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
        if(strstr(c->name, wmname))
            mk = c;
    if(n == 0)
        return;
    /* master */
    ww = m->mfacts[m->curtag] * m->ww;
    if(mk) {
        resize(mk, m->wx + ww, m->wy, m->ww - ww - 2 * mk->bw, m->wh - 2 * mk->bw, False);
        strncpy(m->ltsymbol, "==P", sizeof m->ltsymbol);
        if(--n == 0)
            return;
    }
    /* tile stack */
    x = m->wx;
    y = m->wy;
    w = (mk ? ww : m->ww) / n;
    h = m->wh;
    if(h < bh)
        h = m->wh;
    for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
        if(c == mk) {
            --i;
            continue;
        }
        resize(c, x, y, ((i + 1 == n) ? m->mx + (mk ? ww : m->ww) - x : w) - 2 * c->bw,
               h - 2 * c->bw, False);
        if(w != m->ww)
            x = c->x + WIDTH(c);
    }
}

static int
shifttag(int dist)
{
    int i, curtags;
    int seltag = 0;
    int numtags = LENGTH(tags);

    curtags = selmon->tagset[selmon->seltags];
    for(i = 0; i < LENGTH(tags); i++) {
        if((curtags & (1 << i)) != 0) {
            seltag = i;
            break;
        }
    }

    seltag += dist;
    if(seltag < 0)
        seltag = numtags - (-seltag) % numtags;
    else
        seltag %= numtags;

    return 1 << seltag;
}

static void
cycle(const Arg *arg)
{
    const Arg a = { .i = shifttag(arg->i) };
    view(&a);
}

static void
tagcycle(const Arg *arg)
{
    const Arg a = { .i = shifttag(arg->i) };
    tag(&a);
    view(&a);
}

config.h

/* See LICENSE file for copyright and license details. */

/* appearance */
static const char font[]                = "-*-snap-*-*-*-*-10-100-*-*-*-*-iso10646-*";
static const char normbordercolor[]     = "#555753";
static const char normbgcolor[]         = "#2e3436";
static const char normfgcolor[]         = "#d3d7cf";
static const char selbordercolor[]      = "#555753";
static const char selbgcolor[]          = "#000000";
static const char selfgcolor[]          = "#d3d7cf";
static const char urgbordercolor[]    = "#ff0066";
static const char urgbgcolor[]        = "#ff0066";
static const char urgfgcolor[]        = "#ffffff";
static const unsigned int borderpx      = 1;        /* border pixel of windows */
static const unsigned int snap          = 24;       /* snap pixel */
static const Bool showbar               = True;     /* False means no bar */
static const Bool topbar                = True;     /* False means bottom bar */
static const unsigned int titlemaxw    = 230;      /* Maximum title widh in px*/

/* tagging */
static const char *tags[] = { "C", "WWW", "Irssi", "IM", "Mail", "FM", "Box" };

static const Rule rules[] = {
    /* class          instance    title           tags mask     isfloating   monitor */
    { "Gimp",          NULL,       NULL,            0,              True,         -1 },
    { "Chrome",        NULL,       NULL,            1 << 1,         False,        -1 },
    { "Uzbl",      NULL,          NULL,          1 << 1,      False            -1 },
    { "Pidgin",     "Pidgin",    "Buddy List",       1 << 3,         False,        -1 },
    { "URxvt",     "irssi",     "irssi",            1 << 2,         False,        -1 },
    { "Pcmanfm",     NULL,       NULL,         1 << 5,     False,        -1 },
    { "MPlayer",     NULL,         NULL,         1 << 6,     True,           -1 },
};

/* layout(s) */
static const float mfact      = 0.55; /* factor of master area size [0.05..0.95] */
static const Bool resizehints = False; /* True means respect size hints in tiled resizals */
static const Layout layouts[] = {
    /* symbol     arrange function */
    { "[T]=",      tile },    /* first entry is default */
    { "[G]",      grid },
    { "[F]",      NULL },    /* no layout function means floating behavior */
    { "[M]",      monocle },
    { "[s]",      bstack },
};

/* key definitions */
#define MODKEY Mod4Mask
#define TAGKEYS(KEY,TAG) \
    { MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
    { MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
    { MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
    { MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },

/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }

/* commands */
static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *termcmd[]  = { "urxvtc", NULL };
static const char *browser[]  = { "chromium-browser", NULL };

static Key keys[] = {
    /* modifier                     key        function        argument */
    { MODKEY,                       XK_r,      spawn,          {.v = dmenucmd } },
    { MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
    { MODKEY,            XK_c,      spawn,       {.v = browser } },
    { MODKEY,                       XK_b,      togglebar,      {0} },
    { MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
    { MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
    { MODKEY,                       XK_h,      setmfact,       {.f = -0.05} },
    { MODKEY,                       XK_l,      setmfact,       {.f = +0.05} },
    { MODKEY,                       XK_Return, zoom,           {0} },
    { MODKEY,                       XK_Tab,    view,           {0} },
    { MODKEY|ShiftMask,             XK_c,      killclient,     {0} },
    { MODKEY,                       XK_t,      setlayout,      {.v = &layouts[0]} },
    { MODKEY,                       XK_f,      setlayout,      {.v = &layouts[1]} },
    { MODKEY,                       XK_m,      setlayout,      {.v = &layouts[2]} },
    { MODKEY,                       XK_space,  setlayout,      {0} },
    { MODKEY|ShiftMask,             XK_space,  togglefloating, {0} },
    { MODKEY,                       XK_0,      view,           {.ui = ~0 } },
    { MODKEY|ShiftMask,             XK_0,      tag,            {.ui = ~0 } },
    { MODKEY,                       XK_comma,  focusmon,       {.i = -1 } },
    { MODKEY,                       XK_period, focusmon,       {.i = +1 } },
    { MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
    { MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
    { MODKEY,            XK_Left,   cycle,       {.i = -1 } },
    { MODKEY,            XK_Right,  cycle,       {.i = +1 } },
    { MODKEY|ControlMask,        XK_Left,   tagcycle,       {.i = -1 } },
    { MODKEY|ControlMask,           XK_Right,  tagcycle,       {.i = +1 } },
    TAGKEYS(                        XK_1,                      0)
    TAGKEYS(                        XK_2,                      1)
    TAGKEYS(                        XK_3,                      2)
    TAGKEYS(                        XK_4,                      3)
    TAGKEYS(                        XK_5,                      4)
    TAGKEYS(                        XK_6,                      5)
    TAGKEYS(                        XK_7,                      6)
    TAGKEYS(                        XK_8,                      7)
    TAGKEYS(                        XK_9,                      8)
    { MODKEY|ShiftMask,             XK_q,      quit,           {0} },
};

/* button definitions */
/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static Button buttons[] = {
    /* click                event mask      button          function        argument */
    { ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
    { ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
    { ClkWinTitle,          0,              Button2,        zoom,           {0} },
    { ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
    { ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
    { ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} },
    { ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} },
    { ClkTagBar,            0,              Button1,        view,           {0} },
    { ClkTagBar,            0,              Button3,        toggleview,     {0} },
    { ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
    { ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
};

roll Snapping my own life roll
hmmgithubhmm
coolMyBlogcool

Offline

#189 2011-01-13 07:36:58

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 30,424
Website

Re: The dwm thread

Moved to the dwm thread: the other one is for hacks... (again).

I don't know what the leanertags patch is (it's not on the suckless wiki), but if you want colour in your status bar, you'll need statusbarcolor.

You seem to have a couple of the layout patches and the cycle patch - if status color won't apply cleanly, you'll need to hand patch it.


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#190 2011-01-13 12:30:07

hellnest
Member
From: $ dmesg | grep ATA
Registered: 2010-11-11
Posts: 194
Website

Re: The dwm thread

@jasonwyran smile
Lol, yeah beacuse the leantag.patch is come from post 1 in DWM Hacking thread ^^.. ok will try to apply one by one and see if it can get well.


roll Snapping my own life roll
hmmgithubhmm
coolMyBlogcool

Offline

#191 2011-09-08 19:51:49

JHeaton
Member
From: United Kingdom
Registered: 2009-05-16
Posts: 158

Re: The dwm thread

Just a quick question, does anyone else have issues with the gaps between applications in dwm? If I launch a pair of terminals, for example, there's no gap between them. If I switch to the next tag and back again, a gap has appeared. Is this something anyone has encountered and found a fix for?

Offline

#192 2011-09-08 21:33:35

the sad clown
Member
From: 192.168.0.X
Registered: 2011-03-20
Posts: 837

Re: The dwm thread

JHeaton wrote:

Just a quick question, does anyone else have issues with the gaps between applications in dwm? If I launch a pair of terminals, for example, there's no gap between them. If I switch to the next tag and back again, a gap has appeared. Is this something anyone has encountered and found a fix for?

What terminal are you using?  I have urxvt and haven't noticed the issue.

Edit:  Actually, it might be urxvt if your font size is causing it to have gaps.  This is a known issue with stock urxvt.  There is a urxvt in the AUR that will fix this for you.

https://aur.archlinux.org/packages.php?ID=44649

Last edited by the sad clown (2011-09-08 21:40:48)


I laugh, yet the joke is on me

Offline

#193 2011-09-09 07:02:44

JHeaton
Member
From: United Kingdom
Registered: 2009-05-16
Posts: 158

Re: The dwm thread

the sad clown wrote:
JHeaton wrote:

Just a quick question, does anyone else have issues with the gaps between applications in dwm? If I launch a pair of terminals, for example, there's no gap between them. If I switch to the next tag and back again, a gap has appeared. Is this something anyone has encountered and found a fix for?

What terminal are you using?  I have urxvt and haven't noticed the issue.

Edit:  Actually, it might be urxvt if your font size is causing it to have gaps.  This is a known issue with stock urxvt.  There is a urxvt in the AUR that will fix this for you.

https://aur.archlinux.org/packages.php?ID=44649

It happens with applications in general, terminals were just an example (it also happens with xterm and I have the patched urxvt from AUR already). hmm

Thing is, I like it when they have the gaps as it helps to break things up more. But if that's not supposed to be the intended functionality, I guess I'll have to find/make a patch for it.

Offline

#194 2011-09-09 12:44:18

the sad clown
Member
From: 192.168.0.X
Registered: 2011-03-20
Posts: 837

Re: The dwm thread

Well, if you like gaps, you should add the uselessgap patch to dwm.  It's updated for dwm 5.9 and works very well.  Then your gaps really will be intended functionality, plus, it will then be able to manipulate the size of the gaps from your config.h file.

http://dwm.suckless.org/patches/uselessgap


I laugh, yet the joke is on me

Offline

#195 2011-09-09 13:53:09

JHeaton
Member
From: United Kingdom
Registered: 2009-05-16
Posts: 158

Re: The dwm thread

Thanks, I'll give that a try.

Edit: Installed the patch, however still get the problem only the gaps are initially visible now. Switching to another tag and back widens them to the specified gap-size (3px in my case). This appears to be driver-related; I was using nouveau and switching to the proprietary nvidia driver does not give the same issue. Is there any way that I can find out if this is a problem with dwm or nouveau? I'm guessing it's the latter, but... :S

Last edited by JHeaton (2011-09-09 21:31:42)

Offline

#196 2011-10-01 20:41:21

Army
Member
Registered: 2007-12-07
Posts: 1,784

Re: The dwm thread

Is there a way in dwm to switch to the next or previous tag? Right now it only seems to be possible to go to e.g. tag 2 with Mod+2. I'd like to be able to jump from tag 1 to tag 2 with Mod+n and back from tag 2 to tag 1 with Mod+p. Is that possible? Does anybody know a way?

Offline

#197 2011-10-01 20:44:41

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 30,424
Website

Re: The dwm thread

You could use the cycle patch and bind next and previous to Mod n and Mod p.

https://github.com/simongmzlj/dwm/blob/master/cycle.c


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#198 2011-10-01 20:48:15

Army
Member
Registered: 2007-12-07
Posts: 1,784

Re: The dwm thread

Ah, cycle patch, "cycle" is the keyword I didn't search for, so thanks!

Offline

#199 2011-12-25 21:30:36

adriasansa
Member
Registered: 2011-12-25
Posts: 3

Re: The dwm thread

I recently install dwm, I have configured succesfully some shortcouts, but I can't close the windows, althought other similar shortcouts like opening a terminal are working. Here's my config.h :

/* See LICENSE file for copyright and license details. */

/* appearance */
static const char font[]            = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*";
static const char normbordercolor[] = "#444444";
static const char normbgcolor[]     = "#222222";
static const char normfgcolor[]     = "#bbbbbb";
static const char selbordercolor[]  = "#005577";
static const char selbgcolor[]      = "#005577";
static const char selfgcolor[]      = "#eeeeee";
static const unsigned int borderpx  = 1;        /* border pixel of windows */
static const unsigned int snap      = 32;       /* snap pixel */
static const Bool showbar           = True;     /* False means no bar */
static const Bool topbar            = True;     /* False means bottom bar */

/* tagging */
static const char *tags[] = { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X" };

static const Rule rules[] = {
	/* class      instance    title       tags mask     isfloating   monitor */
	{ "Gimp",     NULL,       NULL,       0,            True,        -1 },
	{ "Firefox",  NULL,       NULL,       0,       False,       -1 },
		                    /* a tags mask abans posava 1<<8    */
};

/* layout(s) */
static const float mfact      = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster      = 1;    /* number of clients in master area */
static const Bool resizehints = True; /* True means respect size hints in tiled resizals */

static const Layout layouts[] = {
	/* symbol     arrange function */
	{ "Pantalla compl",      tile },    /* first entry is default */
	{ "Finestra",      NULL },    /* no layout function means floating behavior */
	{ "[M]",      monocle },
};

/* key definitions */
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
	{ MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
	{ MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
	{ MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
	{ MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },

/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }

/* commands */
static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *termcmd[]  = { "urxvt", NULL };

static Key keys[] = {
	/* modifier                     key        function        argument */
	{ MODKEY,                       XK_z,      spawn,          {.v = dmenucmd } },
	{ MODKEY,	                XK_a,  	spawn,          {.v = termcmd } },
	{ MODKEY,                       XK_b,      togglebar,      {0} },
	{ MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
	{ MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
	{ MODKEY,                       XK_i,      incnmaster,     {.i = +1 } },
	{ MODKEY,                       XK_d,      incnmaster,     {.i = -1 } },
	{ MODKEY,                       XK_h,      setmfact,       {.f = -0.05} },
	{ MODKEY,                       XK_l,      setmfact,       {.f = +0.05} },
	{ MODKEY,                       XK_Return, zoom,           {0} },
	{ MODKEY,                       XK_Tab,    view,           {0} },
	{ MODKEY,             		XK_c,      killclient,     {0} },
	{ MODKEY,                       XK_t,      setlayout,      {.v = &layouts[0]} },
	{ MODKEY,                       XK_f,      setlayout,      {.v = &layouts[1]} },
	{ MODKEY,                       XK_m,      setlayout,      {.v = &layouts[2]} },
	{ MODKEY,                       XK_space,  setlayout,      {0} },
	{ MODKEY|ShiftMask,             XK_space,  togglefloating, {0} },
	{ MODKEY,                       XK_0,      view,           {.ui = ~0 } },
	{ MODKEY|ShiftMask,             XK_0,      tag,            {.ui = ~0 } },
	{ MODKEY,                       XK_comma,  focusmon,       {.i = -1 } },
	{ MODKEY,                       XK_period, focusmon,       {.i = +1 } },
	{ MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
	{ MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
	TAGKEYS(                        XK_1,                      0)
	TAGKEYS(                        XK_2,                      1)
	TAGKEYS(                        XK_3,                      2)
	TAGKEYS(                        XK_4,                      3)
	TAGKEYS(                        XK_5,                      4)
	TAGKEYS(                        XK_6,                      5)
	TAGKEYS(                        XK_7,                      6)
	TAGKEYS(                        XK_8,                      7)
	TAGKEYS(                        XK_9,                      8)
	{ MODKEY|ShiftMask,             XK_q,      quit,           {0} },
};

/* button definitions */
/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static Button buttons[] = {
	/* click                event mask      button          function        argument */
	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
	{ ClkWinTitle,          0,              Button2,        zoom,           {0} },
	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
	{ ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} },
	{ ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} },
	{ ClkTagBar,            0,              Button1,        view,           {0} },
	{ ClkTagBar,            0,              Button3,        toggleview,     {0} },
	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
};

I haven't changed any other file. Thank you very much.

Last edited by adriasansa (2011-12-26 21:39:18)

Offline

#200 2011-12-25 21:32:56

karol
Archivist
Registered: 2009-05-06
Posts: 25,440

Re: The dwm thread

adriasansa, please edit your post.
When pasting code, please use [ code ] tags https://bbs.archlinux.org/help.php#bbcode

like this

It makes the code more readable and more convenient to scroll through.

Offline

Board footer

Powered by FluxBB