You are not logged in.

#151 2011-01-04 10:07:31

pyknite
Member
Registered: 2010-03-03
Posts: 166

Re: catwm, Cute and Tiny Window Manager

Hi there... I'm glad that someone is still using catwm and liking it wink

I just saw these post this morning, I was skying the few last days wink

If I got the time I really want to rewrite the code with xcb... I tried a few month ago but the machine crashed hardly and I lost all the code sad

Offline

#152 2011-04-22 10:07:50

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

tOGRmbQ

I've had another play with catwm today, shifted a couple of things around, and added different tiling modes. There's horizontal, vertical and toggle the focused app fullscreen. There's keyboard shortcuts for each mode and catwm will remember each workspaces mode for the session. Default is set in the config file.
Earlier I added room for conky piped to dzen so I added which tiling mode is used for each workspace to the display. The file this is read from should be set from the config file.
I've called it catwm-0.0.2 'cause it is different to pyknites' original work but 99% of it is his work so I hope that's ok. The files are small like catwm's footprint so here they are :

/edit
    After spending a couple of hours here and there I've ended up with :
             the option for normal catwm behaviour(like the dwm attach aside patch apparently) or where the new window becomes the master, set in the config file.
             three tiling modes - horizontal, fullscreen and vertical - keyboard shortcuts for each and and catwm remembers the mode for each desktop for the session, default set in the config
             a panel height setting in the config for running conky through dzen
             I removed the writing to file bit as tiling and workspace changes are pretty stable now
I've updated the below files for how catwm is as I'm using it now.
Thanks for the fun little app pyknite smile

catwm-0.0.2.c

 /* catwm-0.0.2.c
 *
 *  ( o   o )  Made by cat...
 *  (  =^=  )
 *  (        )            ... for cat!
 *  (         )
 *  (          ))))))________________ Cute And Tiny Window Manager
 *  ______________________________________________________________________________
 *
 *  Copyright (c) 2010, Rinaldini Julien, julien.rinaldini@heig-vd.ch
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  Some changes and additions by P. Newman 24.4.11
 *     - best not to email julien if you use this... :)
 */

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/XF86keysym.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>

#define TABLENGTH(X)    (sizeof(X)/sizeof(*X))

typedef union {
    const char** com;
    const int i;
} Arg;

// Structs
struct key {
    unsigned int mod;
    KeySym keysym;
    void (*function)(const Arg arg);
    const Arg arg;
};

typedef struct client client;
struct client{
    // Prev and next client
    client *next;
    client *prev;

    // The window
    Window win;
};

typedef struct desktop desktop;
struct desktop{
    int master_size;
    int mode;
    client *head;
    client *current;
};

// Functions
static void add_window(Window w);
static void change_desktop(const Arg arg);
static void client_to_desktop(const Arg arg);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
static void decrease();
static void destroynotify(XEvent *e);
static void die(const char* e);
static unsigned long getcolor(const char* color);
static void grabkeys();
static void increase();
static void keypress(XEvent *e);
static void kill_client();
static void maprequest(XEvent *e);
static void move_down();
static void move_up();
static void next_desktop();
static void next_win();
static void prev_desktop();
static void prev_win();
static void quit();
static void remove_window(Window w);
static void save_desktop(int i);
static void select_desktop(int i);
static void send_kill_signal(Window w);
static void setup();
static void sigchld(int unused);
static void spawn(const Arg arg);
static void start();
static void swap_master();
static void toggle_fullscreen();
static void switch_vertical();
static void switch_horizontal();
static void tile();
static void update_current();

// Include configuration file (need struct key)
#include "config.h"

// Variable
static Display *dis;
static int bool_quit;
static int current_desktop;
static int master_size;
static int mode;
static int sh;
static int sw;
static int screen;
static unsigned int win_focus;
static unsigned int win_unfocus;
static Window root;
static client *head;
static client *current;
static int holder;    // for coming out of fullscreen mode back to what mode it was

// Events array
static void (*events[LASTEvent])(XEvent *e) = {
    [KeyPress] = keypress,
    [MapRequest] = maprequest,
    [DestroyNotify] = destroynotify,
    [ConfigureNotify] = configurenotify,
    [ConfigureRequest] = configurerequest
};

// Desktop array
static desktop desktops[5];

/* ***************************** Window Management ******************************* */
void add_window(Window w) {
    client *c,*t;

    if(!(c = (client *)calloc(1,sizeof(client))))
           die("Error calloc!");

    if(head == NULL) {
        c->next = NULL;
        c->prev = NULL;
        c->win = w;
        head = c;
    }
    else {
        if(ATTACH_ASIDE == 0) {
            for(t=head;t->next;t=t->next);
                c->next = NULL;
                c->prev = t;
                c->win = w;
                t->next = c;
        }
        else {
            for(t=head;t->prev;t=t->prev);
                c->prev = NULL;
                c->next = t;
                c->win = w;
                t->prev = c;

            head = c;
        }
    }

    current = c;
    save_desktop(current_desktop);
}

