/* 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. * * Calls to fetch an X event from the event queue are blocking. Due reading * status text from standard input, a select()-driven main loop has been * implemented which selects for reads on the X connection and STDIN_FILENO to * handle all data smoothly. The event handlers of 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 global * doubly-linked client list, the focus history is remembered through a global * stack list. 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef XINERAMA #include #endif /* 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(x) (x->tags & tagset[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 MAXTAGLEN 16 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define TAGMASK ((int)((1LL << 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, NetLast }; /* EWMH atoms */ enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ typedef union { int i; unsigned int ui; float f; 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 Client Client; struct Client { char name[256]; float mina, maxa; int x, y, w, h; int basew, baseh, incw, inch, maxw, maxh, minw, minh; int bw, oldbw; unsigned int tags; Bool isfixed, isfloating, isurgent; Client *next; Client *snext; Window win; }; typedef struct { int x, y, w, h; unsigned long norm[ColLast]; unsigned long sel[ColLast]; Drawable drawable; GC gc; struct { int ascent; int descent; int height; XFontSet set; XFontStruct *xfont; } font; } DC; /* draw context */ typedef struct { unsigned int mod; KeySym keysym; void (*func)(const Arg *); const Arg arg; } Key; typedef struct { const char *symbol; void (*arrange)(void); } Layout; typedef struct { const char *class; const char *instance; const char *title; unsigned int tags; Bool isfloating; } Rule; /* function declarations */ static void applyrules(Client *c); static void arrange(void); static void attach(Client *c); static void attachstack(Client *c); static void buttonpress(XEvent *e); static void checkotherwm(void); static void cleanup(void); static void clearurgent(void); static void configure(Client *c); static void configurenotify(XEvent *e); static void configurerequest(XEvent *e); static void destroynotify(XEvent *e); static void detach(Client *c); static void detachstack(Client *c
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
	<head>
		<title>Democracy: Fundamentals (Unfinished)</title>
		<link rel="stylesheet" href="/style.css" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
		<meta charset="utf-8" />
	</head>
	<body class="indent">
		<h1>Democracy: Fundamentals (Unfinished)</h1>
		<p>Article ID: 4</p>
		<p><i>Unless otherwise specified, "democracy" in this article refers to representative democracy.  "Country" can additionally refer to other regions that have people and its own policies, such as a state, provinces in some countries, etc.</i></p>
		<p>
		We usually think of "democracy" as people influencing the policies of the country by electing trustworthy experts that serve their interest to make actual decisions about running the country.  This type of democracy, representative democracy, has evolved from direct democracy aging back two thousand years ago as created by Athens in Greece.  Representative democracy is more scalable than direct democracy and also avoids some forms of populism and uninformed decisions as its the experts in the field that are making the actual policies.
		</p>
		<p>
		The Chinese term for democracy is "民主".  The first character, "民", means "people"; the second, "主", ascin "主人" means "owner".  You could understand it as saying "the people of the country own the country (and thus get to decide on its affairs)".  But at the same time, "主" as in "自主" means "do things themselves", i.e. the right not to be interfered by others while doing their own business.
		</p>
		<p>
		This is, of course, not the proper definition for democracy; democracy is just saying that the general public ultimately runs the country.  But we could take the time to appreciate how with democracy we usually end up with liberty and how we take personal liberty for granted.
		</p>
		<p>
		In any case, both democracy and liberty are important in a long-lasting prosperous system of society.  Note my wording in the first paragraph, that the decisions of elected experts are for "running the country"&mdash;I specifically mean issues that deal with either the general public (such as public health and the environment) and things that would be otherwise hard to solve personally (such as enforcement of contracts and crimes).  The "will of the people", represented by the government, have no business doing things like banning freedom of thought or mandating people not to smoke in their private property.  Only when things affect others such as smoking in public should the government, or the will of the general public, have any say.  And of course, people should take responsibility for their own private deeds.  It is argued that a lung cancer patient who got lung cancer by smoking excessively doesn't deserve medical insurance from taxpayers; but for cases where an illness isn't caused by a identifiable private decision factor, medical insurance and support should be given.  (In practice the distinction is subtle; this is also a very controversial topic.)
		</p>
		<p>
		People overemphasize the importance of democracy.  In fact, democracy is in my opinion less important than liberty&mdash;though in practice indeed liberty wouldn't survive for long without democracy.
		</p>
		<p>
		Note that abortion and similar subjects may fall into the scope of government.  Some opponents of abortion believe that fetus is human life and thus abortion is murder and shall be outlawed.  The "privacy" and "personal liberty" arguments don't stand up well against this as it's no longer a personal matter when another human life is supposedly on the line.  <a href="abortion.html">I oppose the abortion bans that Republicans in the US are placing in many states for a different reason.</a>
		</p>
		<p>
		Modern populism (which is a poorly-defined term but does have the following general scope) gives the power of deciding everything that happens in the country to the people.  This is bad in two ways. (1) The general public often make uninformed and un-thought-through decisions and are easily influenced.  (2) The government, in this case directly the collective decision of the people, is stepping its feet into the personal lives of people.  While it is democratic, it doesn't give people liberty, creating a tyranny of the majority, and at the same time making uninformed decisions which are better made by experts which people elect.
		</p>
		<p>
		In future articles, I will discuss more practical issues in democracy and society, especially on corruption of representatives, issues with the modern voting system, etc.
		</p>
		<div id="footer">
			<hr />
			<p><a href="/">Runxi Yu's Website</a></p>
			<p>Unless otherwise specified with the "<span class="copyright">copyright</span>" HTML/CSS class, works hosted on this subdomain (<code>www.andrewyu.org</code>) served with the HTTP(S) protocol is available under <a href="https://www.andrewyu.org/note/pubdom.html">Runxi Yu's Public Domain Dedication</a>.</p>
		</div>
	</body>
</html>
xfonts)->descent); xfonts++; } } else { if(dc.font.xfont) XFreeFont(dpy, dc.font.xfont); dc.font.xfont = NULL; 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 isoccupied(unsigned int t) { Client *c; for(c = clients; c; c = c->next) if(c->tags & 1 << t) return True; return False; } 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; } Bool isurgent(unsigned int t) { Client *c; for(c = clients; c; c = c->next) if(c->isurgent && c->tags & 1 << t) return True; return False; } 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(!sel) return; if(isprotodel(sel)) { ev.type = ClientMessage; ev.xclient.window = sel->win; ev.xclient.message_type = wmatom[WMProtocols]; ev.xclient.format = 32; ev.xclient.data.l[0] = wmatom[WMDelete]; ev.xclient.data.l[1] = CurrentTime; XSendEvent(dpy, sel->win, False, NoEventMask, &ev); } else XKillClient(dpy, sel->win); } void manage(Window w, XWindowAttributes *wa) { Client *c, *t = NULL; Status rettrans; Window trans; XWindowChanges wc; if(!(c = calloc(1, sizeof(Client)))) die("fatal: could not calloc() %u bytes\n", sizeof(Client)); c->win = w; /* geometry */ c->x = wa->x; c->y = wa->y; c->w = wa->width; c->h = wa->height; c->oldbw = wa->border_width; if(c->w == sw && c->h == sh) { c->x = sx; c->y = sy; c->bw = 0; } else { if(c->x + c->w + 2 * c->bw > sx + sw) c->x = sx + sw - c->w - 2 * c->bw; if(c->y + c->h + 2 * c->bw > sy + sh) c->y = sy + sh - c->h - 2 * c->bw; c->x = MAX(c->x, sx); /* only fix client y-offset, if the client center might cover the bar */ c->y = MAX(c->y, ((by == 0) && (c->x + (c->w / 2) >= wx) && (c->x + (c->w / 2) < wx + ww)) ? bh : sy); 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); updatetitle(c); if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success)) for(t = clients; t && t->win != trans; t = t->next); if(t) c->tags = t->tags; else applyrules(c); if(!c->isfloating) c->isfloating = (rettrans == Success) || 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(); } 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(!getclient(ev->window)) manage(ev->window, &wa); } void monocle(void) { Client *c; for(c = nexttiled(clients); c; c = nexttiled(c->next)) resize(c, wx, wy, ww - 2 * c->bw, wh - 2 * c->bw, resizehints); } void movemouse(const Arg *arg) { int x, y, ocx, ocy, di, nx, ny; unsigned int dui; Client *c; Window dummy; XEvent ev; if(!(c = sel)) return; restack(); ocx = nx = c->x; ocy = ny = c->y; if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, cursor[CurMove], CurrentTime) != GrabSuccess) return; XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui); for(;;) { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); switch (ev.type) { case ButtonRelease: XUngrabPointer(dpy, CurrentTime); return; case ConfigureRequest: case Expose: case MapRequest: handler[ev.type](&ev); break; case MotionNotify: XSync(dpy, False); nx = ocx + (ev.xmotion.x - x); ny = ocy + (ev.xmotion.y - y); if(snap && nx >= wx && nx <= wx + ww && ny >= wy && ny <= wy + wh) { if(abs(wx - nx) < snap) nx = wx; else if(abs((wx + ww) - (nx + c->w + 2 * c->bw)) < snap) nx = wx + ww - c->w - 2 * c->bw; if(abs(wy - ny) < snap) ny = wy; else if(abs((wy + wh) - (ny + c->h + 2 * c->bw)) < snap) ny = wy + wh - c->h - 2 * c->bw; if(!c->isfloating && lt[sellt]->arrange && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) togglefloating(NULL); } if(!lt[sellt]->arrange || c->isfloating) resize(c, nx, ny, c->w, c->h, False); break; } } } Client * nexttiled(Client *c) { for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); return c; } void propertynotify(XEvent *e) { Client *c; Window trans; XPropertyEvent *ev = &e->xproperty; if(ev->state == PropertyDelete) return; /* ignore */ if((c = getclient(ev->window))) { switch (ev->atom) { default: break; case XA_WM_TRANSIENT_FOR: XGetTransientForHint(dpy, c->win, &trans); if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL))) arrange(); break; case XA_WM_NORMAL_HINTS: updatesizehints(c); break; case XA_WM_HINTS: updatewmhints(c); drawbar(); break; } if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { updatetitle(c); if(c == sel) drawbar(); } } } void quit(const Arg *arg) { readin = running = False; } void resize(Client *c, int x, int y, int w, int h, Bool sizehints) { XWindowChanges wc; if(sizehints) { /* set minimum possible */ w = MAX(1, w); h = MAX(1, h); /* 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; else if(c->mina > (float) h/w) h = w * c->mina; } /* 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); } if(w <= 0 || h <= 0) return; if(x > sx + sw) x = sw - w - 2 * c->bw; if(y > sy + sh) y = sh - h - 2 * c->bw; if(x + w + 2 * c->bw < sx) x = sx; if(y + h + 2 * c->bw < sy) y = sy; if(h < bh) h = bh; if(w < bh) w = bh; if(c->x != x || c->y != y || c->w != w || c->h != h) { c->x = wc.x = x; c->y = wc.y = y; c->w = wc.width = w; c->h = wc.height = h; wc.border_width = c->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; XEvent ev; if(!(c = sel)) return; restack(); 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); for(;;) { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask , &ev); switch(ev.type) { case 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)); return; case ConfigureRequest: case Expose: case MapRequest: handler[ev.type](&ev); break; case MotionNotify: XSync(dpy, False); 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 >= wx && nw <= wx + ww && nh >= wy && nh <= wy + wh) { if(!c->isfloating && lt[sellt]->arrange && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) togglefloating(NULL); } if(!lt[sellt]->arrange || c->isfloating) resize(c, c->x, c->y, nw, nh, True); break; } } } void restack(void) { Client *c; XEvent ev; XWindowChanges wc; drawbar(); if(!sel) return; if(sel->isfloating || !lt[sellt]->arrange) XRaiseWindow(dpy, sel->win); if(lt[sellt]->arrange) { wc.stack_mode = Below; wc.sibling = barwin; for(c = 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) { char *p; char sbuf[sizeof stext]; fd_set rd; int r, xfd; unsigned int len, offset; XEvent ev; /* main event loop, also reads status text from stdin */ XSync(dpy, False); xfd = ConnectionNumber(dpy); offset = 0; len = sizeof stext - 1; sbuf[len] = stext[len] = '\0'; /* 0-terminator is never touched */ while(running) { FD_ZERO(&rd); if(readin) FD_SET(STDIN_FILENO, &rd); FD_SET(xfd, &rd); if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) { if(errno == EINTR) continue; die("select failed\n"); } if(FD_ISSET(STDIN_FILENO, &rd)) { switch((r = read(STDIN_FILENO, sbuf + offset, len - offset))) { case -1: strncpy(stext, strerror(errno), len); readin = False; break; case 0: strncpy(stext, "EOF", 4); readin = False; break; default: for(p = sbuf + offset; r > 0; p++, r--, offset++) if(*p == '\n' || *p == '\0') { *p = '\0'; strncpy(stext, sbuf, len); p += r - 1; /* p is sbuf + offset + r - 1 */ for(r = 0; *(p - r) && *(p - r) != '\n'; r++); offset = r; if(r) memmove(sbuf, p - r + 1, r); break; } break; } drawbar(); } while(XPending(dpy)) { XNextEvent(dpy, &ev); if(handler[ev.type]) (handler[ev.type])(&ev); /* call handler */ } } } void scan(void) { unsigned int i, num; Window *wins, d1, d2; XWindowAttributes wa; wins = NULL; 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 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 != lt[sellt]) sellt ^= 1; if(arg && arg->v) lt[sellt] = (Layout *)arg->v; if(sel) arrange(); else drawbar(); } /* arg > 1.0 will set mfact absolutly */ void setmfact(const Arg *arg) { float f; if(!arg || !lt[sellt]->arrange) return; f = arg->f < 1.0 ? arg->f + mfact : arg->f - 1.0; if(f < 0.1 || f > 0.9) return; mfact = f; arrange(); } void setup(void) { unsigned int i; int w; XSetWindowAttributes wa; /* init screen */ screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); initfont(font); sx = 0; sy = 0; sw = DisplayWidth(dpy, screen); sh = DisplayHeight(dpy, screen); bh = dc.h = dc.font.height + 2; lt[0] = &layouts[0]; lt[1] = &layouts[1 % LENGTH(layouts)]; updategeom(); /* init atoms */ wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False); wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); /* init cursors */ wa.cursor = 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.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); dc.gc = XCreateGC(dpy, root, 0, 0); XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); if(!dc.font.set) XSetFont(dpy, dc.gc, dc.font.xfont->fid); /* init bar */ for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) { w = TEXTW(layouts[i].symbol); blw = MAX(blw, w); } wa.override_redirect = 1; wa.background_pixmap = ParentRelative; wa.event_mask = ButtonPressMask|ExposureMask; barwin = XCreateWindow(dpy, root, wx, by, ww, bh, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); XDefineCursor(dpy, barwin, cursor[CurNormal]); XMapRaised(dpy, barwin); strcpy(stext, "dwm-"VERSION); drawbar(); /* EWMH support per view */ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, PropModeReplace, (unsigned char *) netatom, NetLast); /* select for events */ wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask |EnterWindowMask|LeaveWindowMask|StructureNotifyMask; XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); XSelectInput(dpy, root, wa.event_mask); /* grab keys */ grabkeys(); } void spawn(const Arg *arg) { /* The double-fork construct avoids zombie processes and keeps the code * clean from stupid signal handlers. */ if(fork() == 0) { 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); } wait(0); } void tag(const Arg *arg) { if(sel && arg->ui & TAGMASK) { sel->tags = arg->ui & TAGMASK; arrange(); } } 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(void) { int x, y, h, w, mw; unsigned int i, n; Client *c; for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next), n++); if(n == 0) return; /* master */ c = nexttiled(clients); mw = mfact * ww; resize(c, wx, wy, (n == 1 ? ww : mw) - 2 * c->bw, wh - 2 * c->bw, resizehints); if(--n == 0) return; /* tile stack */ x = (wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : wx + mw; y = wy; w = (wx + mw > c->x + c->w) ? wx + ww - x : ww - mw; h = wh / n; if(h < bh) h = 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) ? (wy + wh) - y : h) - 2 * c->bw, resizehints); if(h != wh) y = c->y + c->h + 2 * c->bw; } } void togglebar(const Arg *arg) { showbar = !showbar; updategeom(); updatebar(); arrange(); } void togglefloating(const Arg *arg) { if(!sel) return; sel->isfloating = !sel->isfloating || sel->isfixed; if(sel->isfloating) resize(sel, sel->x, sel->y, sel->w, sel->h, True); arrange(); } void toggletag(const Arg *arg) { unsigned int mask = sel->tags ^ (arg->ui & TAGMASK); if(sel && mask) { sel->tags = mask; arrange(); } } void toggleview(const Arg *arg) { unsigned int mask = tagset[seltags] ^ (arg->ui & TAGMASK); if(mask) { tagset[seltags] = mask; clearurgent(); arrange(); } } void unmanage(Client *c) { XWindowChanges wc; wc.border_width = c->oldbw; /* The server grab construct avoids race conditions. */ XGrabServer(dpy); XSetErrorHandler(xerrordummy); XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ detach(c); detachstack(c); if(sel == c) focus(NULL); XUngrabButton(dpy, AnyButton, AnyModifier, c->win); setclientstate(c, WithdrawnState); free(c); XSync(dpy, False); XSetErrorHandler(xerror); XUngrabServer(dpy); arrange(); } void unmapnotify(XEvent *e) { Client *c; XUnmapEvent *ev = &e->xunmap; if((c = getclient(ev->window))) unmanage(c); } void updatebar(void) { if(dc.drawable != 0) XFreePixmap(dpy, dc.drawable); dc.drawable = XCreatePixmap(dpy, root, ww, bh, DefaultDepth(dpy, screen)); XMoveResizeWindow(dpy, barwin, wx, by, ww, bh); } void updategeom(void) { #ifdef XINERAMA int n, i = 0; XineramaScreenInfo *info = NULL; /* window area geometry */ if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { if(n > 1) { int di, x, y; unsigned int dui; Window dummy; if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) for(i = 0; i < n; i++) if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) break; } wx = info[i].x_org; wy = showbar && topbar ? info[i].y_org + bh : info[i].y_org; ww = info[i].width; wh = showbar ? info[i].height - bh : info[i].height; XFree(info); } else #endif { wx = sx; wy = showbar && topbar ? sy + bh : sy; ww = sw; wh = showbar ? sh - bh : sh; } /* bar position */ by = showbar ? (topbar ? wy - bh : wy + wh) : -bh; } void updatesizehints(Client *c) { long msize; XSizeHints size; XGetWMNormalHints(dpy, c->win, &size, &msize); 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 / (float)size.min_aspect.x; c->maxa = (float)size.max_aspect.x / (float)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, wmatom[WMName], c->name, sizeof c->name); } void updatewmhints(Client *c) { XWMHints *wmh; if((wmh = XGetWMHints(dpy, c->win))) { if(ISVISIBLE(c) && wmh->flags & XUrgencyHint) { wmh->flags &= ~XUrgencyHint; XSetWMHints(dpy, c->win, wmh); } else c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; XFree(wmh); } } void view(const Arg *arg) { if(arg && (arg->i & TAGMASK) == tagset[seltags]) return; seltags ^= 1; /* toggle sel tagset */ if(arg && (arg->ui & TAGMASK)) tagset[seltags] = arg->i & TAGMASK; clearurgent(); arrange(); } /* 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 = sel; if(!lt[sellt]->arrange || lt[sellt]->arrange == monocle || (sel && sel->isfloating)) return; if(c == nexttiled(clients)) if(!c || !(c = nexttiled(c->next))) return; detach(c); attach(c); focus(c); arrange(); } int main(int argc, char *argv[]) { if(argc == 2 && !strcmp("-v", argv[1])) die("dwm-"VERSION", © 2006-2008 dwm engineers, see LICENSE for details\n"); else if(argc != 1) die("usage: dwm [-v]\n"); if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fprintf(stderr, "warning: no locale support\n"); if(!(dpy = XOpenDisplay(0))) die("dwm: cannot open display\n"); checkotherwm(); setup(); scan(); run(); cleanup(); XCloseDisplay(dpy); return 0; }