/* * wmfs.c * Copyright © 2008 Martin Duquesnoy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of the nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "wmfs.h" void arrange(void) { Client *c; for(c = clients; c; c = c->next) if(!ishide(c)) unhide(c); else hide(c); focus(NULL); tags[seltag].layout.func(); updatebar(); return; } void attach(Client *c) { if(clients) clients->prev = c; c->next = clients; clients = c; return; } int clientpertag(int tag) { Client *c; int i = 0; for(c = clients; c; c = c->next) if(c->tag == tag) ++i; return i; } /* True : next * False : prev */ void client_switch(Bool b) { Client *c; if(!sel || ishide(sel)) return; if(b) { for(c = sel->next; c && ishide(c); c = c->next); if(!c) for(c = clients; c && ishide(c); c = c->next); if(c) { focus(c); if(!c->tile) raiseclient(c); } } else { for(c = sel->prev; c && ishide(c); c = c->prev); if(!c) { for(c = clients; c && c->next; c = c->next); for(; c && ishide(c); c = c->prev); } if(c) { focus(c); if(!c->tile) raiseclient(c); } } updateall(); return; } void uicb_client_prev(char *cmd) { client_switch(False); return; } void uicb_client_next(char *cmd) { client_switch(True); return; } void detach(Client *c) { Client **cc; for(cc = &clients; *cc && *cc != c; cc = &(*cc)->next); *cc = c->next; return; } int errorhandler(Display *d, XErrorEvent *event) { char mess[512]; XGetErrorText(d, event->error_code, mess, 128); fprintf(stderr, "WMFS error: %s(%d) opcodes %d/%d\n resource 0x%lx\n", mess, event->error_code, event->request_code, event->minor_code, event->resourceid); return 1; } /* for no-important error */ int errorhandlerdummy(Display *d, XErrorEvent *event) { return 0; } void focus(Client *c) { if(sel && sel != c) { grabbuttons(sel, False); setborder(sel->win, conf.colors.bordernormal); if(conf.ttbarheight) setborder(sel->tbar, conf.colors.bordernormal); } if(c) grabbuttons(c, True); sel = c; if(c) { setborder(c->win, conf.colors.borderfocus); if(conf.ttbarheight) setborder(sel->tbar, conf.colors.borderfocus); if(conf.raisefocus) raiseclient(c); XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); updatetitle(c); } else XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); return; } Client* getbutton(Window w) { Client *c; for(c = clients; c && c->button != w; c = c->next); return c; } Client* getclient(Window w) { Client *c; for(c = clients; c && c->win != w; c = c->next); return c; } Client* getnext(Client *c) { for(; c; c = c->prev); return c; } Client* gettbar(Window w) { Client *c; for(c = clients; c && c->tbar != w; c = c->next); return c; } void grabbuttons(Client *c, Bool focused) { int i; XUngrabButton(dpy, AnyButton, AnyModifier, c->win); if(conf.ttbarheight) { XUngrabButton(dpy, AnyButton, AnyModifier, c->tbar); if(conf.ttbarheight > 5) XUngrabButton(dpy, AnyButton, AnyModifier, c->button); } if(focused) { /* Window */ XGrabButton(dpy, Button1, ALT, c->win, False, ButtonMask, GrabModeAsync,GrabModeSync, None, None); XGrabButton(dpy, Button1, ALT|LockMask, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button2, ALT, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button2, ALT|LockMask, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button3, ALT, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button3, ALT|LockMask, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); if(conf.ttbarheight) { /* Titlebar */ XGrabButton(dpy, Button1, AnyModifier, c->tbar, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button2, AnyModifier, c->tbar, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button3, AnyModifier, c->tbar, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); /* Titlebar Button */ if(conf.ttbarheight > 5) { XGrabButton(dpy, Button1, AnyModifier, c->button, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button3, AnyModifier, c->button, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); } } /* Bar Button */ for(i=0; i< conf.nbutton; ++i) XGrabButton(dpy, Button1, AnyModifier, conf.barbutton[i].win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); } else { XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); if(conf.ttbarheight) { XGrabButton(dpy, AnyButton, AnyModifier, c->tbar, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); if(conf.ttbarheight > 5) XGrabButton(dpy, AnyButton, AnyModifier, c->button, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); } for(i=0; i< conf.nbutton; ++i) XGrabButton(dpy, Button1, AnyModifier, conf.barbutton[i].win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); } return; } void grabkeys(void) { unsigned int i; KeyCode code; XUngrabKey(dpy, AnyKey, AnyModifier, root); for(i = 0; i < conf.nkeybind; i++) { code = XKeysymToKeycode(dpy, keys[i].keysym); XGrabKey(dpy, code, keys[i].mod, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, code, keys[i].mod|numlockmask, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, code, keys[i].mod|LockMask, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, code, keys[i].mod|LockMask|numlockmask, root, True, GrabModeAsync, GrabModeAsync); } return; } void hide(Client *c) { if(!c) return; XMoveWindow(dpy, c->win, c->x, c->y+mh*2); if(conf.ttbarheight) { XMoveWindow(dpy, c->tbar, c->x, c->y+mh*2); if(conf.ttbarheight > 5) XMoveWindow(dpy, c->button, c->x, c->y+mh*2); } setwinstate(c->win, IconicState); c->hide = True; return; } void init(void) { XSetWindowAttributes at; XModifierKeymap *modmap; int i, j; char fontbuf[128]; /* FIRST INIT */ gc = DefaultGC (dpy, screen); screen = DefaultScreen (dpy); root = RootWindow (dpy, screen); mw = DisplayWidth (dpy, screen); mh = DisplayHeight (dpy, screen); /* INIT TAG / LAYOUT ATTRIBUTE */ taglen[0] = 3; seltag = 1; for(i = 0; i < conf.ntag + 1; ++i) tags[i] = conf.tag[i - 1]; /* INIT FONT */ /* make the font string with * the configuration information */ sprintf(fontbuf, "*-%s-%s-*-%d-*", conf.font.face, conf.font.style, conf.font.size); font = XLoadQueryFont(dpy, fontbuf); if(!font) { fprintf(stderr, "XLoadQueryFont: failed loading font '%s'\n" "Load the default font.\n", fontbuf); font = XLoadQueryFont(dpy, "*-*-*-*-12-*"); } XSetFont(dpy, gc, font->fid); fonth = (font->ascent + font->descent) - 1; barheight = fonth + 3; /* INIT CURSOR */ cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); /* INIT MODIFIER */ 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); /* INIT ATOM */ wm_atom[WMState] = XInternAtom(dpy, "WM_STATE", False); wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32, PropModeReplace, (unsigned char *) net_atom, NetLast); /* INIT ROOT */ at.event_mask = KeyMask | ButtonPressMask | ButtonReleaseMask | SubstructureRedirectMask | SubstructureNotifyMask | EnterWindowMask | LeaveWindowMask | StructureNotifyMask ; at.cursor = cursor[CurNormal]; XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &at); /* INIT BAR / BUTTON */ bary = (conf.bartop) ? 0 : mh - barheight; dr = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), barheight, DefaultDepth(dpy, screen)); at.override_redirect = 1; at.background_pixmap = ParentRelative; at.event_mask = ButtonPressMask | ExposureMask; bar = XCreateWindow(dpy, root, 0, bary, mw, barheight, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect | CWBackPixmap | CWEventMask, &at); XMapRaised(dpy, bar); strcpy(bartext, WMFS_VERSION); updatebutton(False); updatebar(); /* INIT STUFF */ XSetErrorHandler(errorhandler); grabkeys(); return; } Bool ishide(Client *c) { int i; for(i = 0; i < conf.ntag + 1; ++i) if(c->tag == i && seltag == i) return False; return True; } void uicb_killclient(char *cmd) { XEvent ev; if(!sel) return; ev.type = ClientMessage; ev.xclient.window = sel->win; ev.xclient.message_type = wm_atom[WMProtocols]; ev.xclient.format = 32; ev.xclient.data.l[0] = wm_atom[WMDelete]; ev.xclient.data.l[1] = CurrentTime; XSendEvent(dpy, sel->win, False, NoEventMask, &ev); return; } void mainloop(void) { fd_set fd; char sbuf[sizeof bartext], *p; int len, r, offset = 0; Bool readstdin = True; len = sizeof bartext - 1; sbuf[len] = bartext[len] = '\0'; while(!exiting) { FD_ZERO(&fd); if(readstdin) FD_SET(STDIN_FILENO, &fd); FD_SET(ConnectionNumber(dpy), &fd); if(select(ConnectionNumber(dpy) + 1, &fd, NULL, NULL, NULL) == -1) printf("WMFS Warning: Select failed\n"); if(FD_ISSET(STDIN_FILENO, &fd)) { if((r = read(STDIN_FILENO, sbuf + offset, len - offset))) { for(p = sbuf + offset; r > 0; ++p, --r, ++offset) { if(*p == '\n') { *p = '\0'; strncpy(bartext, sbuf, len); p += r - 1; for(r = 0; *(p - r) && *(p - r) != '\n'; ++r); offset = r; if(r) memmove(sbuf, p - r + 1, r); break; } } } else { strncpy(bartext, sbuf, strlen(sbuf)); readstdin = False; } updatebar(); } while(XPending(dpy)) { XNextEvent(dpy, &event); getevent(); } } return; } void mapclient(Client *c) { if(!c) return; XMapWindow(dpy, c->win); XMapSubwindows(dpy, c->win); if(conf.ttbarheight) { XMapWindow(dpy, c->tbar); if(conf.ttbarheight > 5) XMapWindow(dpy, c->button); } return; } void manage(Window w, XWindowAttributes *wa) { Client *c, *t = NULL; Window trans; Status rettrans; XWindowChanges winc; c = emalloc(1, sizeof(Client)); c->win = w; c->x = wa->x; c->y = wa->y + conf.ttbarheight + barheight; c->w = wa->width; c->h = wa->height; c->tag = seltag; /* Create titlebar & button */ if(conf.ttbarheight) { c->tbar = XCreateSimpleWindow(dpy, root, c->x, c->y - conf.ttbarheight, c->w, conf.ttbarheight, conf.borderheight, conf.colors.bordernormal, conf.colors.bar); XSelectInput(dpy, c->tbar, ExposureMask | EnterWindowMask); if(conf.ttbarheight > 5) c->button = XCreateSimpleWindow(dpy, root, BUTX(c->x, c->w), BUTY(c->y), ((BUTH) ? BUTH : 1), ((BUTH) ? BUTH : 1), 1, conf.colors.bordernormal, conf.colors.borderfocus); } XConfigureWindow(dpy, w, CWBorderWidth, &winc); setborder(w, conf.colors.bordernormal); grabbuttons(c, False); XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask); setsizehints(c); updatetitle(c); if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success)) for(t = clients; t && t->win != trans; t = t->next); if(t) c->tag = t->tag; if(!c->free) c->free = (rettrans == Success) || c->hint; if(c->free) raiseclient(c); attach(c); XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); mapclient(c); setwinstate(c->win, NormalState); arrange(); return; } /* If the type is 0, this function will move, else, * this will resize */ void mouseaction(Client *c, int x, int y, int type) { int ocx, ocy; XEvent ev; if(c->max || c->tile || c->lmax) return; ocx = c->x; ocy = c->y; if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync, None, cursor[((type) ?CurResize:CurMove)], CurrentTime) != GrabSuccess) return; if(type) XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h); for(;;) { XMaskEvent(dpy, MouseMask | ExposureMask | SubstructureRedirectMask, &ev); if(ev.type == ButtonRelease) { if(type) XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h); XUngrabPointer(dpy, CurrentTime); return; } else if(ev.type == MotionNotify) { XSync(dpy, False); /* Resize */ if(type) moveresize(c, c->x, c->y, ((ev.xmotion.x - ocx <= 0) ? 1 : ev.xmotion.x - ocx), ((ev.xmotion.y - ocy <= 0) ? 1 : ev.xmotion.y - ocy), True); /* Move */ else moveresize(c, (ocx + (ev.xmotion.x - x)), (ocy + (ev.xmotion.y - y)), c->w, c->h, True); /* for don't pass on the bar */ if(conf.bartop && c->y < barheight + conf.ttbarheight - 5) { moveresize(c, c->x, barheight + conf.ttbarheight, c->w, c->h, True); XUngrabPointer(dpy, CurrentTime); return; } else if(!conf.bartop && c->y + c->h > bary + 3) { moveresize(c, c->x, bary - c->h, c->w, c->h, True); XUngrabPointer(dpy, CurrentTime); return; } } } return; } void moveresize(Client *c, int x, int y, int w, int h, bool r) { if(!c) return; /* Resize hints {{{ */ if(r) { /* minimum possible */ if (w < 1) w = 1; if (h < 1) h = 1; /* base */ w -= c->basew; h -= c->baseh; /* aspect */ if (c->minay > 0 && c->maxay > 0 && c->minax > 0 && c->maxax > 0) { if (w * c->maxay > h * c->maxax) w = h * c->maxax / c->maxay; else if (w * c->minay < h * c->minax) h = w * c->minay / c->minax; } /* incremental */ if(c->incw) w -= w % c->incw; if(c->inch) h -= h % c->inch; /* base dimension */ w += c->basew; h += c->baseh; if(c->minw > 0 && w < c->minw) w = c->minw; if(c->minh > 0 && h < c->minh) h = c->minh; if(c->maxw > 0 && w > c->maxw) w = c->maxw; if(c->maxh > 0 && h > c->maxh) h = c->maxh; if(w <= 0 || h <= 0) return; } /* }}} */ c->max = False; if(c->x != x || c->y != y || c->w != w || c->h != h) { c->x = x; c->y = y; c->w = w; c->h = h; if(conf.bartop) { if((y - conf.ttbarheight) <= barheight) y = barheight+conf.ttbarheight; } else if(y - h >= bary) y = bary - h; XMoveResizeWindow(dpy, c->win, x, y, w ,h); if(conf.ttbarheight) { XMoveResizeWindow(dpy, c->tbar, x, y - conf.ttbarheight, w, conf.ttbarheight); if(conf.ttbarheight > 5) XMoveWindow(dpy, c->button, BUTX(x, w), BUTY(y)); } updateall(); XSync(dpy, False); } return; } void uicb_quit(char *cmd) { exiting = True; return; } void raiseclient(Client *c) { if(!c) return; XRaiseWindow(dpy, c->win); if(conf.ttbarheight) { XRaiseWindow(dpy, c->tbar); if(conf.ttbarheight > 5) XRaiseWindow(dpy, c->button); } return; } /* scan all the client who was in X before wmfs */ 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)) continue; if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) continue; if(wa.map_state == IsViewable) manage(wins[i], &wa); } } if(wins) XFree(wins); arrange(); return; } void setborder(Window win, int color) { XSetWindowBorder(dpy, win, color); XSetWindowBorderWidth(dpy, win, conf.borderheight); return; } void setwinstate(Window win, long state) { long data[] = {state, None}; XChangeProperty(dpy, win, wm_atom[WMState], wm_atom[WMState], 32, PropModeReplace, (unsigned char *)data, 2); return; } void setsizehints(Client *c) { long msize; XSizeHints size; if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags) size.flags = PSize; /* base */ 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; /* inc */ if(size.flags & PResizeInc) { c->incw = size.width_inc; c->inch = size.height_inc; } else c->incw = c->inch = 0; /* max */ if(size.flags & PMaxSize) { c->maxw = size.max_width; c->maxh = size.max_height; } else c->maxw = c->maxh = 0; /* min */ 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; /* aspect */ if(size.flags & PAspect) { c->minax = size.min_aspect.x; c->maxax = size.max_aspect.x; c->minay = size.min_aspect.y; c->maxay = size.max_aspect.y; } else c->minax = c->maxax = c->minay = c->maxay = 0; c->hint = (c->maxw && c->minw && c->maxh && c->minh && c->maxw == c->minw && c->maxh == c->minh); return; } void uicb_togglebarpos(char *cmd) { int i; conf.bartop = !conf.bartop; if(conf.bartop) bary = 0; else bary = mh - barheight; XMoveWindow(dpy, bar, 0, bary); updatebar(); for(i = 0; i < conf.nbutton; ++i) XUnmapWindow(dpy, conf.barbutton[i].win); updatebutton(0); for(i = 0; i < conf.nbutton; ++i) XMapWindow(dpy, conf.barbutton[i].win); arrange(); return; } void unhide(Client *c) { if(!c) return; XMoveWindow(dpy, c->win, c->x, c->y); if(conf.ttbarheight) { XMoveWindow(dpy, c->tbar, c->x, (c->y - conf.ttbarheight)); if(conf.ttbarheight > 5) XMoveWindow(dpy, c->button, BUTX(c->x, c->w), BUTY(c->y)); } setwinstate(c->win, NormalState); c->hide = False; return; } void unmanage(Client *c) { XGrabServer(dpy); XSetErrorHandler(errorhandlerdummy); sel = ((sel == c) ? ((c->next) ? c->next : NULL) : NULL); detach(c); if(conf.ttbarheight) { XUnmapWindow(dpy, c->tbar); XDestroyWindow(dpy, c->tbar); if(conf.ttbarheight > 5) { XUnmapWindow(dpy, c->button); XDestroyWindow(dpy, c->button); } } setwinstate(c->win, WithdrawnState); free(c); XSync(dpy, False); XUngrabServer(dpy); arrange(); return; } void updateall(void) { Client *c; for(c = clients; c; c = c->next) if(!ishide(c)) updatetitle(c); return; } void updatebar(void) { int i , k; char buf[conf.ntag][256]; char p[4]; XSetForeground(dpy, gc, conf.colors.bar); XFillRectangle(dpy, dr, gc, 0, 0, mw, barheight); for(i = 0; i < conf.ntag; ++i) { /* Make the tags string */ ITOA(p, clientpertag(i+1)); sprintf(buf[i], "%s<%s> ", tags[i+1].name, (clientpertag(i+1)) ? p : ""); taglen[i+1] = taglen[i] + TEXTW(buf[i]); /* Rectangle for the tag background */ XSetForeground(dpy, gc, (i+1 == seltag) ? conf.colors.tagselbg : conf.colors.bar); XFillRectangle(dpy, dr, gc, taglen[i] - 3, 0, TEXTW(buf[i]) - 3, barheight); /* Draw tag */ XSetForeground(dpy, gc, (i+1 == seltag) ? conf.colors.tagselfg : conf.colors.text); XDrawString(dpy, dr, gc, taglen[i], fonth, buf[i], strlen(buf[i])); } /* Draw layout symbol */ XSetForeground(dpy, gc, conf.colors.layout_bg); XFillRectangle(dpy, dr, gc, taglen[conf.ntag] - 5, 0, TEXTW(strdup(tags[seltag].layout.symbol)), barheight); XSetForeground(dpy, gc, conf.colors.layout_fg); XDrawString(dpy, dr, gc, taglen[conf.ntag] - 4, fonth, tags[seltag].layout.symbol, strlen(tags[seltag].layout.symbol)); /* Draw status */ k = TEXTW(bartext); XSetForeground(dpy, gc, conf.colors.text); XDrawString(dpy, dr, gc, mw - k, fonth-1, bartext, strlen(bartext)); XDrawLine(dpy, dr, gc, mw-k-5, 0, mw-k-5, barheight); XCopyArea(dpy, dr, bar, gc, 0, 0, mw, barheight, 0, 0); XSync(dpy, False); /* Update Bar Buttons */ updatebutton(True); return; } /* if c is False, you can execute this function for the first time * else the button is just updated */ void updatebutton(Bool c) { int i, j, p, x, pm = 0; XSetWindowAttributes at; int y = 3; int h = barheight - 5; int fonth_l = fonth - 3; at.override_redirect = 1; at.background_pixmap = ParentRelative; at.event_mask = ButtonPressMask | ExposureMask; j = taglen[conf.ntag] + TEXTW(tags[seltag].layout.symbol); if(!conf.bartop) y = bary + 3; for(i = 0; i < conf.nbutton; ++i) { p = TEXTW(conf.barbutton[i].text); if(!conf.barbutton[i].x) { if(i) pm += TEXTW(conf.barbutton[i-1].text); x = (!i) ? j : j + pm; } else x = conf.barbutton[i].x; if(!c) { conf.barbutton[i].win = XCreateWindow(dpy, root, x, y, p, h, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect | CWBackPixmap | CWEventMask, &at); XSetWindowBackground(dpy, conf.barbutton[i].win, conf.barbutton[i].bg_color); XMapRaised(dpy, conf.barbutton[i].win); XSetForeground(dpy, gc, conf.barbutton[i].fg_color); XDrawString(dpy, conf.barbutton[i].win, gc, 1, fonth_l, conf.barbutton[i].text, p); } else { if(!conf.barbutton[i].win) return; XSetForeground(dpy, gc, conf.barbutton[i].fg_color); XMoveWindow(dpy, conf.barbutton[i].win, x, y); XDrawString(dpy, conf.barbutton[i].win, gc, 1, fonth_l, conf.barbutton[i].text, strlen(conf.barbutton[i].text)); } } XSync(dpy, False); return; } void unmapclient(Client *c) { if(!c) return; XUnmapWindow(dpy, c->win); if(conf.ttbarheight) { XUnmapWindow(dpy, c->tbar); if(conf.ttbarheight > 5) XUnmapWindow(dpy, c->button); } XUnmapSubwindows(dpy, c->win); return; } void updatetitle(Client *c) { XFetchName(dpy, c->win, &(c->title)); if(!c->title) c->title = strdup("WMFS"); if(conf.ttbarheight > 10) { XClearWindow(dpy, c->tbar); XSetForeground(dpy, gc, conf.colors.text); XDrawString(dpy, c->tbar, gc, 3, ((fonth-2) + ((conf.ttbarheight - fonth) / 2)), c->title, strlen(c->title)); } return; } int main(int argc, char **argv) { dpy = XOpenDisplay(NULL); int i; static struct option long_options[] = { {"help", 0, NULL, 'h'}, {"info", 0, NULL, 'i'}, {"version", 0, NULL, 'v'}, {NULL, 0, NULL, 0} }; while ((i = getopt_long (argc, argv, "hvi", long_options, NULL)) != -1) { switch (i) { case 'h': default: printf("Usage: wmfs [OPTION]\n" " -h, --help show this page\n" " -i, --info show informations\n" " -v, --version show WMFS version\n"); exit(EXIT_SUCCESS); break; case 'i': printf("WMFS - Window Manager From Scratch. By :\n" " - Martin Duquesnoy (code)\n" " - Marc Lagrange (build system)\n"); exit(EXIT_SUCCESS); break; case 'v': printf("WMFS version : "WMFS_VERSION".\n" " Compilation settings :\n" " - Flags : "WMFS_COMPILE_FLAGS"\n" " - Linked Libs : "WMFS_LINKED_LIBS"\n" " - On "WMFS_COMPILE_MACHINE" by "WMFS_COMPILE_BY".\n"); exit(EXIT_SUCCESS); break; } } if(!dpy) { printf("WMFS: cannot open X server.\n"); exit(EXIT_FAILURE); } /* Let's Go ! */ init_conf(); init(); scan(); mainloop(); /* Exiting WMFS :'( */ XFreeFont(dpy, font); XUngrabKey(dpy, AnyKey, AnyModifier, root); XFreeCursor(dpy, cursor[CurNormal]); XFreeCursor(dpy, cursor[CurMove]); XFreeCursor(dpy, cursor[CurResize]); XDestroyWindow(dpy, bar); if(conf.nbutton) for(i = 0; i < conf.nbutton; ++i) XDestroyWindow(dpy, conf.barbutton[i].win); XSync(dpy, False); XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); XCloseDisplay(dpy); exit(EXIT_SUCCESS); }