void swap_master() {
    Window tmp;

    if(head != NULL && current != NULL && current != head && mode != 1) {
        tmp = head->win;
        head->win = current->win;
        current->win = tmp;
        current = head;

        save_desktop(current_desktop);
        tile();
    }
}

void move_down() {
    Window tmp;
    if(current == NULL || current->next == NULL || current->win == head->win || current->prev == NULL)
        return;

    tmp = current->win;
    current->win = current->next->win;
    current->next->win = tmp;
    //keep the moved window activated
    next_win();
    save_desktop(current_desktop);
    tile();
}

void move_up() {
    Window tmp;
    if(current == NULL || current->prev == head || current->win == head->win) {
        fprintf(stdout, "%s\n","move_up not gonna be used");
        return;
    }
    tmp = current->win;
    current->win = current->prev->win;
    current->prev->win = tmp;
    prev_win();
    save_desktop(current_desktop);
    tile();
}

void next_win() {
    client *c;

    if(current != NULL && head != NULL) {
        if(current->next == NULL)
            c = head;
        else
            c = current->next;

        current = c;
        update_current();
    }
}

void prev_win() {
    client *c;

    if(current != NULL && head != NULL) {
        if(current->prev == NULL)
            for(c=head;c->next;c=c->next);
        else
            c = current->prev;

        current = c;
        update_current();
    }
}

void decrease() {
//    if(master_size < 50) {
        master_size -= 10;
        tile();
//    }
}

void increase() {
//    if(master_size < sh-50) {
        master_size += 10;
        tile();
//    }
}

void remove_window(Window w) {
    client *c;

    // CHANGE THIS UGLY CODE
    for(c=head;c;c=c->next) {

        if(c->win == w) {
            if(c->prev == NULL && c->next == NULL) {
                free(head);
                head = NULL;
                current = NULL;
                return;
            }

            if(c->prev == NULL) {
                head = c->next;
                c->next->prev = NULL;
                current = c->next;
            }
            else if(c->next == NULL) {
                c->prev->next = NULL;
                current = c->prev;
            }
            else {
                c->prev->next = c->next;
                c->next->prev = c->prev;
                current = c->prev;
            }

            free(c);
            return;
        }
    }
}

void kill_client() {
    if(current != NULL) {
        //send delete signal to window
        XEvent ke;
        ke.type = ClientMessage;
        ke.xclient.window = current->win;
        ke.xclient.message_type = XInternAtom(dis, "WM_PROTOCOLS", True);
        ke.xclient.format = 32;
        ke.xclient.data.l[0] = XInternAtom(dis, "WM_DELETE_WINDOW", True);
        ke.xclient.data.l[1] = CurrentTime;
        XSendEvent(dis, current->win, False, NoEventMask, &ke);
        send_kill_signal(current->win);
    }
}

unsigned long getcolor(const char* color) {
    XColor c;
    Colormap map = DefaultColormap(dis,screen);

    if(!XAllocNamedColor(dis,map,color,&c,&c))
        die("Error parsing color!");

    return c.pixel;
}

void update_current() {
    client *c;

    for(c=head;c;c=c->next)
        if(current == c) {
            // "Enable" current window
            XSetWindowBorderWidth(dis,c->win,BORDER_WIDTH);
            XSetWindowBorder(dis,c->win,win_focus);
            XSetInputFocus(dis,c->win,RevertToParent,CurrentTime);
            XRaiseWindow(dis,c->win);
        }
        else
            XSetWindowBorder(dis,c->win,win_unfocus);
}

/* **************************** Desktop Management ************************************* */
void change_desktop(const Arg arg) {
    client *c;

    if(arg.i == current_desktop)
        return;

    // Save current "properties"
    save_desktop(current_desktop);

    // Unmap all window
    if(head != NULL)
        for(c=head;c;c=c->next)
            XUnmapWindow(dis,c->win);

    // Take "properties" from the new desktop
    select_desktop(arg.i);

    // Map all windows
    if(head != NULL)
        for(c=head;c;c=c->next)
            XMapWindow(dis,c->win);

    tile();
    update_current();

}

void next_desktop() {
    int tmp = current_desktop;
    if(tmp == 5)
        tmp = 0;
    else
        tmp++;

    Arg a = {.i = tmp};
    change_desktop(a);
}

void prev_desktop() {
    int tmp = current_desktop;
    if(tmp == 0)
        tmp = 5;
    else
        tmp--;

    Arg a = {.i = tmp};
    change_desktop(a);
}

void client_to_desktop(const Arg arg) {
    client *tmp = current;
    int tmp2 = current_desktop;
    
    if(arg.i == current_desktop || current == NULL)
        return;

    // Add client to desktop
    select_desktop(arg.i);
    add_window(tmp->win);
    save_desktop(arg.i);

    // Remove client from current desktop
    select_desktop(tmp2);
    remove_window(current->win);
    XUnmapWindow(dis,tmp->win);
    current = current->next;

    tile();
    update_current();
}

void save_desktop(int i) {
    desktops[i].master_size = master_size;
    desktops[i].mode = mode;
    desktops[i].head = head;
    desktops[i].current = current;
}

