diff --git a/CMakeLists.txt b/CMakeLists.txt index 05eb135..b5224f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,8 @@ set(wmfs_src layout.c tag.c bar.c - draw.c) + draw.c + client.c) # Set the executable from the wmfs_src add_executable(wmfs ${wmfs_src}) diff --git a/client.c b/client.c new file mode 100644 index 0000000..0801ee8 --- /dev/null +++ b/client.c @@ -0,0 +1,498 @@ +/* +* client.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" + +int +clientpertag(int tag) +{ + Client *c; + int i = 0; + + for(c = clients; c; c = c->next) + if(c->tag == tag) + ++i; + return i; +} + +void +client_attach(Client *c) +{ + if(clients) + clients->prev = c; + c->next = clients; + clients = c; + + return; +} + +void +client_detach(Client *c) +{ + Client **cc; + + for(cc = &clients; *cc && *cc != c; cc = &(*cc)->next); + *cc = c->next; + + return; +} + +/* 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) + { + client_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) + { + client_focus(c); + if(!c->tile) + raiseclient(c); + } + } + arrange(); + + return; +} + +void +uicb_client_prev(uicb_t cmd) +{ + client_switch(False); + + return; +} + +void +uicb_client_next(uicb_t cmd) +{ + client_switch(True); + + return; +} + +void +client_focus(Client *c) +{ + Client *cc; + + if(sel && sel != c) + { + grabbuttons(sel, False); + draw_border(sel->win, conf.colors.bordernormal); + if(conf.ttbarheight) + draw_border(sel->tbar->win, conf.colors.bordernormal); + + } + if(c) + grabbuttons(c, True); + + sel = c; + selbytag[seltag] = sel; + + if(c) + { + draw_border(c->win, conf.colors.borderfocus); + if(conf.ttbarheight) + draw_border(c->tbar->win, conf.colors.borderfocus); + if(conf.raisefocus) + raiseclient(c); + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + updatetitlebar(c); + } + else + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + + for(cc = clients; cc; cc = cc->next) + if(!ishide(cc)) + updatetitlebar(cc); + + return; +} + +Client* +getclient(Window w) +{ + Client *c; + + for(c = clients; c && c->win != w; c = c->next); + + return c; +} + +Client* +client_gettbar(Window w) +{ + Client *c; + + if(!conf.ttbarheight) + return NULL; + + for(c = clients; c && c->tbar->win != w; c = c->next); + + return c; +} + +void +client_hide(Client *c) +{ + if(!c) + return; + + XMoveWindow(dpy, c->win, c->x, c->y+mh*2); + if(conf.ttbarheight) + bar_moveresize(c->tbar, c->x, c->y+mh*2, c->w, c->h); + + //unmapclient(c); + setwinstate(c->win, IconicState); + c->hide = True; + + 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(uicb_t 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 +mapclient(Client *c) +{ + if(!c) + return; + + XMapWindow(dpy, c->win); + if(conf.ttbarheight) + { + XMapWindow(dpy, c->tbar->win); + bar_refresh(c->tbar); + } + + return; +} + +void +client_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 */ + if(conf.ttbarheight) + c->tbar = bar_create(c->x, c->y - conf.ttbarheight, + c->w, conf.ttbarheight, conf.borderheight, + conf.colors.bar, True); + + XConfigureWindow(dpy, w, CWBorderWidth, &winc); + draw_border(w, conf.colors.bordernormal); + grabbuttons(c, False); + XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask + | PropertyChangeMask | StructureNotifyMask); + client_size_hints(c); + updatetitlebar(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; + else + raiseclient(c); + + client_attach(c); + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + mapclient(c); + setwinstate(c->win, NormalState); + client_focus(c); + arrange(); + + return; +} + +void +client_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; + + XMoveResizeWindow(dpy, c->win, x, y, w ,h); + + if(conf.ttbarheight) + bar_moveresize(c->tbar, x, y - conf.ttbarheight, w, conf.ttbarheight); + + updatetitlebar(c); + XSync(dpy, False); + } + + return; +} + +void +client_size_hints(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 +raiseclient(Client *c) +{ + if(!c) + return; + XRaiseWindow(dpy, c->win); + + if(conf.ttbarheight) + { + XRaiseWindow(dpy, c->tbar->win); + updatetitlebar(c); + } + + return; +} + +void +client_unhide(Client *c) +{ + if(!c) + return; + XMoveWindow(dpy, c->win, c->x, c->y); + if(conf.ttbarheight) + bar_moveresize(c->tbar, c->x, c->y - conf.ttbarheight, c->w, conf.ttbarheight); + + //mapclient(c); + setwinstate(c->win, NormalState); + c->hide = False; + + return; +} + +void +client_unmanage(Client *c) +{ + XGrabServer(dpy); + XSetErrorHandler(errorhandlerdummy); + sel = ((sel == c) ? ((c->next) ? c->next : NULL) : NULL); + if(sel && sel->tag == seltag) + selbytag[seltag] = sel; + else + selbytag[seltag] = NULL; + client_detach(c); + if(conf.ttbarheight) + bar_delete(c->tbar); + + setwinstate(c->win, WithdrawnState); + free(c); + XSync(dpy, False); + XUngrabServer(dpy); + arrange(); + + return; +} + +void +unmapclient(Client *c) +{ + if(!c) + return; + + XUnmapWindow(dpy, c->win); + if(conf.ttbarheight) + XUnmapWindow(dpy, c->tbar->win); + + return; +} diff --git a/config.c b/config.c index ff759bf..83f4345 100644 --- a/config.c +++ b/config.c @@ -31,7 +31,6 @@ */ #include "wmfs.h" -#include "structs.h" #define FILE_NAME ".config/wmfs/wmfsrc" @@ -185,8 +184,6 @@ init_conf(void) CFG_STR("layout_bg", "#292929", CFGF_NONE), CFG_STR("titlebar_text_focus", "#FFFFFF", CFGF_NONE), CFG_STR("titlebar_text_normal", "#FFFFFF", CFGF_NONE), - CFG_STR("button", "#6286A1", CFGF_NONE), - CFG_STR("button_border", "#354B5C", CFGF_NONE), CFG_END() }; @@ -354,9 +351,6 @@ init_conf(void) conf.colors.layout_bg = getcolor(var_to_str(cfg_getstr(cfg_colors, "layout_bg"))); conf.colors.ttbar_text_focus = strdup(var_to_str(cfg_getstr(cfg_colors, "titlebar_text_focus"))); conf.colors.ttbar_text_normal = strdup(var_to_str(cfg_getstr(cfg_colors, "titlebar_text_normal"))); - conf.colors.button = getcolor(var_to_str(cfg_getstr(cfg_colors, "button"))); - conf.colors.button_border = getcolor(var_to_str(cfg_getstr(cfg_colors, "button_border"))); - /* layout */ if((conf.nlayout = cfg_size(cfg_layouts, "layout")) > MAXLAYOUT diff --git a/draw.c b/draw.c index 5208aa6..c329d2d 100644 --- a/draw.c +++ b/draw.c @@ -152,6 +152,18 @@ get_image_attribute(char *file) return ret; } +void +draw_border(Window win, int color) +{ + if(!win) + return; + + XSetWindowBorder(dpy, win, color); + XSetWindowBorderWidth(dpy, win, conf.borderheight); + + return; +} + ushort textw(const char *text) { diff --git a/event.c b/event.c index 1da6af0..e427e78 100644 --- a/event.c +++ b/event.c @@ -49,7 +49,7 @@ buttonpress(XEvent ev) /* TITLEBAR */ /* ******** */ { - if((c = gettbar(ev.xbutton.window))) + if((c = client_gettbar(ev.xbutton.window))) { raiseclient(c); /* BUTTON 1 */ @@ -76,32 +76,6 @@ buttonpress(XEvent ev) } - /* ****** */ - /* BUTTON */ - /* ****** */ - { - if((c = getbutton(ev.xbutton.window))) - { - /* BUTTON 1 */ - { - if(ev.xbutton.button == Button1) - uicb_killclient(NULL); - } - /* BUTTON 2 AND 3 */ - { - if(ev.xbutton.button == Button2 - || ev.xbutton.button == Button3) - { - if(tags[seltag].layout.func == tile) - uicb_tile_switch(NULL); - else - uicb_togglemax(NULL); - } - } - } - - } - } /* ****** */ @@ -266,7 +240,7 @@ configurerequest(XEvent ev) ev.xconfigurerequest.value_mask, &wc); if((c = getclient(ev.xconfigurerequest.window))) if(wc.y < mw && wc.x < mh) - moveresize(c, wc.x, wc.y, wc.width, wc.height, True); + client_moveresize(c, wc.x, wc.y, wc.width, wc.height, True); return; } @@ -278,9 +252,9 @@ destroynotify(XEvent ev) Client *c; if((c = getclient(ev.xdestroywindow.window))) - unmanage(c); + client_unmanage(c); - return; + return; } /* ENTERNOTIFY */ @@ -293,10 +267,10 @@ enternotify(XEvent ev) || ev.xcrossing.detail == NotifyInferior) return; if((c = getclient(ev.xcrossing.window)) - || (c = gettbar(ev.xcrossing.window))) - focus(c); + || (c = client_gettbar(ev.xcrossing.window))) + client_focus(c); else - focus(NULL); + client_focus(NULL); return; } @@ -329,6 +303,47 @@ focusin(XEvent ev) return; } +void +grabbuttons(Client *c, Bool focused) +{ + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + + 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); + } + else + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); + + return; +} + +void +grabkeys(void) +{ + uint 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; +} + + /* KEYPRESS */ void keypress(XEvent ev) @@ -370,8 +385,59 @@ maprequest(XEvent ev) return; if(!getclient(ev.xmaprequest.window)) { - focus(NULL); - manage(ev.xmaprequest.window, &at); + client_focus(NULL); + client_manage(ev.xmaprequest.window, &at); + } + + 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); + updatebar(); + return; + } + else if(ev.type == MotionNotify) + { + XSync(dpy, False); + /* Resize */ + if(type) + client_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 + client_moveresize(c, (ocx + (ev.xmotion.x - x)), + (ocy + (ev.xmotion.y - y)), + c->w, c->h, True); + } + else if(ev.type == Expose) + expose(ev); } return; @@ -397,7 +463,7 @@ propertynotify(XEvent ev) arrange(); break; case XA_WM_NORMAL_HINTS: - setsizehints(c); + client_size_hints(c); break; } if(ev.xproperty.atom == XA_WM_NAME @@ -416,7 +482,7 @@ unmapnotify(XEvent ev) if((c = getclient(ev.xunmap.window))) if(!c->hide) - unmanage(c); + client_unmanage(c); return; } diff --git a/layout.c b/layout.c index 5e9fb1c..0bb186d 100644 --- a/layout.c +++ b/layout.c @@ -32,6 +32,30 @@ #include "wmfs.h" +void +arrange(void) +{ + Client *c; + + for(c = clients; c; c = c->next) + if(!ishide(c)) + client_unhide(c); + else + client_hide(c); + + if(sel) + tags[seltag].layout.func(); + + if(selbytag[seltag]) + client_focus(selbytag[seltag]); + else + client_focus(NULL); + + updatebar(); + + return; +} + void freelayout(void) { @@ -43,7 +67,7 @@ freelayout(void) { if(c->tile || c->lmax) { - moveresize(c, c->ox, c->oy, c->ow, c->oh, True); + client_moveresize(c, c->ox, c->oy, c->ow, c->oh, True); c->tile = False; c->lmax = False; } @@ -103,7 +127,7 @@ maxlayout(void) c->ox = c->x; c->oy = c->y; c->ow = c->w; c->oh = c->h; - moveresize(c, 0, (conf.ttbarheight + ((conf.bartop) ? barheight : 0)), + client_moveresize(c, 0, (conf.ttbarheight + ((conf.bartop) ? barheight : 0)), (mw - (conf.borderheight * 2)), (mh - (conf.borderheight * 2) - conf.ttbarheight - barheight), False); @@ -218,7 +242,7 @@ tile(void) else h = th - (bord + conf.ttbarheight) - bord*2; } - moveresize(c, x, y, w, h, tags[seltag].resizehint); + client_moveresize(c, x, y, w, h, tags[seltag].resizehint); if(n > nm && th != mht) y = c->y + c->h + bord + conf.ttbarheight; } @@ -236,9 +260,9 @@ uicb_tile_switch(uicb_t cmd) if((c = sel) == nexttiled(clients)) if(!(c = nexttiled(c->next))) return; - detach(c); - attach(c); - focus(c); + client_detach(c); + client_attach(c); + client_focus(c); arrange(); return; @@ -253,15 +277,15 @@ uicb_togglemax(uicb_t cmd) { sel->ox = sel->x; sel->oy = sel->y; sel->ow = sel->w; sel->oh = sel->h; - moveresize(sel, 0, (conf.ttbarheight + ((conf.bartop) ? barheight: 0)), - (mw - (conf.borderheight * 2)), - (mh - (conf.borderheight * 2)- conf.ttbarheight - barheight), False); + client_moveresize(sel, 0, (conf.ttbarheight + ((conf.bartop) ? barheight: 0)), + (mw - (conf.borderheight * 2)), + (mh - (conf.borderheight * 2)- conf.ttbarheight - barheight), False); raiseclient(sel); sel->max = True; } else if(sel->max) { - moveresize(sel, sel->ox, sel->oy, sel->ow, sel->oh, False); + client_moveresize(sel, sel->ox, sel->oy, sel->ow, sel->oh, False); sel->max = False; } arrange(); @@ -269,3 +293,4 @@ uicb_togglemax(uicb_t cmd) return; } + diff --git a/structs.h b/structs.h index 1900e0f..43f3d54 100644 --- a/structs.h +++ b/structs.h @@ -79,8 +79,6 @@ struct Client Window win; /* Titlebar */ BarWindow *tbar; - /* Titlebar Button */ - Window button; /* Client Layout Information */ Bool max, tile, free; Bool hint, hide, lmax; @@ -157,8 +155,6 @@ typedef struct uint layout_bg; char *ttbar_text_focus; char *ttbar_text_normal; - uint button; - uint button_border; } colors; Tag tag[MAXTAG]; Layout layout[MAXLAYOUT]; diff --git a/util.c b/util.c index 26c3522..1e2b9a4 100644 --- a/util.c +++ b/util.c @@ -53,6 +53,17 @@ getcolor(char *color) return xcolor.pixel; } +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 uicb_spawn(uicb_t cmd) { diff --git a/wmfs.c b/wmfs.c index 35f4702..27c1395 100644 --- a/wmfs.c +++ b/wmfs.c @@ -32,123 +32,6 @@ #include "wmfs.h" -void -arrange(void) -{ - Client *c; - - for(c = clients; c; c = c->next) - if(!ishide(c)) - unhide(c); - else - hide(c); - - if(sel) - tags[seltag].layout.func(); - - if(selbytag[seltag]) - focus(selbytag[seltag]); - else - focus(NULL); - - 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); - } - } - arrange(); - - return; -} - -void -uicb_client_prev(uicb_t cmd) -{ - client_switch(False); - - return; -} - -void -uicb_client_next(uicb_t 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) { @@ -171,146 +54,6 @@ errorhandlerdummy(Display *d, XErrorEvent *event) return 0; } -void -focus(Client *c) -{ - Client *cc; - - if(sel && sel != c) - { - grabbuttons(sel, False); - setborder(sel->win, conf.colors.bordernormal); - if(conf.ttbarheight) - setborder(sel->tbar->win, conf.colors.bordernormal); - - } - if(c) - grabbuttons(c, True); - - sel = c; - selbytag[seltag] = sel; - - if(c) - { - setborder(c->win, conf.colors.borderfocus); - if(conf.ttbarheight) - setborder(c->tbar->win, conf.colors.borderfocus); - if(conf.raisefocus) - raiseclient(c); - XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); - updatetitlebar(c); - } - else - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); - - for(cc = clients; cc; cc = cc->next) - if(!ishide(cc)) - updatetitlebar(cc); - - 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; - - if(!conf.ttbarheight) - return NULL; - - for(c = clients; c && c->tbar->win != w; c = c->next); - - return c; -} - -void -grabbuttons(Client *c, Bool focused) -{ - XUngrabButton(dpy, AnyButton, AnyModifier, c->win); - - 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); - } - else - XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); - - return; -} - -void -grabkeys(void) -{ - uint 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) - { - bar_moveresize(c->tbar, c->x, c->y+mh*2, c->w, c->h); - if(conf.ttbarheight > 5) - XMoveWindow(dpy, c->button, c->x, c->y+mh*2); - } - //unmapclient(c); - setwinstate(c->win, IconicState); - c->hide = True; - - return; -} - void init(void) { @@ -386,36 +129,6 @@ init(void) 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(uicb_t 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) { @@ -471,202 +184,6 @@ mainloop(void) return; } -void -mapclient(Client *c) -{ - if(!c) - return; - - XMapWindow(dpy, c->win); - if(conf.ttbarheight) - { - XMapWindow(dpy, c->tbar->win); - bar_refresh(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 = bar_create(c->x, c->y - conf.ttbarheight, - c->w, conf.ttbarheight, conf.borderheight, - conf.colors.bar, True); - - /* Basic window for close button... */ - 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.button_border, - conf.colors.button); - } - - XConfigureWindow(dpy, w, CWBorderWidth, &winc); - setborder(w, conf.colors.bordernormal); - grabbuttons(c, False); - XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask - | PropertyChangeMask | StructureNotifyMask); - setsizehints(c); - updatetitlebar(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; - else - raiseclient(c); - - attach(c); - XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); - mapclient(c); - setwinstate(c->win, NormalState); - focus(c); - 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); - updatebar(); - 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); - } - else if(ev.type == Expose) - expose(ev); - } - - 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; - - XMoveResizeWindow(dpy, c->win, x, y, w ,h); - - if(conf.ttbarheight) - { - bar_moveresize(c->tbar, x, y - conf.ttbarheight, w, conf.ttbarheight); - if(conf.ttbarheight > 5) - XMoveWindow(dpy, c->button, BUTX(x, w), BUTY(y)); - } - updatetitlebar(c); - XSync(dpy, False); - } - - return; -} - void uicb_quit(uicb_t cmd) { @@ -675,24 +192,6 @@ uicb_quit(uicb_t cmd) return; } -void -raiseclient(Client *c) -{ - if(!c) - return; - XRaiseWindow(dpy, c->win); - - if(conf.ttbarheight) - { - XRaiseWindow(dpy, c->tbar->win); - if(conf.ttbarheight > 5) - XRaiseWindow(dpy, c->button); - updatetitlebar(c); - } - - return; -} - /* scan all the client who was in X before wmfs */ void scan(void) @@ -711,7 +210,7 @@ scan(void) if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) continue; if(wa.map_state == IsViewable) - manage(wins[i], &wa); + client_manage(wins[i], &wa); } } if(wins) @@ -722,160 +221,6 @@ scan(void) return; } -void -setborder(Window win, int color) -{ - if(!win) - return; - - 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 -unhide(Client *c) -{ - if(!c) - return; - XMoveWindow(dpy, c->win, c->x, c->y); - if(conf.ttbarheight) - { - bar_moveresize(c->tbar, c->x, c->y - conf.ttbarheight, c->w, conf.ttbarheight); - if(conf.ttbarheight > 5) - XMoveWindow(dpy, c->button, BUTX(c->x, c->w), BUTY(c->y)); - } - //mapclient(c); - 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); - if(sel && sel->tag == seltag) - selbytag[seltag] = sel; - else - selbytag[seltag] = NULL; - detach(c); - if(conf.ttbarheight) - { - bar_delete(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 -unmapclient(Client *c) -{ - if(!c) - return; - - XUnmapWindow(dpy, c->win); - if(conf.ttbarheight) - { - XUnmapWindow(dpy, c->tbar->win); - if(conf.ttbarheight > 5) - XUnmapWindow(dpy, c->button); - } - - return; -} - int main(int argc, char **argv) { diff --git a/wmfs.h b/wmfs.h index 51595eb..76d8e52 100644 --- a/wmfs.h +++ b/wmfs.h @@ -64,9 +64,6 @@ #define ALT Mod1Mask #define ITOA(p ,n) sprintf(p, "%i", n) #define debug(p) fprintf(stderr, "debug: %i\n", p) -#define BUTY(y) y - conf.ttbarheight + 3 -#define BUTH conf.ttbarheight - 6 -#define BUTX(x, w) x + w - BUTH/400 #define PAD 8 #define BPAD 2 @@ -88,8 +85,31 @@ void draw_taglist(Drawable dr); void draw_layout(int x, int y); void draw_rectangle(Drawable dr, int x, int y, uint w, uint h, uint color); XImage* get_image_attribute(char *file); +void draw_border(Window win, int color); ushort textw(const char *text); +/* client.c */ +int clientpertag(int tag); +void client_attach(Client *c); +void client_detach(Client *c); +void client_switch(Bool c); +void client_focus(Client *c); +Client *getclient(Window w); +Client* client_gettbar(Window w); +void client_hide(Client *c); +Bool ishide(Client *c); +void mapclient(Client *c); +void client_manage(Window w, XWindowAttributes *wa); +void client_moveresize(Client *c, int x, int y, int w, int h, bool r); +void client_size_hints(Client *c); +void raiseclient(Client *c); +void client_unhide(Client *c); +void client_unmanage(Client *c); +void unmapclient(Client *c); +void uicb_client_prev(uicb_t); +void uicb_client_next(uicb_t); +void uicb_killclient(uicb_t); + /* config.c */ void init_conf(void); @@ -100,9 +120,12 @@ void destroynotify(XEvent ev); void enternotify(XEvent ev); void expose(XEvent ev); void focusin(XEvent ev); +void grabbuttons(Client *c, Bool focused); +void grabkeys(void); void keypress(XEvent ev); void mapnotify(XEvent ev); void maprequest(XEvent ev); +void mouseaction(Client *c, int x, int y, int type); void propertynotify(XEvent ev); void unmapnotify(XEvent ev); void getevent(void); @@ -110,6 +133,7 @@ void getevent(void); /* util.c */ void *emalloc(uint elemet, uint size); ulong getcolor(char *color); +void setwinstate(Window win, long state); void uicb_spawn(uicb_t); /* tag.c */ @@ -119,6 +143,7 @@ void uicb_tag_prev(uicb_t); void uicb_tagtransfert(uicb_t); /* layout.c */ +void arrange(void); void freelayout(void); void layoutswitch(Bool b); void maxlayout(void); @@ -132,39 +157,11 @@ void uicb_set_mwfact(uicb_t); void uicb_set_nmaster(uicb_t); /* wmfs.c */ -void arrange(void); -void attach(Client *c); -int clientpertag(int tag); -void client_switch(Bool c); -void detach(Client *c); int errorhandler(Display *d, XErrorEvent *event); int errorhandlerdummy(Display *d, XErrorEvent *event); -void focus(Client *c); -Client* getbutton(Window w); -Client* getclient(Window w); -Client* getnext(Client *c); -Client* gettbar(Window w); -void grabbuttons(Client *c, Bool focused); -void grabkeys(void); -void hide(Client *c); void init(void); -Bool ishide(Client *c); void mainloop(void); -void mapclient(Client *c); -void manage(Window w, XWindowAttributes *wa); -void mouseaction(Client *c, int x, int y, int type); -void moveresize(Client *c, int x, int y, int w, int h, bool r); -void raiseclient(Client *c); void scan(void); -void setborder(Window win, int color); -void setwinstate(Window win, long state); -void setsizehints(Client *c); -void unhide(Client *c); -void unmanage(Client *c); -void unmapclient(Client *c); -void uicb_client_prev(uicb_t); -void uicb_client_next(uicb_t); -void uicb_killclient(uicb_t); void uicb_quit(uicb_t); /* Variables */ diff --git a/wmfsrc b/wmfsrc index 4bdeffd..eda76dc 100644 --- a/wmfsrc +++ b/wmfsrc @@ -38,10 +38,6 @@ colors #Titlebar titlebar_text_focus = "#D4D4D4" titlebar_text_normal = "#D4D4D4" - - #Button - button = "#7E89A2" - button_border = "#3F485E" } layouts