void select_desktop(int i) {
    head = desktops[i].head;
    current = desktops[i].current;
    master_size = desktops[i].master_size;
    mode = desktops[i].mode;
    current_desktop = i;
}

void tile() {
    client *c;
    int n = 0;
    int x = 0;

    // If only one window
    if(head != NULL && head->next == NULL) {
        XMoveResizeWindow(dis,head->win,0,0,sw-4,sh-4);
    }
    else if(head != NULL) {
        switch(mode) {
            case 0: /* Horizontal */
                // Master window
                XMoveResizeWindow(dis,head->win,0,0,sw-4,master_size - BORDER_WIDTH);

                // Stack
                for(c=head->next;c;c=c->next) ++n;
                for(c=head->next;c;c=c->next) {
                    XMoveResizeWindow(dis,c->win,x,master_size + BORDER_WIDTH,(sw/n) - BORDER_WIDTH,sh-master_size - (2 * BORDER_WIDTH));
                    x += sw/n;
                }
                break;
            case 1: /* Fullscreen */
                for(c=head;c;c=c->next) {
                    XMoveResizeWindow(dis,c->win,0,0,sw,sh);
                }
                break;
            case 2: /* Vertical */
                // Master window
                XMoveResizeWindow(dis,head->win,0,0,master_size - BORDER_WIDTH,sh - BORDER_WIDTH);

                // Stack
                for(c=head->next;c;c=c->next) ++n;
                for(c=head->next;c;c=c->next) {
                    XMoveResizeWindow(dis,c->win,master_size + BORDER_WIDTH,x,sw-master_size-(2*BORDER_WIDTH),(sh/n) - BORDER_WIDTH);
                    x += sh/n;
                }
                break;
            default:
                break;
        }
    }
}

void toggle_fullscreen() {
    if(mode != 1) {
        holder = mode;
        mode = 1;
    }
    else {
        mode = holder;
    }

    tile();
    update_current();
}

void switch_vertical() {
    mode = 2;
        master_size = sw * MASTER_SIZE;
    tile();
    update_current();
}

void switch_horizontal() {
    mode = 0;
        master_size = sh * MASTER_SIZE;
    tile();
    update_current();
}

/* ********************** Keyboard Management ********************** */
void grabkeys() {
    int i;
    KeyCode code;

    // For each shortcuts
    for(i=0;i<TABLENGTH(keys);++i) {
        if((code = XKeysymToKeycode(dis,keys[i].keysym))) {
            XGrabKey(dis,code,keys[i].mod,root,True,GrabModeAsync,GrabModeAsync);
        }
    }
}

void keypress(XEvent *e) {
    int i;
    XKeyEvent ke = e->xkey;
    KeySym keysym = XKeycodeToKeysym(dis,ke.keycode,0);

    for(i=0;i<TABLENGTH(keys);++i) {
        if(keys[i].keysym == keysym && keys[i].mod == ke.state) {
            keys[i].function(keys[i].arg);
        }
    }
}

void configurenotify(XEvent *e) {
    // Do nothing for the moment
}

/* ********************** Signal Management ************************** */
void configurerequest(XEvent *e) {
    // Paste from DWM, thx again \o/
    XConfigureRequestEvent *ev = &e->xconfigurerequest;
    XWindowChanges wc;
    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(dis, ev->window, ev->value_mask, &wc);
}

void destroynotify(XEvent *e) {
    int i=0;
    client *c;
    XDestroyWindowEvent *ev = &e->xdestroywindow;

    // Uber (and ugly) hack ;)
    for(c=head;c;c=c->next)
        if(ev->window == c->win)
            i++;
    
    // End of the hack
    if(i == 0)
        return;

    remove_window(ev->window);
    tile();
    update_current();
}

void die(const char* e) {
    fprintf(stdout,"catwm-0.0.4: %s\n",e);
    exit(1);
}
 
void maprequest(XEvent *e) {
    XMapRequestEvent *ev = &e->xmaprequest;

    // For fullscreen mplayer (and maybe some other program)
    client *c;
    for(c=head;c;c=c->next)
        if(ev->window == c->win) {
            XMapWindow(dis,ev->window);
            return;
        }

    add_window(ev->window);
    XMapWindow(dis,ev->window);
    tile();
    update_current();
}

void quit() {
    Window root_return, parent;
    Window *children;
    int i;
    unsigned int nchildren; 
    XEvent ev;

    /*
     * if a client refuses to terminate itself,
     * we kill every window remaining the brutal way.
     * Since we're stuck in the while(nchildren > 0) { ... } loop
     * we can't exit through the main method.
     * This all happens if MOD+q is pushed a second time.
     */
    if(bool_quit == 1) {
        XUngrabKey(dis, AnyKey, AnyModifier, root);
        XDestroySubwindows(dis, root);
        fprintf(stdout, "catwm-0.0.2: Thanks for using!\n");
        XCloseDisplay(dis);
        die("forced shutdown");
    }

    bool_quit = 1;
    XQueryTree(dis, root, &root_return, &parent, &children, &nchildren);
    for(i = 0; i < nchildren; i++) {
        send_kill_signal(children[i]);
    }
    //keep alive until all windows are killed
    while(nchildren > 0) {
        XQueryTree(dis, root, &root_return, &parent, &children, &nchildren);
        XNextEvent(dis,&ev);
        if(events[ev.type])
            events[ev.type](&ev);
    }

    XUngrabKey(dis,AnyKey,AnyModifier,root);
    fprintf(stdout,"catwm-0.0.2: You Quit : Thanks for using!\n");
}

void send_kill_signal(Window w) { 
    XEvent ke;
    ke.type = ClientMessage;
    ke.xclient.window = w;
    ke.xclient.message_type = XInternAtom(dis, "WM_PROTOCOLS", True);
    ke.xclient.format = 32;
    ke.xclient.data.l[0] = XInternAtom(dis, "WM_DELETE_WINDOW", True);
    ke.xclient.data.l[1] = CurrentTime;
    XSendEvent(dis, w, False, NoEventMask, &ke);
}

void setup() {
    // Install a signal
    sigchld(0);

    // Screen and root window
    screen = DefaultScreen(dis);
    root = RootWindow(dis,screen);

    // Screen width and height
    sw = XDisplayWidth(dis,screen) - BORDER_WIDTH;
    sh = XDisplayHeight(dis,screen) - PANEL_HEIGHT - BORDER_WIDTH;

    // Colors
    win_focus = getcolor(FOCUS);
    win_unfocus = getcolor(UNFOCUS);

    // Shortcuts
    grabkeys();

    // Default stack
    mode = DEFAULT_MODE;

    // For exiting
    bool_quit = 0;

    // List of client
    head = NULL;
    current = NULL;

    // Master size
    if(mode == 0)
        master_size = sh*MASTER_SIZE;
    else
        master_size = sw*MASTER_SIZE;

    // Set up all desktop
    int i;
    for(i=0;i<TABLENGTH(desktops);++i) {
        desktops[i].master_size = master_size;
        desktops[i].mode = mode;
        desktops[i].head = head;
        desktops[i].current = current;
    }

    // Select first dekstop by default
    const Arg arg = {.i = 0};
    current_desktop = arg.i;
    change_desktop(arg);
    // To catch maprequest and destroynotify (if other wm running)
    XSelectInput(dis,root,SubstructureNotifyMask|SubstructureRedirectMask);
    fprintf(stdout,"\n\n catwm-0.0.2: We're up and running!\n");
}

void sigchld(int unused) {
    // Again, thx to dwm ;)
    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(fork() == 0) {
            if(dis)
                close(ConnectionNumber(dis));

            setsid();
            execvp((char*)arg.com[0],(char**)arg.com);
        }
        exit(0);
    }
}

void start() {
    XEvent ev;

    // Main loop, just dispatch events (thx to dwm ;)
    while(!bool_quit && !XNextEvent(dis,&ev)) {
        if(events[ev.type])
            events[ev.type](&ev);
    }
}


int main(int argc, char **argv) {
    // Open display   
    if(!(dis = XOpenDisplay(NULL)))
        die("Cannot open display!");

    // Setup env
    setup();

    // Start wm
    start();

    // Close display
    XCloseDisplay(dis);

    return 0;
}

config.h

 /* config.h for catwm-0.0.2.c
 *
 *  ( o   o )  Made by cat...
 *  (  =^=  )
 *  (        )            ... for cat!
 *  (         )
 *  (          ))))))________________ Cute And Tiny Window Manager
 *  ______________________________________________________________________________
 *
 *  Copyright (c) 2010, Rinaldini Julien, julien.rinaldini@heig-vd.ch
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  Some changes and additions by P. Newman 24.4.11
 *     - best not to email julien if you use this... :)
 */

#ifndef CONFIG_H
#define CONFIG_H

/* Mod (Mod1 == alt) and master size
   and I added panel size and  the windows key (Mod4 == Super)
   added shortcuts for different tiling modes
   added shortcuts for moving the window to the next workspace and back
   */
#define MOD1            Mod1Mask
#define MOD4        Mod4Mask
#define MASTER_SIZE     0.6
#define PANEL_HEIGHT    20
#define BORDER_WIDTH    4
#define ATTACH_ASIDE    1 /* 0=TRUE, 1=New window is master */
#define DEFAULT_MODE    2 /* 0 = Horizontal, 1 = Fullscreen, 2 = Vertical */

// Colors
#define FOCUS           "#664422" // dkorange
#define UNFOCUS         "#004050" // blueish

const char* dmenucmd[]      = {"dmenu_run","-i","-nb","#664422","-nf","white",NULL};
const char* urxvtcmd[]      = {"urxvtc",NULL};
const char* terminalcmd[]   = {"Terminal",NULL};
const char* thunarcmd[]     = {"thunar",NULL};
const char* firefoxcmd[]    = {"firefox",NULL};
const char* mailcmd[]       = {"thunderbird",NULL };
const char* voldowncmd[]    = {"/home/pnewm/bin/voldown",NULL};
const char* volupcmd[]      = {"/home/pnewm/bin/volup",NULL};
const char* vols_what[]     = {"/home/pnewm/bin/volumes_what",NULL};
// for reboot and shutdown
const char* rebootcmd[]     = {"sudo","reboot",NULL};
const char* shutdowncmd[]   = {"sudo","shutdown","-h","now",NULL};

// Avoid multiple paste
#define DESKTOPCHANGE(K,N) \
    {  MOD1,             K,                          change_desktop, {.i = N}}, \
    {  MOD1|ShiftMask,   K,                          client_to_desktop, {.i = N}},

// Shortcuts
static struct key keys[] = {
    // MOD               KEY                         FUNCTION        ARGS
    {  MOD1,             XK_h,                       increase,       {NULL}},
    {  MOD1,             XK_l,                       decrease,       {NULL}},
    {  MOD1,             XK_c,                       kill_client,    {NULL}},
    {  MOD1,             XK_j,                       next_win,       {NULL}},
    {  MOD1,             XK_k,                       prev_win,       {NULL}},
    {  MOD1,             XK_v,                       spawn,          {.com = dmenucmd}},
    {  MOD1,             XK_Return,                  spawn,          {.com = urxvtcmd}},
    {  MOD1,             XK_Up,                     spawn,          {.com = volupcmd}},
    {  MOD1,             XK_Down,             spawn,          {.com = voldowncmd}},
// alt + shift + shortcut
    {  MOD1|ShiftMask,   XK_j,                       move_up,        {NULL}},
    {  MOD1|ShiftMask,   XK_k,                       move_down,      {NULL}},
    {  MOD1|ShiftMask,   XK_Return,                  swap_master,    {NULL}},
    {  MOD1|ShiftMask,   XK_m,                       toggle_fullscreen,{NULL}},
    {  MOD1|ShiftMask,   XK_v,                       switch_vertical,{NULL}},
    {  MOD1|ShiftMask,   XK_h,                       switch_horizontal,{NULL}},
// Window key + shortcut
    {  MOD4,             XK_Right,                   next_desktop,   {NULL}},
    {  MOD4,             XK_Left,                    prev_desktop,   {NULL}},
    {  MOD4,             XK_e,                     spawn,          {.com = mailcmd}},
    {  MOD4,             XK_f,                     spawn,          {.com = firefoxcmd}},
    {  MOD4,             XK_h,                     spawn,          {.com = thunarcmd}},
    {  MOD4,             XK_t,                       spawn,          {.com = terminalcmd}},
    {  MOD4,             XK_v,                       spawn,          {.com = vols_what}},
// Control + alt + shortcut
    {  MOD1|ControlMask, XK_q,                       quit,           {NULL}},
    {  MOD1|ControlMask, XK_r,                       spawn,          {.com = rebootcmd}},
    {  MOD1|ControlMask, XK_s,                       spawn,          {.com = shutdowncmd}},
       DESKTOPCHANGE(   XK_1,                                       0)
       DESKTOPCHANGE(   XK_2,                                       1)
       DESKTOPCHANGE(   XK_3,                                       2)
       DESKTOPCHANGE(   XK_4,                                       3)
       DESKTOPCHANGE(   XK_5,                                       4)
       DESKTOPCHANGE(   XK_6,                                       5)
};

#endif

Here's a Makefile for it

CFLAGS+= -Wall
LDADD+= -lX11 
LDFLAGS=
EXEC=catwm-0.0.2

PREFIX?= /usr
BINDIR?= $(PREFIX)/bin

CC=gcc

all: $(EXEC)

catwm-0.0.2: catwm-0.0.2.o
    $(CC) $(LDFLAGS) -Os -o $@ $+ $(LDADD)

install: all
    install -Dm 755 catwm-0.0.2 $(DESTDIR)$(BINDIR)/catwm-0.0.2

clean:
    rm -fv catwm-0.0.2 *.o

I pipe conky through dzen2 to get the statusbar at the bottom :

dzen_conky

out_to_x no
out_to_console yes
double_buffer yes
use_spacer left
update_interval 1
no_buffers yes

TEXT
^bg()^fg(\#003040)^pa(350) | Mem: ^fg(\#ffff00)${mem} ^fg(\#003040)| CPU  ^fg(\#00ff00)${cpu cpu0}%  ^fg(\#003040)|| Down: ^fg(\#6666ff)${downspeed eth0} ^fg(\#003040) | Swap ^fg(\#ff4444) ${swapperc}% ^fg(\#003040) | Temp ^fg(\#44ff44)${acpitemp}C  ^fg(\#003040)| ^fg(\#565600)${uptime} ^fg(\#003040) | ^pa(1195) ${time %a  %d / %m}   ^pa(1300) ^fg(\#007777) ${time %I:%M %P }

and I use ~/.xinitrc to make it all work nice :

.xinitrc

xsetroot -cursor_name left_ptr &
feh --bg-scale '/home/pnewm/.fluxbox/backgrounds/tiles-dark.jpg'
urxvtd -q -f -o &

 conky -c /home/pnewm/build/Catwm-0.0.2/dzen_conky | dzen2 -x %x -y 1038 -bg black -fn -*-arial-*-*-*-*-*-*-*-*-*-*-*-* -ta l &
 exec /home/pnewm/build/CatWM-0.0.2/src/catwm-0.0.2

I don't know if anyone is still interested in this window manager but I like its' low resource use and configurability tongue

Last edited by moetunes (2011-04-25 05:34:20)


You're just jealous because the voices only talk to me.

Offline

#153 2011-04-22 15:05:20

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 664

Re: catwm, Cute and Tiny Window Manager

I myself use musca(manual tiler), but this is for sure my favorite automatic-tiling-wm!

The only thing i'm missing in catwm, is that there's no external config file... I know that this is by design, just like dwm, but I just really preffer to be able to update existing configured installs with aur helpers like packer, just like my other used aur apps, without having to mess around with the source and recompile afterwards... Yeah, of course I can make a patch with my config and write a script to patch and update, but nonetheless...   

Just a feature-request, allthough i'm sure you disagree, but just in case wink

Also, another feature-request about having the option to have new windows appear in the master area instead of the stack, like dwm; catwm now works like dwm with the attachaside patch and it would be nice to have the option of using catwm with the normal dwm-like tiling mode also...

Just for fun, then here's a ps_mem.py memory and filesize comparison between catwm(pyknite's, haven't tried moetunes version yet!) and dwm and with musca thrown in additionally.

Memory:

 Private  +   Shared  =  RAM used    Program 

176.0 KiB +  83.5 KiB = 259.5 KiB    catwm
316.0 KiB + 247.0 KiB = 563.0 KiB    dwm
404.0 KiB + 195.0 KiB = 599.0 KiB    musca

Filesize:

Targets (1): catwm-git-20110422-1

Total Download Size:    0.00 MB
Total Installed Size:   0.02 MB

Targets (1): dwm-5.8.2-2

Total Download Size:    0.00 MB
Total Installed Size:   0.11 MB

Targets (1): musca-0.9.24-1

Total Download Size:    0.00 MB
Total Installed Size:   0.12 MB

Last edited by mhertz (2011-04-23 00:48:20)

Offline

#154 2011-04-23 12:43:40

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 664

Re: catwm, Cute and Tiny Window Manager

I'm currently testing running automatic tiling instead of manual on one of my boxes, to see if I maybe will like that better, and so i'm changing between catwm and dwm.

I love catwm as an auto-tiler, but the reason i'm changing back and forth between catwm and dwm, is that catwm uses a little "strange" auto-tiling algo, which is the same as dwm's attachaside patch, which means that new windows gets opened and focused on the stack instead of on the master which unpatched dwm does, and I cannot really decide what is the best approach?

So, could some of you catwm users/devs please tell me why you prefer the "open new windows on the stack instead of master" tiling approach instead of the normal dwm one?

I think most other auto-tilers does the opposite of catwm i.e. like dwm, since it would imho make sence to have new windows opened as the biggest window i.e. master, but there's one case where I can see catwm's method to make sence, and that's when opening a browser first, so thats on master and biggest and then the rest terminals opened are just stacked on the stack, but that approach then needs me to always open my browser first which isn't maybe always the case?(yes, I know i can swap master, but nonetheless).

Any thoughts on this would be highly appreciated!

Edit: Btw, i'm using pyknite's original catwm version and not moetunes "fork", since pyknite's original version features _exactly_ what I need and not a thing more, just the way I like it! I have no need for the added extra features...

Last edited by mhertz (2011-04-23 13:27:03)

Offline

#155 2011-04-23 18:49:40

Sara
Member
From: USA
Registered: 2009-07-09
Posts: 212
Website

Re: catwm, Cute and Tiny Window Manager

mhertz wrote:

I'm currently testing running automatic tiling instead of manual on one of my boxes, to see if I maybe will like that better, and so i'm changing between catwm and dwm.

I love catwm as an auto-tiler, but the reason i'm changing back and forth between catwm and dwm, is that catwm uses a little "strange" auto-tiling algo, which is the same as dwm's attachaside patch, which means that new windows gets opened and focused on the stack instead of on the master which unpatched dwm does, and I cannot really decide what is the best approach?

So, could some of you catwm users/devs please tell me why you prefer the "open new windows on the stack instead of master" tiling approach instead of the normal dwm one?

I'm not a catwm user, but I do use the attachaside patch for dwm, which replicates this exact feature, as you noted. For me, I prefer this, because I often open my most important window first, and then I want the rest to be slaves. For instance, if I'm doing a homework assignment, I want all the PDFs I have to reference to be on the side, and I open them first because then I have to use my terminal (the same one that launched those PDFs) to edit my LaTeX file with vi.

Hope the feedback helps (I'm sure the reasons for preferring this type of behavior vary).

Last edited by Sara (2011-04-23 18:50:25)


Registed Linux User 483618

Offline

#156 2011-04-23 18:57:13

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 664

Re: catwm, Cute and Tiny Window Manager

Thanks alot mate! That makes perfect sence to me also!

Much appreciated! smile

Offline

#157 2011-04-23 21:46:55

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

@ mhertz
If you want catwm to work like standard dwm then comment out the line
update_current();
in the swap_master function and at the end of the add_window function add the line
swap_master();
I've only given it a quick check here but it seems to work fine smile


You're just jealous because the voices only talk to me.

Offline

#158 2011-04-23 22:03:26

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

A tip for trying out configuration changes in wm's like catwm and dwm :
I login at tty1 and start catwm and do some changes and rebuild catwm then login at tty2 and run

startx -- :1

which starts another X session on tty8. I then put my changes through some tests to see if I keep them.
Hope that's useful smile


You're just jealous because the voices only talk to me.

Offline

#159 2011-04-23 22:14:43

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 664

Re: catwm, Cute and Tiny Window Manager

Hey, that's a great tip(dwm-like tiling), man! Thanks alot mate!

However, i'm just gonna keep it like default, as im beginning to get used to this way of doing things...

catwm really rocks and the foot/work-print is unbelieable! Im really beginning to like this wm and am not changing back and forth with dwm any longer!

Still im undecided about what I like the best in case of musca(manual) and catwm(auto) though... I've always used manual tilers(ratpoison and then musca) and never really given the auto-tilers any chance...

Damn, I hate it- when I cannot decide between things! smile lol...

CU, Martin.

Edit: In the end I must say that I prefer manual tiling with musca still, but nonetheless, then kudos to pyknite and moetunes for making one heck of an awesome auto-tiler, and which seriously gives dwm a run for it's money(that is if you don't use floating windows, however...)

Last edited by mhertz (2011-04-23 23:14:10)

Offline

#160 2011-04-24 06:55:05

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

Here's a different add_window function that will always add a new window as the master. It also places the current master window at the top of the stack so it will be the master window again when that new window gets closed.

void add_window(Window w) {
    client *c,*t;

    if(!(c = (client *)calloc(1,sizeof(client))))
           die("Error calloc!");

    if(head == NULL) {
        c->next = NULL;
        c->prev = NULL;
        c->win = w;
        head = c;
    }
    else {
        for(t=head;t->prev;t=t->prev);
            c->prev = NULL;
            c->next = t;
            c->win = w;
            t->prev = c;
    
        head = c;
    }

    current = c;
    save_desktop(current_desktop);
}

Last edited by moetunes (2011-04-24 20:38:02)


You're just jealous because the voices only talk to me.

Offline

#161 2011-04-24 12:06:12

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 664

Re: catwm, Cute and Tiny Window Manager

Great contribution! NIce work, mate!

Offline

#162 2011-04-24 20:40:42

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

The original add_window function I posted above did a good job of rearranging windows but didn't order the stack so there were issues with window deletion, moving etc. So I replaced it with one that does the same thing but orders the stack this time...


You're just jealous because the voices only talk to me.

Offline

#163 2011-04-25 05:42:51

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

I updated post #152 to reflect what I've settled on using after this round of playing with catwm.
(thanks pyknite)
- 3 tiling modes
    with the default set in the config file
    with keyboard shortcuts to use them
    catwm remembers which mode for each desktop for the session
- normal catwm tiling ( like dwm with the attach aside patch)
    or where the new window becomes the master(like the defaults in dwm etc)
    choice of which is set in the config file
- room to run a panel like dzen at the bottom
    with the height set in the config file
- removed the write to file stuff as tiling and workspace changes are stable now

With such a small code base it is easy enough to try stuff out  smile


You're just jealous because the voices only talk to me.

Offline

#164 2011-04-25 13:10:59

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 664

Re: catwm, Cute and Tiny Window Manager

Thanks for your efforts moetunes! Your version sounds pretty sweet and I wanted to test it, but i'm getting this when running make:

[martin@arch catwm]$ make
gcc -Wall   -c -o catwm-0.0.2.o catwm-0.0.2.c
gcc  -Os -o catwm-0.0.2 catwm-0.0.2.o -lX11 
/usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: ld returned 1 exit status
make: *** [catwm-0.0.2] Error 1

I think it's probably because when I copy/paste from those codeboxes and into vim, then the code gets garbled and isn't adjusted right...

If you want, then you could put the files on e.g. pastebin or something(or tarball on public dropbox etc, etc.).

However, I would recommend that you either fork it and put it on aur, or you contact pyknite and ask him for taking over the project and it's aur package...

Thanks again!

Offline

#165 2011-04-25 20:31:40

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

@mhertz
It works ok here pasting into leafpad so it might be something about your vim or you missed a bit of the file or who knows... smile

I'm not looking to take over the project I want to play with some c programming sometimes and this is a fun little app to play with since the codebase is small.
I don't think there'd be too many people using catwm as their daily wm and if too much is added to it it won't be cute and tiny anymore smile

On another note I'm still not ordering the stack properly when not using it like the original catwm (when ATTACH_ASIDE = 1) so if you try my changes be aware that catwm might crash when you move windows to other desktops...


You're just jealous because the voices only talk to me.

Offline

#166 2011-04-25 22:03:19

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

The pic in post #152 shows what happens when opening a file manager then a couple of text editors with the default catwm way of ordering the windows.
Doing the same thing with the new window being the master like default dwm does gives

tOGY1cw

I like it this way smile


You're just jealous because the voices only talk to me.

Offline

#167 2011-04-26 00:02:25

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 664

Re: catwm, Cute and Tiny Window Manager

Hi again, mate!

Hmm, when I copy/pasted with vim, then I did it the unix way of marking the text without copying and then shift+insert into vim in insert mode, which I always do with everything else, but that failed during building the app...

Now after you mentioned leafpad, then I to test did install it and this time actually did a windows-like copy/paste into leafpad, and it also failed that time, but with another error; the copy/pasted text wasen't mangled in this way, but there where missing some TABs in the makefile, i.e. line 14, 17 and 20 should have replaced it's preliminary space with actual Tabs and then it would build... Also just a FYI to others interested in trying this nice WM out!

Anyway, I commend you on a job well done! It's a great version of catwm you've made there and the new features are very nice without bloating up the codebase with useless stuff!

Also the memory is the same as previous, as I checked it again with ps_mem.py; both the original and yours starts up at about 325kb and over some minutes goes further down alittle to about 290kb! Just simply awesome! smile

As I previously stated, then i'm prefering manual ratpoison-like tiling, and so isn't using catwm but musca, but I would seriously recommend other ppl which prefers auto-tiling to check out this little piece of awesomeness, and now with moetunes help, then it rocks even better than before!

Nice job again and thanks for a great contribution, mate!

CU, Martin.

Last edited by mhertz (2011-04-26 00:09:11)

Offline

#168 2011-05-01 02:35:08

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

I've added a popup urxvtc. Here's a pic:

tOGkweQ

Last edited by moetunes (2011-05-01 09:06:24)


You're just jealous because the voices only talk to me.

Offline

#169 2011-08-17 01:45:02

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

I've been having another play with catwm and have removed the popup urxvtc 'cause I fixed a bad window error killing the wm and have fixed up the numlock being on stopping the keyboard shortcuts from working. It's still the lightest wm I've found smile


You're just jealous because the voices only talk to me.

Offline

#170 2011-08-19 18:36:50

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 664

Re: catwm, Cute and Tiny Window Manager

Thanks moetunes!

I cannot see you have edited your catvm-0-02 source with these changes? Btw, it would be nice if you could place your code on github or some other place e.g. pastebin or whatever... Also, since when copy/pasting, then you need to add tabs in the makefile... Then you could just update it whenever you have the motivation...

Offline

#171 2011-08-19 23:42:06

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

I should find somewhere to host it as I'm going to keep playing with it and someone might find it useful. smile
I've just added follow mouse option to it with 17 new lines and it's settable in the config and I haven't been able to crash it in ages.
Cheers


You're just jealous because the voices only talk to me.

Offline

#172 2011-08-20 08:28:33

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

I've set up a github account so the files are accessible here :
github.
If there's interest I'll start a post about it 'cause I'll keep playing with it for a while yet wink

edit: I should say I've started calling it DMiniWM as it is no longer the cute and tiny window manager the original author left it as, though it is still tiny.

Last edited by moetunes (2011-08-20 08:33:59)


You're just jealous because the voices only talk to me.

Offline

#173 2011-08-20 08:38:51

itsbrad212
Member
From: Chicago, USA
Registered: 2010-01-23
Posts: 1,848

Re: catwm, Cute and Tiny Window Manager

moetunes wrote:

I've set up a github account so the files are accessible here :
github.
If there's interest I'll start a post about it 'cause I'll keep playing with it for a while yet wink

edit: I should say I've started calling it DMiniWM as it is no longer the cute and tiny window manager the original author left it as, though it is still tiny.

It's great to see that you've picked up on the wm. However, I do believe that you need to retain mention of catwm in your license, as it is a fork and still contains a lot of code from the original project. smile

Offline

#174 2011-08-20 08:52:30

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

'snip'

It's great to see that you've picked up on the wm. However, I do believe that you need to retain mention of catwm in your license, as it is a fork and still contains a lot of code from the original project. smile

Cheers for that smile
I'd appreciate an idea of the sort of references required as the whole framework is pyknites' but I can't say that he is still interested in it so I don't want to include his email address e.g. Or should I just still call it catwm ?

Last edited by moetunes (2011-08-20 10:05:53)


You're just jealous because the voices only talk to me.

Offline

#175 2011-08-20 09:24:51

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,012

Re: catwm, Cute and Tiny Window Manager

I've added my xcb port of this - without keyboard shortcuts yet - to github if anyone wants to have a play with it.


You're just jealous because the voices only talk to me.

Offline

Board footer

Powered by FluxBB