sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit 6b185479a855eb4e10bc6104de19d88c65721eb0
parent 8099f2cbd223c943bbe24e22fb3c543897fee5a3
Author: Shvedov Yury <shved@lvk.cs.msu.su>
Date:   Sun, 22 Jun 2014 20:31:49 +0400

Merge branch 'master' of git://git.suckless.org/sites

Diffstat:
Adwm.suckless.org/customisation/patches_in_git.md | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/dwmstatus/getvol.c | 40++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/dwmstatus/index.md | 4+++-
Ddwm.suckless.org/dwmstatus/p1c0-dwmstatus-volume.c | 232-------------------------------------------------------------------------------
Adwm.suckless.org/multi-monitor.md | 48++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/alwaysfullscreen.md | 18++++++++++++++++++
Mdwm.suckless.org/patches/attachaside.md | 6++++--
Adwm.suckless.org/patches/bottommargin.md | 13+++++++++++++
Adwm.suckless.org/patches/dwm-6.0-attachaside.diff | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.0-bottommargin.diff | 26++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.0-keypressrelease.diff | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/dwm-6.0-pango.diff | 41+++++++++++++++++++++++++----------------
Adwm.suckless.org/patches/dwm-6.0-pertag-tab-v2a.diff | 897+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.0-pertag.diff | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.0-pertag_without_bar.diff | 166+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.0-tab-v2a.diff | 720+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.1-hide_vacant_tags.diff | 38++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.1-nametag-prepend.diff | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/dwm-6.1-systray.diff | 116++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Adwm.suckless.org/patches/dwm-6.1-tagintostack-allmaster.diff | 32++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.1-tagintostack-onemaster.diff | 20++++++++++++++++++++
Adwm.suckless.org/patches/dwm-cdec978-alwaysfullscreen.diff | 13+++++++++++++
Adwm.suckless.org/patches/dwm-master_2013-08-27_cdec978-pertag-tab-v2a.diff | 672+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-master_2013-08-27_cdec978-tab-v2a.diff | 505+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-nofullscreen.diff | 11+++++++++++
Adwm.suckless.org/patches/hide_vacant_tags.md | 26++++++++++++++++++++++++++
Mdwm.suckless.org/patches/historical/taglayouts.md | 2+-
Mdwm.suckless.org/patches/index.md | 2+-
Adwm.suckless.org/patches/keypressrelease.md | 37+++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/moveresize.md | 2+-
Adwm.suckless.org/patches/multimon-1-added-monitor-marker-to-bar.diff | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/multimon-2-added-n-view-wrappers-for-unified-multi-monitor.diff | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/multimon-3-added-reset_view-function.diff | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/multimon-4-added-statusall-toggle-replacing-need-for-patch.diff | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/multimon.md | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/nametag.md | 4++++
Adwm.suckless.org/patches/nofullscreen.m4 | 19+++++++++++++++++++
Mdwm.suckless.org/patches/pertag.md | 3++-
Mdwm.suckless.org/patches/runorraise.md | 4++--
Adwm.suckless.org/patches/tagintostack.md | 21+++++++++++++++++++++
Ast.suckless.org/faq.md | 5+++++
Mst.suckless.org/index.md | 8+-------
Mst.suckless.org/patches/argbbg.md | 7+++++--
Ast.suckless.org/patches/hide_X_cursor.md | 19+++++++++++++++++++
Ast.suckless.org/patches/solarized_color_scheme.md | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-0.5-argbbg.diff | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-0.5-hidexcursor.diff | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-0.5-no-bold-colors.diff | 12++++++++++++
Ast.suckless.org/patches/st-argbbg.png | 0
Ast.suckless.org/patches/st-git-hidexcursor.diff | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-no-bold-colors.diff | 12++++++++++++
Ast.suckless.org/patches/st-on-openbsd.diff | 25+++++++++++++++++++++++++
Ast.suckless.org/patches/st-solarized-dark.diff | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-solarized-dark.png | 0
Ast.suckless.org/patches/st-solarized-light.diff | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-solarized-light.png | 0
Ast.suckless.org/patches/st_on_openbsd.md | 42++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/screenshots/20h-2012-s.png | 0
Ast.suckless.org/screenshots/hendry-s.png | 0
Mst.suckless.org/screenshots/index.md | 4++--
Msta.li/masterplan.md | 8++++----
Msta.li/sandbox.md | 5++---
Msta.li/technologies.md | 2+-
Msuckless.org/index.md | 13+++++++++++++
Msuckless.org/other_projects.md | 4+++-
Msuckless.org/people/Sin.md | 4++--
Msuckless.org/people/cls.md | 2+-
Msuckless.org/project_ideas.md | 35-----------------------------------
Msuckless.org/rocks.md | 6+++---
Msurf.suckless.org/files/autologin.md | 2+-
Msurf.suckless.org/files/kiosk_mode.md | 2+-
Asurf.suckless.org/patches/chromekeys.md | 21+++++++++++++++++++++
Asurf.suckless.org/patches/surf-0.6-chromekeys.diff | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/patches/dmenu-git-xft.diff | 467+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools.suckless.org/dmenu/patches/xft.md | 1+
Mtools.suckless.org/dmenu/scripts/index.md | 9+++++++--
Mtools.suckless.org/ii/usage.md | 5+++++
Atools.suckless.org/sbase.md | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/sinit.md | 23+++++++++++++++++++++++
Atools.suckless.org/ubase.md | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
80 files changed, 6193 insertions(+), 367 deletions(-)

diff --git a/dwm.suckless.org/customisation/patches_in_git.md b/dwm.suckless.org/customisation/patches_in_git.md @@ -0,0 +1,98 @@ +# How to maintain dwm configuration and customization in git # + +Since suckless.org has migrated to git, customizations can now be be +managed directly in git as an alternative to the +[patch queue in Mercurial tutorial](http://dwm.suckless.org/customisation/patch_queue). + +## The concept ## + +By recording changes and applied patches as commits in a special +branch they can be rebased on top of the master branch when required. + +## Cloning the repository ## + +You need to have the [Git VCS](http://git-scm.com/) installed first. +Then clone the upstream repository locally + + git clone git://git.suckless.org/dwm + +## Recording customizations ## + +Create a special branch where all the customizations will be kept. It +doesn't matter what the name is, it just needs to be something +different than `master`. + + git branch my_dwm + +Now switch to the new branch. This will do nothing at the moment as +the branches are the same. + + git checkout my_dwm + +Now make your changes. If you want to apply one of the +[contributed patches](http://dwm.suckless.org/patches/) you can use +the `git apply` command + + git apply some_patch.diff + +Note that many patches make changes `config.def.h` instead of `config.h`. Either +move those changes also to `config.h`, or add `rm config.h` to the +`clean` target in the `Makefile`. + +Then record the changes as commits + + # tell git to add the changes in the given file(s) to be recorded + git add some_file.ext + # git will ask you to provide a message describing your changes + git commit + +### Experimenting with different combinations of customizations ### + +If you plan on experimenting with different combinations of +customizations it might be easier to record the commits in separate +feature branches by first creating and checking out a branch and then +recording the changes as commits. Having patches in different branches +also helps to keep their dependencies transparent by creating branches based +on other patch branches. + +Then merge the selected combination of changes into your branch + + git merge some_feature_branch + git merge other_feature_branch + +If you some conflicts occur, resolve them and then record the changes +and commit the result. `git mergetool` can help with resolving the +conflicts. + +## Updating customizations after new release ## + +When the time comes to update your customizations after a new +release of dwm or when the dwm repository contains a commit fixing +some bug, you first pull the new upstream changes into the master +branch + + git checkout master + git pull + +Then rebase your customization branch on top of the master branch + + git checkout my_dwm + git rebase --preserve-merges master + +The `--preserve-merges` option ensures that you don't have to resolve +conflicts which you have already resolved while performing merges again. + +In case there are merge conflicts anyway, resolve them (possibly with +the help of `git mergetool`), then record them as resolved and let the +rebase continue + + git add resolved_file.ext + git rebase --continue + +If you want to give up, you can always abort the rebase + + git rebase --abort + +## Author ## + +* [Ondřej Grover](mailto:ondrej.grover@gmail.com) diff --git a/dwm.suckless.org/dwmstatus/getvol.c b/dwm.suckless.org/dwmstatus/getvol.c @@ -0,0 +1,40 @@ +/* include this into your dwmstatus.c and use get_vol() as volume. + * if your audio card and subunit numbers differ from 0,0 you might havo + * to use amixer, aplay and the /proc/asound file tree to adapt. + * + * I had compilation issues. As result i had to drop the -std=c99 and + * -pedantic flags from the config.mk + */ + +#include <alsa/asoundlib.h> +#include <alsa/control.h> + +int +get_vol(void) +{ + int vol; + snd_hctl_t *hctl; + snd_ctl_elem_id_t *id; + snd_ctl_elem_value_t *control; + +// To find card and subdevice: /proc/asound/, aplay -L, amixer controls + snd_hctl_open(&hctl, "hw:0", 0); + snd_hctl_load(hctl); + + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); + +// amixer controls + snd_ctl_elem_id_set_name(id, "Master Playback Volume"); + + snd_hctl_elem_t *elem = snd_hctl_find_elem(hctl, id); + + snd_ctl_elem_value_alloca(&control); + snd_ctl_elem_value_set_id(control, id); + + snd_hctl_elem_read(elem, control); + vol = (int)snd_ctl_elem_value_get_integer(control,0); + + snd_hctl_close(hctl); + return vol; +} diff --git a/dwm.suckless.org/dwmstatus/index.md b/dwm.suckless.org/dwmstatus/index.md @@ -21,8 +21,9 @@ Please add your own version of dwmstatus here. * [dwmsd](https://github.com/johnko/dwmsd) - a daemon that listens on localhost tcp (may be useful as a base for asynchronous updates) * [profil-dwmstatus-1.0.c](profil-dwmstatus-1.0.c) - cpufreq, battery percent and date/time -* [p1c0-dwmstatus-volume.c](p1c0-dwmstatus-volume.c) - volume percentage & bar display * [suspend-statusbar.c](suspend-statusbar.c) - loadavg, wifi, battery and date. If battery goes below threshold - run suspend command +* [gods](https://github.com/schachmat/gods) - implemented in Go. prints network speed, cpu, ram, date/time +* [barmonitor](https://github.com/levi0x0/Scrips-IO/blob/master/bar_monitor.c) - display battery status, date/time. Helper functions @@ -46,6 +47,7 @@ add them here as file or as code example. dynamic_info. * [Battery function](batterystatus.c) : Battery percentage and status. + if charging, - if discharging, = if full. +* [Alsa Volume API](getvol.c) : Alsa Volume via the Alsa API Questions --------- diff --git a/dwm.suckless.org/dwmstatus/p1c0-dwmstatus-volume.c b/dwm.suckless.org/dwmstatus/p1c0-dwmstatus-volume.c @@ -1,232 +0,0 @@ -/* made by p1c0 2013-1-23. -** -** Compile with: -** gcc -Wall -pedantic -std=c99 status.c -lX11 -** -** Notes: -** bind volume keys in dwm config.h -** -** static const char *volup[] = { "dwmstatus", "volume", "up", NULL}; -** static const char *voldown[] = { "dwmstatus", "volume", "down", NULL}; -** -** static Key keys[] = { -** { 0, XF86XK_AudioRaiseVolume, spawn, {.v = volup } }, -** { 0, XF86XK_AudioLowerVolume, spawn, {.v = voldown } }, -** //{ MODKEY, XK_F11, spawn, {.v = voldown } }, -** //{ MODKEY, XK_F12, spawn, {.v = volup } }, -** }; -*/ - -#define _BSD_SOURCE -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <strings.h> -#include <sys/time.h> -#include <time.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include <X11/Xlib.h> - -char *tzargentina = "America/Buenos_Aires"; -char *tzutc = "UTC"; -char *tzberlin = "Europe/Berlin"; -char *tzla = "America/Los_Angeles"; - -static Display *dpy; - -char * -smprintf(char *fmt, ...) -{ - va_list fmtargs; - char *ret; - int len; - - va_start(fmtargs, fmt); - len = vsnprintf(NULL, 0, fmt, fmtargs); - va_end(fmtargs); - - ret = malloc(++len); - if (ret == NULL) { - perror("malloc"); - exit(1); - } - - va_start(fmtargs, fmt); - vsnprintf(ret, len, fmt, fmtargs); - va_end(fmtargs); - - return ret; -} - -void -settz(char *tzname) -{ - setenv("TZ", tzname, 1); -} - -char * -mktimes(char *fmt, char *tzname) -{ - char buf[129]; - time_t tim; - struct tm *timtm; - - memset(buf, 0, sizeof(buf)); - settz(tzname); - tim = time(NULL); - timtm = localtime(&tim); - if (timtm == NULL) { - perror("localtime"); - exit(1); - } - - if (!strftime(buf, sizeof(buf)-1, fmt, timtm)) { - fprintf(stderr, "strftime == 0\n"); - exit(1); - } - - return smprintf("%s", buf); -} - -void -setstatus(char *str) -{ - XStoreName(dpy, DefaultRootWindow(dpy), str); - XSync(dpy, False); -} - -char * -loadavg(void) -{ - double avgs[3]; - - if (getloadavg(avgs, 3) < 0) { - perror("getloadavg"); - exit(1); - } - - return smprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]); -} - -char* -runcmd(char* cmd) { - FILE* fp = popen(cmd, "r"); - if (fp == NULL) return NULL; - char ln[30]; - fgets(ln, sizeof(ln)-1, fp); - pclose(fp); - ln[strlen(ln)-1]='\0'; - return smprintf("%s", ln); -} - -int -getvolume() { - int volume; - sscanf(runcmd("amixer | grep -A 6 PCM | grep 'Front Left: Playback'\ - | grep -o '[0-9%]*%'"), "%i%%", &volume); - return volume; -} - -void -setvolume(int percent) { - char volcmd[32]; - sprintf(volcmd, "amixer set PCM %i%%", percent); - system(volcmd); -} - -char* -mkprogressbar(unsigned int size, unsigned int percent) { - unsigned int num = ((size-2)*percent)/100; - char *bar = malloc(size+1); - if (bar == NULL) { - perror("malloc"); - exit(1); - } - bar[0] = '['; - for (int i = 1; i < num+1; i++) { - bar[i] = '*'; - } - for (int i = num+1; i < size-1; i++) { - bar[i] = ' '; - } - bar[size-1] = ']'; - bar[size] = '\0'; - return bar; -} - -int -main(int argc, char *argv[]) -{ - char *status; - char *avgs; - char *tla; - int volume; - char *volumebar; - - if (!(dpy = XOpenDisplay(NULL))) { - fprintf(stderr, "dwmstatus: cannot open display.\n"); - return 1; - } - - if (argc > 1) { - if (strcmp(argv[1], "volume") == 0) { - if (strcmp(argv[2], "up") == 0) { - volume = getvolume(); - if (volume < 100) - volume += 5; - setvolume(volume); - volumebar = mkprogressbar(22, volume); - avgs = loadavg(); - tla = mktimes("%H:%M", tzla); - status = smprintf("%i%% %s | %s | %s", - volume, volumebar, avgs, tla); - setstatus(status); - free(avgs); - free(tla); - free(volumebar); - free(status); - exit(0); - } else if (strcmp(argv[2], "down") == 0) { - volume = getvolume(); - if (volume > 0) - volume -= 5; - setvolume(volume); - volumebar = mkprogressbar(22, volume); - avgs = loadavg(); - tla = mktimes("%H:%M", tzla); - status = smprintf("%i%% %s | %s | %s", - volume, volumebar, avgs, tla); - setstatus(status); - free(avgs); - free(tla); - free(volumebar); - free(status); - exit(0); - } - } - exit(0); - } - - for (;;sleep(90)) { - avgs = loadavg(); - tla = mktimes("%H:%M", tzla); - volume = getvolume(); - volumebar = mkprogressbar(22, volume); - status = smprintf("%i%% %s | %s | %s", - volume, volumebar, avgs, tla); - setstatus(status); - free(avgs); - free(tla); - free(volumebar); - free(status); - } - - XCloseDisplay(dpy); - - return 0; -} - diff --git a/dwm.suckless.org/multi-monitor.md b/dwm.suckless.org/multi-monitor.md @@ -0,0 +1,48 @@ +# Multi-monitor setup # + +If configured to use Xinerama libraries in `congik.mk`, dwm can +automatically detect configured screen outputs (monitor, overhead +projector, etc.) and their resolutions and draw the windows in the +output area accordingly. + +## Configuring monitors ## + +One of the easiest ways to configure screen outputs is via the *RandR* +X server extension using the `xrandr` tool. Without arguments it will +list the current configuration of screen outputs. + + xrandr + +For each connected output the supported resolution modes will be +printed. + +## Mirroring two outputs ## + +dwm will assume that two outputs should display identical windows and +tags if +* one of them is configured to display in the same area as the other + (``--same-as` switch) +* they have the same resolution + +After connecting a monitor, this could be an example of a mirroring +setup + + xrandr --output VGA1 --auto --same-as LVDS1 --mode 1024x768 + xrandr --output LVDS1 --mode 1024x768 + +The `--auto` switch enables the output after it was connected. + +## Two independent outputs ## + +If two screen outputs have different resolutions, dwm assumes that +they should display different windows and tag sets. It may therefore +be necessary to instruct the X server via the `xrandr` tool to draw +the outputs in different areas of the screen, as it may default to +`--same-as` and the areas would overlap. + +After connecting a monitor, this could be an example of such a setup + + xrandr --output VGA1 --auto --right-of LVDS1 + +In this case the `--auto` switch enables the output after connecting +and also sets its preferred resolution mode. diff --git a/dwm.suckless.org/patches/alwaysfullscreen.md b/dwm.suckless.org/patches/alwaysfullscreen.md @@ -0,0 +1,18 @@ +alwaysfullscreen +================ + +Description +----------- + +Do not allow focus to drift from the active fullscreen client when using +focusstack(). + +Download +-------- + +* [dwm-cdec978-alwaysfullscreen.diff](dwm-cdec978-alwaysfullscreen.diff) (323b) (20140220) + +Author +------ + +* [Chris Down](https://chrisdown.name) (cdown) <chris@chrisdown.name> diff --git a/dwm.suckless.org/patches/attachaside.md b/dwm.suckless.org/patches/attachaside.md @@ -43,9 +43,11 @@ area instead of always becoming the new master. It's basically an Download -------- +* [dwm-6.0-attachaside.diff](dwm-6.0-attachaside.diff) (1,6K) (20140412) * [dwm-5.7.2-attachaside.diff](dwm-5.7.2-attachaside.diff) (1.1K) (20091215) * [dwm-5.6.1-attachaside.diff](dwm-5.6.1-attachaside.diff) (1.1K) (20090915) -Author ------- +Authors +------- * Jerome Andrieux - `<jerome at gcu dot info>` +* Update to 6.0 by Vladimir Seleznev - `<me at wladmis dot org>` diff --git a/dwm.suckless.org/patches/bottommargin.md b/dwm.suckless.org/patches/bottommargin.md @@ -0,0 +1,13 @@ +# bottommargin + +## Description + +Adds a variable margin at the bottom for status or notification bars + +## Download + + * [dwm-6.0-bottommargin.diff](dwm-6.0-bottommargin.diff) dwm-6.0-bottommargin.diff (07.06.2014) + +## Author + + * Julian A. diff --git a/dwm.suckless.org/patches/dwm-6.0-attachaside.diff b/dwm.suckless.org/patches/dwm-6.0-attachaside.diff @@ -0,0 +1,57 @@ +diff --git a/dwm.c b/dwm.c +index 1bbb4b3..b2aa1c8 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -146,6 +146,7 @@ static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool inter + static void arrange(Monitor *m); + static void arrangemon(Monitor *m); + static void attach(Client *c); ++static void attachaside(Client *c); + static void attachstack(Client *c); + static void buttonpress(XEvent *e); + static void checkotherwm(void); +@@ -401,6 +402,17 @@ attach(Client *c) { + } + + void ++attachaside(Client *c) { ++ Client *at = nexttiled(c->mon->clients); ++ if(c->mon->sel == NULL || c->mon->sel->isfloating || !at) { ++ attach(c); ++ return; ++ } ++ c->next = at->next; ++ at->next = c; ++} ++ ++void + attachstack(Client *c) { + c->snext = c->mon->stack; + c->mon->stack = c; +@@ -1051,7 +1063,7 @@ manage(Window w, XWindowAttributes *wa) { + c->isfloating = c->oldstate = trans != None || c->isfixed; + if(c->isfloating) + XRaiseWindow(dpy, c->win); +- attach(c); ++ attachaside(c); + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +@@ -1383,7 +1395,7 @@ sendmon(Client *c, Monitor *m) { + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ +- attach(c); ++ attachaside(c); + attachstack(c); + focus(NULL); + arrange(NULL); +@@ -1818,7 +1830,7 @@ updategeom(void) { + m->clients = c->next; + detachstack(c); + c->mon = mons; +- attach(c); ++ attachaside(c); + attachstack(c); + } + if(m == selmon) diff --git a/dwm.suckless.org/patches/dwm-6.0-bottommargin.diff b/dwm.suckless.org/patches/dwm-6.0-bottommargin.diff @@ -0,0 +1,26 @@ +diff --git a/config.def.h b/config.def.h +index 77ff358..203d354 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -12,6 +12,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ ++static const unsigned int bottommargin = 20; /* Margin at the bottom for another bar */ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +diff --git a/dwm.c b/dwm.c +index 1d78655..cece290 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -1841,6 +1841,9 @@ updatebarpos(Monitor *m) { + m->wh = m->mh; + if(m->showbar) { + m->wh -= bh; ++ m->wh -= marginbottom; ++ if(!m->topbar) ++ m->wy += marginbottom; + m->by = m->topbar ? m->wy : m->wy + m->wh; + m->wy = m->topbar ? m->wy + bh : m->wy; + } diff --git a/dwm.suckless.org/patches/dwm-6.0-keypressrelease.diff b/dwm.suckless.org/patches/dwm-6.0-keypressrelease.diff @@ -0,0 +1,109 @@ +diff -up dwm-6.0-clean/config.def.h dwm-6.0-patched/config.def.h +--- dwm-6.0-clean/config.def.h 2011-12-19 16:02:46.000000000 +0100 ++++ dwm-6.0-patched/config.def.h 2014-02-28 22:21:05.254046315 +0100 +@@ -37,10 +37,10 @@ static const Layout layouts[] = { + /* key definitions */ + #define MODKEY Mod1Mask + #define TAGKEYS(KEY,TAG) \ +- { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ +- { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ +- { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ +- { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, ++ { KeyPress, MODKEY, KEY, view, {.ui = 1 << TAG} }, \ ++ { KeyPress, MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ ++ { KeyPress, MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ ++ { KeyPress, MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, + + /* helper for spawning shell commands in the pre dwm-5.0 fashion */ + #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } +@@ -50,30 +50,30 @@ static const char *dmenucmd[] = { "dmenu + static const char *termcmd[] = { "uxterm", NULL }; + + static Key keys[] = { +- /* modifier key function argument */ +- { MODKEY, XK_p, spawn, {.v = dmenucmd } }, +- { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, +- { MODKEY, XK_b, togglebar, {0} }, +- { MODKEY, XK_j, focusstack, {.i = +1 } }, +- { MODKEY, XK_k, focusstack, {.i = -1 } }, +- { MODKEY, XK_i, incnmaster, {.i = +1 } }, +- { MODKEY, XK_d, incnmaster, {.i = -1 } }, +- { MODKEY, XK_h, setmfact, {.f = -0.05} }, +- { MODKEY, XK_l, setmfact, {.f = +0.05} }, +- { MODKEY, XK_Return, zoom, {0} }, +- { MODKEY, XK_Tab, view, {0} }, +- { MODKEY|ShiftMask, XK_c, killclient, {0} }, +- { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, +- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, +- { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, +- { MODKEY, XK_space, setlayout, {0} }, +- { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, +- { MODKEY, XK_0, view, {.ui = ~0 } }, +- { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, +- { MODKEY, XK_comma, focusmon, {.i = -1 } }, +- { MODKEY, XK_period, focusmon, {.i = +1 } }, +- { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, +- { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ /* type modifier key function argument */ ++ { KeyPress, MODKEY, XK_p, spawn, {.v = dmenucmd } }, ++ { KeyPress, MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, ++ { KeyPress, MODKEY, XK_b, togglebar, {0} }, ++ { KeyPress, MODKEY, XK_j, focusstack, {.i = +1 } }, ++ { KeyPress, MODKEY, XK_k, focusstack, {.i = -1 } }, ++ { KeyPress, MODKEY, XK_i, incnmaster, {.i = +1 } }, ++ { KeyPress, MODKEY, XK_d, incnmaster, {.i = -1 } }, ++ { KeyPress, MODKEY, XK_h, setmfact, {.f = -0.05} }, ++ { KeyPress, MODKEY, XK_l, setmfact, {.f = +0.05} }, ++ { KeyPress, MODKEY, XK_Return, zoom, {0} }, ++ { KeyPress, MODKEY, XK_Tab, view, {0} }, ++ { KeyPress, MODKEY|ShiftMask, XK_c, killclient, {0} }, ++ { KeyPress, MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, ++ { KeyPress, MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, ++ { KeyPress, MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { KeyPress, MODKEY, XK_space, setlayout, {0} }, ++ { KeyPress, MODKEY|ShiftMask, XK_space, togglefloating, {0} }, ++ { KeyPress, MODKEY, XK_0, view, {.ui = ~0 } }, ++ { KeyPress, MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, ++ { KeyPress, MODKEY, XK_comma, focusmon, {.i = -1 } }, ++ { KeyPress, MODKEY, XK_period, focusmon, {.i = +1 } }, ++ { KeyPress, MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, ++ { KeyPress, MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +@@ -83,7 +83,7 @@ static Key keys[] = { + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) +- { MODKEY|ShiftMask, XK_q, quit, {0} }, ++ { KeyPress, MODKEY|ShiftMask, XK_q, quit, {0} }, + }; + + /* button definitions */ +diff -up dwm-6.0-clean/dwm.c dwm-6.0-patched/dwm.c +--- dwm-6.0-clean/dwm.c 2011-12-19 16:02:46.000000000 +0100 ++++ dwm-6.0-patched/dwm.c 2014-02-28 22:19:58.466047686 +0100 +@@ -113,6 +113,7 @@ typedef struct { + } DC; /* draw context */ + + typedef struct { ++ int type; + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); +@@ -270,6 +271,7 @@ static void (*handler[LASTEvent]) (XEven + [Expose] = expose, + [FocusIn] = focusin, + [KeyPress] = keypress, ++ [KeyRelease] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, +@@ -1087,6 +1089,7 @@ keypress(XEvent *e) { + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for(i = 0; i < LENGTH(keys); i++) + if(keysym == keys[i].keysym ++ && ev->type == keys[i].type + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) + keys[i].func(&(keys[i].arg)); diff --git a/dwm.suckless.org/patches/dwm-6.0-pango.diff b/dwm.suckless.org/patches/dwm-6.0-pango.diff @@ -4,7 +4,7 @@ index 77ff358..3bee2e7 100644 +++ b/config.def.h @@ -1,7 +1,7 @@ /* See LICENSE file for copyright and license details. */ - + /* appearance */ -static const char font[] = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*"; +static const char font[] = "Sans 8"; @@ -16,7 +16,7 @@ index 77ff358..3bee2e7 100644 static const Bool showbar = True; /* False means no bar */ static const Bool topbar = True; /* False means bottom bar */ +static const Bool statusmarkup = True; /* True means use pango markup in status message */ - + /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; diff --git a/config.mk b/config.mk @@ -25,17 +25,17 @@ index 484554a..cdfb642 100644 +++ b/config.mk @@ -15,8 +15,8 @@ XINERAMALIBS = -L${X11LIB} -lXinerama XINERAMAFLAGS = -DXINERAMA - + # includes and libs -INCS = -I. -I/usr/include -I${X11INC} -LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} +INCS = -I. -I/usr/include -I${X11INC} `pkg-config --cflags xft pango pangoxft` +LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} `pkg-config --libs xft pango pangoxft` - + # flags CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/dwm.c b/dwm.c -index 1d78655..4e73727 100644 +index 1d78655..8fae3ba 100644 --- a/dwm.c +++ b/dwm.c @@ -36,6 +36,9 @@ @@ -78,7 +78,7 @@ index 1d78655..4e73727 100644 + PangoLayout *layout; } font; } DC; /* draw context */ - + @@ -186,7 +197,7 @@ static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); @@ -89,7 +89,7 @@ index 1d78655..4e73727 100644 static long getstate(Window w); static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); @@ -254,7 +265,7 @@ static void zoom(const Arg *arg); - + /* variables */ static const char broken[] = "broken"; -static char stext[256]; @@ -102,7 +102,7 @@ index 1d78655..4e73727 100644 Layout foo = { "", NULL }; Monitor *m; + int i; - + view(&a); selmon->lt[selmon->sellt] = &foo; for(m = mons; m; m = m->next) @@ -131,6 +131,15 @@ index 1d78655..4e73727 100644 updatebars(); for(m = mons; m; m = m->next) XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); +@@ -787,7 +802,7 @@ drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { + + void + drawtext(const char *text, unsigned long col[ColLast], Bool invert) { +- char buf[256]; ++ char buf[512]; + int i, x, y, h, len, olen; + + XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); @@ -796,20 +811,25 @@ drawtext(const char *text, unsigned long col[ColLast], Bool invert) { return; olen = strlen(text); @@ -161,28 +170,28 @@ index 1d78655..4e73727 100644 + if(text == stext && statusmarkup) /* clear markup attributes */ + pango_layout_set_attributes(dc.font.layout, NULL); } - + void @@ -927,13 +947,13 @@ getatomprop(Client *c, Atom prop) { } - + unsigned long -getcolor(const char *colstr) { +getcolor(const char *colstr, XftColor *color) { Colormap cmap = DefaultColormap(dpy, screen); - XColor color; + Visual *vis = DefaultVisual(dpy, screen); - + - if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) + if(!XftColorAllocName(dpy, vis, cmap, colstr, color)) die("error, cannot allocate color '%s'\n", colstr); - return color.pixel; + return color->pixel; } - + Bool @@ -1034,36 +1054,24 @@ incnmaster(const Arg *arg) { - + void initfont(const char *fontstr) { - char *def, **missing; @@ -233,7 +242,7 @@ index 1d78655..4e73727 100644 + pango_font_metrics_unref(metrics); + g_object_unref(context); } - + #ifdef XINERAMA @@ -1612,17 +1620,16 @@ setup(void) { cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); @@ -261,7 +270,7 @@ index 1d78655..4e73727 100644 updatebars(); updatestatus(); @@ -1692,13 +1699,15 @@ tagmon(const Arg *arg) { - + int textnw(const char *text, unsigned int len) { - XRectangle r; @@ -281,5 +290,5 @@ index 1d78655..4e73727 100644 + pango_layout_set_attributes(dc.font.layout, NULL); + return r.width / PANGO_SCALE; } - + void diff --git a/dwm.suckless.org/patches/dwm-6.0-pertag-tab-v2a.diff b/dwm.suckless.org/patches/dwm-6.0-pertag-tab-v2a.diff @@ -0,0 +1,897 @@ +diff --git a/config.def.h b/config.def.h +index 77ff358..9ca435c 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -12,10 +12,22 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const Bool toptab = False; /* False means bottom tab bar */ ++ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + ++/* default layout per tags */ ++/* The first element is for all-tag view, following i-th element corresponds to */ ++/* tags[i]. Layout is referred using the layouts array index.*/ ++static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ++ + static const Rule rules[] = { + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, True, -1 }, +@@ -25,7 +37,7 @@ static const Rule rules[] = { + /* layout(s) */ + static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ + static const int nmaster = 1; /* number of clients in master area */ +-static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ ++static const Bool resizehints = False; /* True means respect size hints in tiled resizals */ + + static const Layout layouts[] = { + /* symbol arrange function */ +@@ -54,6 +66,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -101,5 +114,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 5268a06..19b4f1d 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + Windows are grouped by tags. Each window can be tagged with one or multiple + tags. Selecting certain tags displays all windows with these tags. + .P +-Each screen contains a small status bar which displays all available tags, the +-layout, the title of the focused window, and the text read from the root window +-name property, if the screen is focused. A floating window is indicated with an +-empty square and a maximised floating window is indicated with a filled square +-before the windows title. The selected tags are indicated with a different +-color. The tags of the focused window are indicated with a filled square in the +-top left corner. The tags which are applied to one or more windows are +-indicated with an empty square in the top left corner. ++Each screen contains two small status bars. ++.P ++One bar displays all available tags, the layout, the title of the focused ++window, and the text read from the root window name property, if the screen is ++focused. A floating window is indicated with an empty square and a maximised ++floating window is indicated with a filled square before the windows title. The ++selected tags are indicated with a different color. The tags of the focused ++window are indicated with a filled square in the top left corner. The tags ++which are applied to one or more windows are indicated with an empty square in ++the top left corner. ++.P ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, that tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ command. + .TP + .B Button1 + click on a tag label to display all windows with that tag, click on the layout +-label toggles between tiled and floating layout. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 1d78655..6c9bc16 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -44,7 +44,7 @@ + #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) + #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) + #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ +- * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) ++ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) + #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define MAX(A, B) ((A) > (B) ? (A) : (B)) +@@ -62,7 +62,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -102,6 +102,7 @@ typedef struct { + unsigned long norm[ColLast]; + unsigned long sel[ColLast]; + Drawable drawable; ++ Drawable tabdrawable; + GC gc; + struct { + int ascent; +@@ -124,25 +125,36 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; ++ ++#define MAXTABS 50 ++ + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + Bool showbar; ++ Bool showtab; + Bool topbar; ++ Bool toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -178,11 +190,15 @@ static void die(const char *errstr, ...); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(void); + static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]); +-static void drawtext(const char *text, unsigned long col[ColLast], Bool invert); ++static void drawtext(Drawable drawable, const char *text, unsigned long col[ColLast], Bool invert); ++//static void drawtabtext(const char *text, unsigned long col[ColLast], Bool invert); + static void enternotify(XEvent *e); + static void expose(XEvent *e); + static void focus(Client *c); ++static void focuswin(const Arg* arg); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); +@@ -229,6 +245,7 @@ static void tagmon(const Arg *arg); + static int textnw(const char *text, unsigned int len); + static void tile(Monitor *); + static void togglebar(const Arg *arg); ++static void tabmode(const Arg *arg); + static void togglefloating(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); +@@ -258,6 +275,7 @@ static char stext[256]; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ ++static int th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -287,6 +305,16 @@ static Window root; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++ Bool showtabs[LENGTH(tags) + 1]; /* display tab bar for the current tag */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -405,6 +433,10 @@ arrange(Monitor *m) { + + void + arrangemon(Monitor *m) { ++ /* Following two lines needed for the auto mode of the tab bar */ ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); ++ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if(m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -454,14 +486,32 @@ buttonpress(XEvent *e) { + else + click = ClkWinTitle; + } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } + else if((c = wintoclient(ev->window))) { + focus(c); + click = ClkClientWin; + } + for(i = 0; i < LENGTH(buttons); i++) + if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button +- && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) +- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); ++ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ ++ buttons[i].func(((click == ClkTagBar || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -491,6 +541,7 @@ cleanup(void) { + XFreeFont(dpy, dc.font.xfont); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + XFreePixmap(dpy, dc.drawable); ++ XFreePixmap(dpy, dc.tabdrawable); + XFreeGC(dpy, dc.gc); + XFreeCursor(dpy, cursor[CurNormal]); + XFreeCursor(dpy, cursor[CurResize]); +@@ -513,6 +564,8 @@ cleanupmon(Monitor *mon) { + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -538,7 +591,7 @@ clientmessage(XEvent *e) { + if(cme->message_type == netatom[NetWMState]) { + if(cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen]) + setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ +- || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); ++ || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + } + else if(cme->message_type == netatom[NetActiveWindow]) { + if(!ISVISIBLE(c)) { +@@ -581,9 +634,13 @@ configurenotify(XEvent *e) { + if(dc.drawable != 0) + XFreePixmap(dpy, dc.drawable); + dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); ++ if(dc.tabdrawable != 0) ++ XFreePixmap(dpy, dc.tabdrawable); ++ dc.tabdrawable = XCreatePixmap(dpy, root, sw, th, DefaultDepth(dpy, screen)); + updatebars(); +- for(m = mons; m; m = m->next) ++ for(m = mons; m; m = m->next){ + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -646,6 +703,7 @@ configurerequest(XEvent *e) { + Monitor * + createmon(void) { + Monitor *m; ++ int i; + + if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); +@@ -653,10 +711,34 @@ createmon(void) { + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; +- m->lt[0] = &layouts[0]; ++ m->ntabs = 0; ++ m->sellt = 0; ++ m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ ++ /* init showtab */ ++ m->pertag->showtabs[i] = m->showtab; ++ } + return m; + } + +@@ -731,13 +813,13 @@ drawbar(Monitor *m) { + for(i = 0; i < LENGTH(tags); i++) { + dc.w = TEXTW(tags[i]); + col = m->tagset[m->seltags] & 1 << i ? dc.sel : dc.norm; +- drawtext(tags[i], col, urg & 1 << i); ++ drawtext(dc.drawable, tags[i], col, urg & 1 << i); + drawsquare(m == selmon && selmon->sel && selmon->sel->tags & 1 << i, +- occ & 1 << i, urg & 1 << i, col); ++ occ & 1 << i, urg & 1 << i, col); + dc.x += dc.w; + } + dc.w = blw = TEXTW(m->ltsymbol); +- drawtext(m->ltsymbol, dc.norm, False); ++ drawtext(dc.drawable, m->ltsymbol, dc.norm, False); + dc.x += dc.w; + x = dc.x; + if(m == selmon) { /* status is only drawn on selected monitor */ +@@ -747,19 +829,20 @@ drawbar(Monitor *m) { + dc.x = x; + dc.w = m->ww - x; + } +- drawtext(stext, dc.norm, False); ++ drawtext(dc.drawable, stext, dc.norm, False); + } + else + dc.x = m->ww; + if((dc.w = dc.x - x) > bh) { + dc.x = x; + if(m->sel) { +- col = m == selmon ? dc.sel : dc.norm; +- drawtext(m->sel->name, col, False); ++ // col = m == selmon ? dc.sel : dc.norm; ++ // drawtext(dc.drawable, m->sel->name, col, False); ++ drawtext(dc.drawable, m->sel->name, dc.norm, False); + drawsquare(m->sel->isfixed, m->sel->isfloating, False, col); + } + else +- drawtext(NULL, dc.norm, False); ++ drawtext(dc.drawable, NULL, dc.norm, False); + } + XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0); + XSync(dpy, False); +@@ -774,6 +857,104 @@ drawbars(void) { + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ unsigned long *col; ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ dc.x = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ dc.w = m->tab_widths[i]; ++ col = (c == m->sel) ? dc.sel : dc.norm; ++ drawtext(dc.tabdrawable, c->name, col, 0); ++ dc.x += dc.w; ++ ++i; ++ } ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ dc.w = m->ww - view_info_w - dc.x; ++ drawtext(dc.tabdrawable, NULL, dc.norm, 0); ++ ++ /* view info */ ++ dc.x += dc.w; ++ dc.w = view_info_w; ++ drawtext(dc.tabdrawable, view_info, dc.norm, 0); ++ ++ XCopyArea(dpy, dc.tabdrawable, m->tabwin, dc.gc, 0, 0, m->ww, th, 0, 0); ++ XSync(dpy, False); ++} ++ ++ ++void + drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { + int x; + +@@ -785,13 +966,14 @@ drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { + XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x); + } + ++ + void +-drawtext(const char *text, unsigned long col[ColLast], Bool invert) { ++drawtext(Drawable drawable, const char *text, unsigned long col[ColLast], Bool invert) { + char buf[256]; + int i, x, y, h, len, olen; + + XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); +- XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); ++ XFillRectangle(dpy, drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); + if(!text) + return; + olen = strlen(text); +@@ -807,11 +989,12 @@ drawtext(const char *text, unsigned long col[ColLast], Bool invert) { + for(i = len; i && i > len - 3; buf[--i] = '.'); + XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); + if(dc.font.set) +- XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); ++ XmbDrawString(dpy, drawable, dc.font.set, dc.gc, x, y, buf, len); + else +- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); ++ XDrawString(dpy, drawable, dc.gc, x, y, buf, len); + } + ++ + void + enternotify(XEvent *e) { + Client *c; +@@ -836,8 +1019,10 @@ expose(XEvent *e) { + Monitor *m; + XExposeEvent *ev = &e->xexpose; + +- if(ev->count == 0 && (m = wintomon(ev->window))) ++ if(ev->count == 0 && (m = wintomon(ev->window))){ + drawbar(m); ++ drawtab(m); ++ } + } + + void +@@ -862,6 +1047,7 @@ focus(Client *c) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + void +@@ -911,6 +1097,19 @@ focusstack(const Arg *arg) { + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) { + int di; +@@ -919,7 +1118,7 @@ getatomprop(Client *c, Atom prop) { + Atom da, atom = None; + + if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, +- &da, &di, &dl, &dl, &p) == Success && p) { ++ &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; + XFree(p); + } +@@ -954,7 +1153,7 @@ getstate(Window w) { + Atom real; + + if(XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], +- &real, &format, &n, &extra, (unsigned char **)&p) != Success) ++ &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return -1; + if(n != 0) + result = *p; +@@ -999,13 +1198,13 @@ grabbuttons(Client *c, Bool focused) { + if(buttons[i].click == ClkClientWin) + for(j = 0; j < LENGTH(modifiers); j++) + XGrabButton(dpy, buttons[i].button, +- buttons[i].mask | modifiers[j], +- c->win, False, BUTTONMASK, +- GrabModeAsync, GrabModeSync, None, None); ++ buttons[i].mask | modifiers[j], ++ c->win, False, BUTTONMASK, ++ GrabModeAsync, GrabModeSync, None, None); + } + else + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, +- BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); ++ BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); + } + } + +@@ -1028,7 +1227,7 @@ grabkeys(void) { + + void + incnmaster(const Arg *arg) { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1139,7 +1338,7 @@ manage(Window w, XWindowAttributes *wa) { + c->x = MAX(c->x, c->mon->mx); + /* only fix client y-offset, if the client center might cover the bar */ + c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) +- && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); ++ && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + c->bw = borderpx; + + wc.border_width = c->bw; +@@ -1311,12 +1510,14 @@ propertynotify(XEvent *e) { + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if(c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if(ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1375,7 +1576,7 @@ resizemouse(const Arg *arg) { + ocx = c->x; + ocy = c->y; + if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, +- None, cursor[CurResize], CurrentTime) != GrabSuccess) ++ None, cursor[CurResize], CurrentTime) != GrabSuccess) + return; + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + do { +@@ -1418,6 +1619,7 @@ restack(Monitor *m) { + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if(!m->sel) + return; + if(m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1529,7 +1731,7 @@ void + setfullscreen(Client *c, Bool fullscreen) { + if(fullscreen) { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, +- PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); ++ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + c->isfullscreen = True; + c->oldstate = c->isfloating; + c->oldbw = c->bw; +@@ -1540,7 +1742,7 @@ setfullscreen(Client *c, Bool fullscreen) { + } + else { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, +- PropModeReplace, (unsigned char*)0, 0); ++ PropModeReplace, (unsigned char*)0, 0); + c->isfullscreen = False; + c->isfloating = c->oldstate; + c->bw = c->oldbw; +@@ -1555,10 +1757,13 @@ setfullscreen(Client *c, Bool fullscreen) { + + void + setlayout(const Arg *arg) { +- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } + if(arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if(selmon->sel) + arrange(selmon); +@@ -1576,7 +1781,7 @@ setmfact(const Arg *arg) { + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if(f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1594,6 +1799,7 @@ setup(void) { + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + bh = dc.h = dc.font.height + 2; ++ th = bh; + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1619,6 +1825,7 @@ setup(void) { + dc.sel[ColBG] = getcolor(selbgcolor); + dc.sel[ColFG] = getcolor(selfgcolor); + dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); ++ dc.tabdrawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), th, DefaultDepth(dpy, screen)); + dc.gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); + if(!dc.font.set) +@@ -1632,7 +1839,7 @@ setup(void) { + /* select for events */ + wa.cursor = cursor[CurNormal]; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask +- |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; ++ |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); +@@ -1729,13 +1936,24 @@ tile(Monitor *m) { + + void + togglebar(const Arg *arg) { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); + } + + void ++tabmode(const Arg *arg) { ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ selmon->pertag->showtabs[selmon->pertag->curtag] = selmon->showtab; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) { + if(!selmon->sel) + return; +@@ -1763,9 +1981,31 @@ toggletag(const Arg *arg) { + void + toggleview(const Arg *arg) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if(newtagset) { ++ if(newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ if (selmon->showtab != selmon->pertag->showtabs[selmon->pertag->curtag]) ++ tabmode(NULL); + focus(NULL); + arrange(selmon); + } +@@ -1828,24 +2068,47 @@ updatebars(void) { + }; + for(m = mons; m; m = m->next) { + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), +- CopyFromParent, DefaultVisual(dpy, screen), +- CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) { ++ Client *c; ++ int nvis = 0; ++ + m->wy = m->my; + m->wh = m->mh; + if(m->showbar) { + m->wh -= bh; + m->by = m->topbar ? m->wy : m->wy + m->wh; +- m->wy = m->topbar ? m->wy + bh : m->wy; +- } +- else ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + Bool +@@ -1992,7 +2255,7 @@ updatesizehints(Client *c) { + else + c->maxa = c->mina = 0.0; + c->isfixed = (c->maxw && c->minw && c->maxh && c->minh +- && c->maxw == c->minw && c->maxh == c->minh); ++ && c->maxw == c->minw && c->maxh == c->minh); + } + + void +@@ -2043,11 +2306,35 @@ updatewmhints(Client *c) { + + void + view(const Arg *arg) { ++ int i; ++ unsigned int tmptag; ++ + if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if(arg->ui & TAGMASK) ++ if(arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if(arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ if (selmon->showtab != selmon->pertag->showtabs[selmon->pertag->curtag]) ++ tabmode(NULL); + focus(NULL); + arrange(selmon); + } +@@ -2073,7 +2360,7 @@ wintomon(Window w) { + if(w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for(m = mons; m; m = m->next) +- if(w == m->barwin) ++ if(w == m->barwin || w == m->tabwin) + return m; + if((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/dwm-6.0-pertag.diff b/dwm.suckless.org/patches/dwm-6.0-pertag.diff @@ -0,0 +1,181 @@ +Author: Jan Christoph Ebersbach <jceb@e-jc.de> +URL: http://dwm.suckless.org/patches/pertag +This patch keeps layout, mwfact, barpos and nmaster per tag. + +diff -r ec4baab78314 dwm.c +--- a/dwm.c Mon Dec 19 15:38:30 2011 +0100 ++++ b/dwm.c Fri Apr 06 08:23:29 2012 +0200 +@@ -124,6 +124,7 @@ + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -143,6 +144,7 @@ + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -287,6 +289,15 @@ + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -646,6 +657,7 @@ + Monitor * + createmon(void) { + Monitor *m; ++ int i; + + if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); +@@ -657,6 +669,24 @@ + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ } + return m; + } + +@@ -1028,7 +1058,7 @@ + + void + incnmaster(const Arg *arg) { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1555,10 +1585,13 @@ + + void + setlayout(const Arg *arg) { +- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } + if(arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if(selmon->sel) + arrange(selmon); +@@ -1576,7 +1609,7 @@ + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if(f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1729,7 +1762,7 @@ + + void + togglebar(const Arg *arg) { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); +@@ -1763,9 +1796,29 @@ + void + toggleview(const Arg *arg) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if(newtagset) { ++ if(newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -2043,11 +2096,33 @@ + + void + view(const Arg *arg) { ++ int i; ++ unsigned int tmptag; ++ + if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if(arg->ui & TAGMASK) ++ if(arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if(arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } diff --git a/dwm.suckless.org/patches/dwm-6.0-pertag_without_bar.diff b/dwm.suckless.org/patches/dwm-6.0-pertag_without_bar.diff @@ -0,0 +1,166 @@ +Author: Jan Christoph Ebersbach <jceb@e-jc.de>, + Troy Sankey <sankeytms@gmail.com> +This modified pertag patch keeps the bar static. It is based on Jan +Christoph Ebersbach's dwm-6.0-pertag.diff. + +diff --git a/dwm.c b/dwm.c +index 1d78655..bd0a7d9 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -124,6 +124,7 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -143,6 +144,7 @@ struct Monitor { + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -287,6 +289,14 @@ static Window root; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -646,6 +656,7 @@ configurerequest(XEvent *e) { + Monitor * + createmon(void) { + Monitor *m; ++ int i; + + if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); +@@ -657,6 +668,21 @@ createmon(void) { + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ } + return m; + } + +@@ -1028,7 +1054,7 @@ grabkeys(void) { + + void + incnmaster(const Arg *arg) { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1555,10 +1581,13 @@ setfullscreen(Client *c, Bool fullscreen) { + + void + setlayout(const Arg *arg) { +- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } + if(arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if(selmon->sel) + arrange(selmon); +@@ -1576,7 +1605,7 @@ setmfact(const Arg *arg) { + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if(f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1763,9 +1792,27 @@ toggletag(const Arg *arg) { + void + toggleview(const Arg *arg) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if(newtagset) { ++ if(newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + focus(NULL); + arrange(selmon); + } +@@ -2043,11 +2090,31 @@ updatewmhints(Client *c) { + + void + view(const Arg *arg) { ++ int i; ++ unsigned int tmptag; ++ + if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if(arg->ui & TAGMASK) ++ if(arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if(arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + focus(NULL); + arrange(selmon); + } diff --git a/dwm.suckless.org/patches/dwm-6.0-tab-v2a.diff b/dwm.suckless.org/patches/dwm-6.0-tab-v2a.diff @@ -0,0 +1,720 @@ +diff --git a/config.def.h b/config.def.h +index 77ff358..666b9c0 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -12,6 +12,13 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const Bool toptab = False; /* False means bottom tab bar */ ++ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +@@ -25,7 +32,7 @@ static const Rule rules[] = { + /* layout(s) */ + static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ + static const int nmaster = 1; /* number of clients in master area */ +-static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ ++static const Bool resizehints = False; /* True means respect size hints in tiled resizals */ + + static const Layout layouts[] = { + /* symbol arrange function */ +@@ -54,6 +61,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -101,5 +109,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 5268a06..19b4f1d 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + Windows are grouped by tags. Each window can be tagged with one or multiple + tags. Selecting certain tags displays all windows with these tags. + .P +-Each screen contains a small status bar which displays all available tags, the +-layout, the title of the focused window, and the text read from the root window +-name property, if the screen is focused. A floating window is indicated with an +-empty square and a maximised floating window is indicated with a filled square +-before the windows title. The selected tags are indicated with a different +-color. The tags of the focused window are indicated with a filled square in the +-top left corner. The tags which are applied to one or more windows are +-indicated with an empty square in the top left corner. ++Each screen contains two small status bars. ++.P ++One bar displays all available tags, the layout, the title of the focused ++window, and the text read from the root window name property, if the screen is ++focused. A floating window is indicated with an empty square and a maximised ++floating window is indicated with a filled square before the windows title. The ++selected tags are indicated with a different color. The tags of the focused ++window are indicated with a filled square in the top left corner. The tags ++which are applied to one or more windows are indicated with an empty square in ++the top left corner. ++.P ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, that tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ command. + .TP + .B Button1 + click on a tag label to display all windows with that tag, click on the layout +-label toggles between tiled and floating layout. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 1d78655..a892b7a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -44,7 +44,7 @@ + #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) + #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) + #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ +- * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) ++ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) + #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define MAX(A, B) ((A) > (B) ? (A) : (B)) +@@ -62,7 +62,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -102,6 +102,7 @@ typedef struct { + unsigned long norm[ColLast]; + unsigned long sel[ColLast]; + Drawable drawable; ++ Drawable tabdrawable; + GC gc; + struct { + int ascent; +@@ -124,24 +125,32 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + Bool showbar; ++ Bool showtab; + Bool topbar; ++ Bool toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; + }; + +@@ -178,11 +187,15 @@ static void die(const char *errstr, ...); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(void); + static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]); +-static void drawtext(const char *text, unsigned long col[ColLast], Bool invert); ++static void drawtext(Drawable drawable, const char *text, unsigned long col[ColLast], Bool invert); ++//static void drawtabtext(const char *text, unsigned long col[ColLast], Bool invert); + static void enternotify(XEvent *e); + static void expose(XEvent *e); + static void focus(Client *c); ++static void focuswin(const Arg* arg); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); +@@ -229,6 +242,7 @@ static void tagmon(const Arg *arg); + static int textnw(const char *text, unsigned int len); + static void tile(Monitor *); + static void togglebar(const Arg *arg); ++static void tabmode(const Arg *arg); + static void togglefloating(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); +@@ -258,6 +272,7 @@ static char stext[256]; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ ++static int th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -405,6 +420,9 @@ arrange(Monitor *m) { + + void + arrangemon(Monitor *m) { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); ++ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if(m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -454,14 +472,32 @@ buttonpress(XEvent *e) { + else + click = ClkWinTitle; + } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } + else if((c = wintoclient(ev->window))) { + focus(c); + click = ClkClientWin; + } + for(i = 0; i < LENGTH(buttons); i++) + if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button +- && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) +- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); ++ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ ++ buttons[i].func(((click == ClkTagBar || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -491,6 +527,7 @@ cleanup(void) { + XFreeFont(dpy, dc.font.xfont); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + XFreePixmap(dpy, dc.drawable); ++ XFreePixmap(dpy, dc.tabdrawable); + XFreeGC(dpy, dc.gc); + XFreeCursor(dpy, cursor[CurNormal]); + XFreeCursor(dpy, cursor[CurResize]); +@@ -513,6 +550,8 @@ cleanupmon(Monitor *mon) { + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -538,7 +577,7 @@ clientmessage(XEvent *e) { + if(cme->message_type == netatom[NetWMState]) { + if(cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen]) + setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ +- || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); ++ || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + } + else if(cme->message_type == netatom[NetActiveWindow]) { + if(!ISVISIBLE(c)) { +@@ -581,9 +620,13 @@ configurenotify(XEvent *e) { + if(dc.drawable != 0) + XFreePixmap(dpy, dc.drawable); + dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); ++ if(dc.tabdrawable != 0) ++ XFreePixmap(dpy, dc.tabdrawable); ++ dc.tabdrawable = XCreatePixmap(dpy, root, sw, th, DefaultDepth(dpy, screen)); + updatebars(); +- for(m = mons; m; m = m->next) ++ for(m = mons; m; m = m->next){ + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -653,7 +696,10 @@ createmon(void) { + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; ++ m->toptab = toptab; ++ m->ntabs = 0; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -731,13 +777,13 @@ drawbar(Monitor *m) { + for(i = 0; i < LENGTH(tags); i++) { + dc.w = TEXTW(tags[i]); + col = m->tagset[m->seltags] & 1 << i ? dc.sel : dc.norm; +- drawtext(tags[i], col, urg & 1 << i); ++ drawtext(dc.drawable, tags[i], col, urg & 1 << i); + drawsquare(m == selmon && selmon->sel && selmon->sel->tags & 1 << i, +- occ & 1 << i, urg & 1 << i, col); ++ occ & 1 << i, urg & 1 << i, col); + dc.x += dc.w; + } + dc.w = blw = TEXTW(m->ltsymbol); +- drawtext(m->ltsymbol, dc.norm, False); ++ drawtext(dc.drawable, m->ltsymbol, dc.norm, False); + dc.x += dc.w; + x = dc.x; + if(m == selmon) { /* status is only drawn on selected monitor */ +@@ -747,19 +793,20 @@ drawbar(Monitor *m) { + dc.x = x; + dc.w = m->ww - x; + } +- drawtext(stext, dc.norm, False); ++ drawtext(dc.drawable, stext, dc.norm, False); + } + else + dc.x = m->ww; + if((dc.w = dc.x - x) > bh) { + dc.x = x; + if(m->sel) { +- col = m == selmon ? dc.sel : dc.norm; +- drawtext(m->sel->name, col, False); ++ // col = m == selmon ? dc.sel : dc.norm; ++ // drawtext(dc.drawable, m->sel->name, col, False); ++ drawtext(dc.drawable, m->sel->name, dc.norm, False); + drawsquare(m->sel->isfixed, m->sel->isfloating, False, col); + } + else +- drawtext(NULL, dc.norm, False); ++ drawtext(dc.drawable, NULL, dc.norm, False); + } + XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0); + XSync(dpy, False); +@@ -774,6 +821,104 @@ drawbars(void) { + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ unsigned long *col; ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ dc.x = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ dc.w = m->tab_widths[i]; ++ col = (c == m->sel) ? dc.sel : dc.norm; ++ drawtext(dc.tabdrawable, c->name, col, 0); ++ dc.x += dc.w; ++ ++i; ++ } ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ dc.w = m->ww - view_info_w - dc.x; ++ drawtext(dc.tabdrawable, NULL, dc.norm, 0); ++ ++ /* view info */ ++ dc.x += dc.w; ++ dc.w = view_info_w; ++ drawtext(dc.tabdrawable, view_info, dc.norm, 0); ++ ++ XCopyArea(dpy, dc.tabdrawable, m->tabwin, dc.gc, 0, 0, m->ww, th, 0, 0); ++ XSync(dpy, False); ++} ++ ++ ++void + drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { + int x; + +@@ -785,13 +930,14 @@ drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { + XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x); + } + ++ + void +-drawtext(const char *text, unsigned long col[ColLast], Bool invert) { ++drawtext(Drawable drawable, const char *text, unsigned long col[ColLast], Bool invert) { + char buf[256]; + int i, x, y, h, len, olen; + + XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); +- XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); ++ XFillRectangle(dpy, drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); + if(!text) + return; + olen = strlen(text); +@@ -807,11 +953,12 @@ drawtext(const char *text, unsigned long col[ColLast], Bool invert) { + for(i = len; i && i > len - 3; buf[--i] = '.'); + XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); + if(dc.font.set) +- XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); ++ XmbDrawString(dpy, drawable, dc.font.set, dc.gc, x, y, buf, len); + else +- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); ++ XDrawString(dpy, drawable, dc.gc, x, y, buf, len); + } + ++ + void + enternotify(XEvent *e) { + Client *c; +@@ -836,8 +983,10 @@ expose(XEvent *e) { + Monitor *m; + XExposeEvent *ev = &e->xexpose; + +- if(ev->count == 0 && (m = wintomon(ev->window))) ++ if(ev->count == 0 && (m = wintomon(ev->window))){ + drawbar(m); ++ drawtab(m); ++ } + } + + void +@@ -862,6 +1011,7 @@ focus(Client *c) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + void +@@ -911,6 +1061,19 @@ focusstack(const Arg *arg) { + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) { + int di; +@@ -919,7 +1082,7 @@ getatomprop(Client *c, Atom prop) { + Atom da, atom = None; + + if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, +- &da, &di, &dl, &dl, &p) == Success && p) { ++ &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; + XFree(p); + } +@@ -954,7 +1117,7 @@ getstate(Window w) { + Atom real; + + if(XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], +- &real, &format, &n, &extra, (unsigned char **)&p) != Success) ++ &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return -1; + if(n != 0) + result = *p; +@@ -999,13 +1162,13 @@ grabbuttons(Client *c, Bool focused) { + if(buttons[i].click == ClkClientWin) + for(j = 0; j < LENGTH(modifiers); j++) + XGrabButton(dpy, buttons[i].button, +- buttons[i].mask | modifiers[j], +- c->win, False, BUTTONMASK, +- GrabModeAsync, GrabModeSync, None, None); ++ buttons[i].mask | modifiers[j], ++ c->win, False, BUTTONMASK, ++ GrabModeAsync, GrabModeSync, None, None); + } + else + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, +- BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); ++ BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); + } + } + +@@ -1139,7 +1302,7 @@ manage(Window w, XWindowAttributes *wa) { + c->x = MAX(c->x, c->mon->mx); + /* only fix client y-offset, if the client center might cover the bar */ + c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) +- && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); ++ && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + c->bw = borderpx; + + wc.border_width = c->bw; +@@ -1311,12 +1474,14 @@ propertynotify(XEvent *e) { + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if(c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if(ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1375,7 +1540,7 @@ resizemouse(const Arg *arg) { + ocx = c->x; + ocy = c->y; + if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, +- None, cursor[CurResize], CurrentTime) != GrabSuccess) ++ None, cursor[CurResize], CurrentTime) != GrabSuccess) + return; + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + do { +@@ -1418,6 +1583,7 @@ restack(Monitor *m) { + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if(!m->sel) + return; + if(m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1529,7 +1695,7 @@ void + setfullscreen(Client *c, Bool fullscreen) { + if(fullscreen) { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, +- PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); ++ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + c->isfullscreen = True; + c->oldstate = c->isfloating; + c->oldbw = c->bw; +@@ -1540,7 +1706,7 @@ setfullscreen(Client *c, Bool fullscreen) { + } + else { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, +- PropModeReplace, (unsigned char*)0, 0); ++ PropModeReplace, (unsigned char*)0, 0); + c->isfullscreen = False; + c->isfloating = c->oldstate; + c->bw = c->oldbw; +@@ -1594,6 +1760,7 @@ setup(void) { + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + bh = dc.h = dc.font.height + 2; ++ th = bh; + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1619,6 +1786,7 @@ setup(void) { + dc.sel[ColBG] = getcolor(selbgcolor); + dc.sel[ColFG] = getcolor(selfgcolor); + dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); ++ dc.tabdrawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), th, DefaultDepth(dpy, screen)); + dc.gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); + if(!dc.font.set) +@@ -1632,7 +1800,7 @@ setup(void) { + /* select for events */ + wa.cursor = cursor[CurNormal]; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask +- |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; ++ |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); +@@ -1736,6 +1904,16 @@ togglebar(const Arg *arg) { + } + + void ++tabmode(const Arg *arg) { ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) { + if(!selmon->sel) + return; +@@ -1828,24 +2006,47 @@ updatebars(void) { + }; + for(m = mons; m; m = m->next) { + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), +- CopyFromParent, DefaultVisual(dpy, screen), +- CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) { ++ Client *c; ++ int nvis = 0; ++ + m->wy = m->my; + m->wh = m->mh; + if(m->showbar) { + m->wh -= bh; + m->by = m->topbar ? m->wy : m->wy + m->wh; +- m->wy = m->topbar ? m->wy + bh : m->wy; +- } +- else ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + Bool +@@ -1992,7 +2193,7 @@ updatesizehints(Client *c) { + else + c->maxa = c->mina = 0.0; + c->isfixed = (c->maxw && c->minw && c->maxh && c->minh +- && c->maxw == c->minw && c->maxh == c->minh); ++ && c->maxw == c->minw && c->maxh == c->minh); + } + + void +@@ -2073,7 +2274,7 @@ wintomon(Window w) { + if(w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for(m = mons; m; m = m->next) +- if(w == m->barwin) ++ if(w == m->barwin || w == m->tabwin) + return m; + if((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/dwm-6.1-hide_vacant_tags.diff b/dwm.suckless.org/patches/dwm-6.1-hide_vacant_tags.diff @@ -0,0 +1,38 @@ +diff --git a/dwm.c b/dwm.c +index ffc8864..0e5d3f1 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -423,9 +423,15 @@ buttonpress(XEvent *e) { + } + if(ev->window == selmon->barwin) { + i = x = 0; +- do ++ unsigned int occ = 0; ++ for(c = m->clients; c; c = c->next) ++ occ |= c->tags; ++ do { ++ /* do not reserve space for vacant tags */ ++ if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) ++ continue; + x += TEXTW(tags[i]); +- while(ev->x >= x && ++i < LENGTH(tags)); ++ } while(ev->x >= x && ++i < LENGTH(tags)); + if(i < LENGTH(tags)) { + click = ClkTagBar; + arg.ui = 1 << i; +@@ -703,11 +709,14 @@ drawbar(Monitor *m) { + } + x = 0; + for(i = 0; i < LENGTH(tags); i++) { ++ /* do not draw vacant tags */ ++ if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) ++ continue; + w = TEXTW(tags[i]); + drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i); + drw_rect(drw, x, 0, w, bh, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, +- occ & 1 << i, urg & 1 << i); ++ 0, urg & 1 << i); + x += w; + } + w = blw = TEXTW(m->ltsymbol); diff --git a/dwm.suckless.org/patches/dwm-6.1-nametag-prepend.diff b/dwm.suckless.org/patches/dwm-6.1-nametag-prepend.diff @@ -0,0 +1,71 @@ +diff --git a/config.def.h b/config.def.h +index 875885b..222745d 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -14,7 +14,10 @@ static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ + + /* tagging */ +-static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; ++#define MAX_TAGNAME_LEN 14 /* excludes TAG_PREPEND */ ++#define TAG_PREPEND "%1i:" /* formatted as 2 chars */ ++#define MAX_TAGLEN 16 /* altogether */ ++static char tags[][MAX_TAGLEN] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + + static const Rule rules[] = { + /* xprop(1): +@@ -79,6 +82,7 @@ static Key keys[] = { + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY, XK_n, nametag, {0} }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +diff --git a/dwm.c b/dwm.c +index 1bbb4b3..fefdd69 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -183,6 +183,7 @@ static void maprequest(XEvent *e); + static void monocle(Monitor *m); + static void motionnotify(XEvent *e); + static void movemouse(const Arg *arg); ++static void nametag(const Arg *arg); + static Client *nexttiled(Client *c); + static void pop(Client *); + static void propertynotify(XEvent *e); +@@ -1174,6 +1175,34 @@ movemouse(const Arg *arg) { + } + } + ++void ++nametag(const Arg *arg) { ++ char *p, name[MAX_TAGNAME_LEN]; ++ FILE *f; ++ int i; ++ ++ errno = 0; // popen(3p) says on failure it "may" set errno ++ if(!(f = popen("dmenu < /dev/null", "r"))) { ++ fprintf(stderr, "dwm: popen 'dmenu < /dev/null' failed%s%s\n", errno ? ": " : "", errno ? strerror(errno) : ""); ++ return; ++ } ++ if (!(p = fgets(name, MAX_TAGNAME_LEN, f)) && (i = errno) && ferror(f)) ++ fprintf(stderr, "dwm: fgets failed: %s\n", strerror(i)); ++ if (pclose(f) < 0) ++ fprintf(stderr, "dwm: pclose failed: %s\n", strerror(errno)); ++ if(!p) ++ return; ++ if((p = strchr(name, '\n'))) ++ *p = '\0'; ++ ++ for(i = 0; i < LENGTH(tags); i++) ++ if(selmon->tagset[selmon->seltags] & (1 << i)) { ++ sprintf(tags[i], TAG_PREPEND, i+1); ++ strcat(tags[i], name); ++ } ++ drawbars(); ++} ++ + Client * + nexttiled(Client *c) { + for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); diff --git a/dwm.suckless.org/patches/dwm-6.1-systray.diff b/dwm.suckless.org/patches/dwm-6.1-systray.diff @@ -8,9 +8,9 @@ Contributors: Index: dwm/config.def.h =================================================================== ---- dwm/config.def.h.orig 2014-02-09 15:24:27.348117387 +0100 -+++ dwm/config.def.h 2014-02-09 15:24:27.340117386 +0100 -@@ -10,6 +10,10 @@ +--- dwm/config.def.h.orig ++++ dwm/config.def.h +@@ -10,6 +10,10 @@ static const char selbgcolor[] = "# static const char selfgcolor[] = "#eeeeee"; static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ @@ -23,8 +23,8 @@ Index: dwm/config.def.h Index: dwm/dwm.c =================================================================== ---- dwm/dwm.c.orig 2014-02-09 15:24:27.348117387 +0100 -+++ dwm/dwm.c 2014-02-09 15:24:27.340117386 +0100 +--- dwm/dwm.c.orig ++++ dwm/dwm.c @@ -56,12 +56,30 @@ #define TAGMASK ((1 << LENGTH(tags)) - 1) #define TEXTW(X) (drw_font_getexts_width(drw->font, X, strlen(X)) + drw->font->h) @@ -59,7 +59,7 @@ Index: dwm/dwm.c enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -@@ -140,6 +158,12 @@ +@@ -140,6 +158,12 @@ typedef struct { int monitor; } Rule; @@ -72,7 +72,7 @@ Index: dwm/dwm.c /* function declarations */ static void applyrules(Client *c); static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact); -@@ -169,8 +193,10 @@ +@@ -169,8 +193,10 @@ static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); @@ -83,7 +83,7 @@ Index: dwm/dwm.c static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, Bool focused); static void grabkeys(void); -@@ -188,13 +214,15 @@ +@@ -188,13 +214,16 @@ static void pop(Client *); static void propertynotify(XEvent *e); static void quit(const Arg *arg); static Monitor *recttomon(int x, int y, int w, int h); @@ -92,6 +92,7 @@ Index: dwm/dwm.c +static void resizebarwin(Monitor *m); static void resizeclient(Client *c, int x, int y, int w, int h); static void resizemouse(const Arg *arg); ++static void resizerequest(XEvent *e); static void restack(Monitor *m); static void run(void); static void scan(void); @@ -100,7 +101,7 @@ Index: dwm/dwm.c static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); -@@ -205,6 +233,7 @@ +@@ -205,6 +234,7 @@ static void setup(void); static void showhide(Client *c); static void sigchld(int unused); static void spawn(const Arg *arg); @@ -108,7 +109,7 @@ Index: dwm/dwm.c static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); -@@ -222,18 +251,24 @@ +@@ -222,18 +252,24 @@ static void updateclientlist(void); static void updatenumlockmask(void); static void updatesizehints(Client *c); static void updatestatus(void); @@ -133,8 +134,11 @@ Index: dwm/dwm.c static const char broken[] = "broken"; static char stext[256]; static int screen; -@@ -257,7 +292,7 @@ +@@ -255,9 +291,10 @@ static void (*handler[LASTEvent]) (XEven + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, [PropertyNotify] = propertynotify, ++ [ResizeRequest] = resizerequest, [UnmapNotify] = unmapnotify }; -static Atom wmatom[WMLast], netatom[NetLast]; @@ -142,7 +146,7 @@ Index: dwm/dwm.c static Bool running = True; static Cur *cursor[CurLast]; static ClrScheme scheme[SchemeLast]; -@@ -471,6 +506,11 @@ +@@ -471,6 +508,11 @@ cleanup(void) { XUngrabKey(dpy, AnyKey, AnyModifier, root); while(mons) cleanupmon(mons); @@ -154,7 +158,7 @@ Index: dwm/dwm.c drw_cur_free(drw, cursor[CurNormal]); drw_cur_free(drw, cursor[CurResize]); drw_cur_free(drw, cursor[CurMove]); -@@ -516,9 +556,49 @@ +@@ -516,9 +558,49 @@ clearurgent(Client *c) { void clientmessage(XEvent *e) { @@ -204,7 +208,7 @@ Index: dwm/dwm.c if(!c) return; if(cme->message_type == netatom[NetWMState]) { -@@ -568,7 +648,7 @@ +@@ -568,7 +650,7 @@ configurenotify(XEvent *e) { drw_resize(drw, sw, bh); updatebars(); for(m = mons; m; m = m->next) @@ -213,7 +217,7 @@ Index: dwm/dwm.c focus(NULL); arrange(NULL); } -@@ -652,6 +732,11 @@ +@@ -652,6 +734,11 @@ destroynotify(XEvent *e) { if((c = wintoclient(ev->window))) unmanage(c, True); @@ -225,7 +229,7 @@ Index: dwm/dwm.c } void -@@ -696,6 +781,7 @@ +@@ -696,6 +783,7 @@ drawbar(Monitor *m) { unsigned int i, occ = 0, urg = 0; Client *c; @@ -233,17 +237,17 @@ Index: dwm/dwm.c for(c = m->clients; c; c = c->next) { occ |= c->tags; if(c->isurgent) -@@ -718,6 +804,9 @@ - if(m == selmon) { /* status is only drawn on selected monitor */ - w = TEXTW(stext); - x = m->ww - w; -+ if(showsystray && m == systraytomon(m)) { -+ x -= getsystraywidth(); -+ } - if(x < xx) { - x = xx; - w = m->ww - xx; -@@ -747,6 +836,7 @@ +@@ -726,6 +814,9 @@ drawbar(Monitor *m) { + } + else + x = m->ww; ++ if(showsystray && m == systraytomon(m)) { ++ x -= getsystraywidth(); ++ } + if((w = x - xx) > bh) { + x = xx; + if(m->sel) { +@@ -747,6 +838,7 @@ drawbars(void) { for(m = mons; m; m = m->next) drawbar(m); @@ -251,7 +255,7 @@ Index: dwm/dwm.c } void -@@ -773,8 +863,11 @@ +@@ -773,8 +865,11 @@ expose(XEvent *e) { Monitor *m; XExposeEvent *ev = &e->xexpose; @@ -264,7 +268,7 @@ Index: dwm/dwm.c } void -@@ -857,10 +950,17 @@ +@@ -857,10 +952,17 @@ getatomprop(Client *c, Atom prop) { unsigned long dl; unsigned char *p = NULL; Atom da, atom = None; @@ -283,7 +287,7 @@ Index: dwm/dwm.c XFree(p); } return atom; -@@ -892,6 +992,15 @@ +@@ -892,6 +994,15 @@ getstate(Window w) { return result; } @@ -299,7 +303,7 @@ Index: dwm/dwm.c Bool gettextprop(Window w, Atom atom, char *text, unsigned int size) { char **list = NULL; -@@ -992,7 +1101,7 @@ +@@ -992,7 +1103,7 @@ void killclient(const Arg *arg) { if(!selmon->sel) return; @@ -308,7 +312,7 @@ Index: dwm/dwm.c XGrabServer(dpy); XSetErrorHandler(xerrordummy); XSetCloseDownMode(dpy, DestroyAll); -@@ -1078,6 +1187,12 @@ +@@ -1078,6 +1189,12 @@ void maprequest(XEvent *e) { static XWindowAttributes wa; XMapRequestEvent *ev = &e->xmaprequest; @@ -321,7 +325,7 @@ Index: dwm/dwm.c if(!XGetWindowAttributes(dpy, ev->window, &wa)) return; -@@ -1194,6 +1309,16 @@ +@@ -1194,6 +1311,16 @@ propertynotify(XEvent *e) { Window trans; XPropertyEvent *ev = &e->xproperty; @@ -338,7 +342,7 @@ Index: dwm/dwm.c if((ev->window == root) && (ev->atom == XA_WM_NAME)) updatestatus(); else if(ev->state == PropertyDelete) -@@ -1243,12 +1368,33 @@ +@@ -1243,12 +1370,33 @@ recttomon(int x, int y, int w, int h) { } void @@ -372,7 +376,26 @@ Index: dwm/dwm.c resizeclient(Client *c, int x, int y, int w, int h) { XWindowChanges wc; -@@ -1398,25 +1544,35 @@ +@@ -1315,6 +1463,18 @@ resizemouse(const Arg *arg) { + } + + void ++resizerequest(XEvent *e) { ++ XResizeRequestEvent *ev = &e->xresizerequest; ++ Client *i; ++ ++ if((i = wintosystrayicon(ev->window))) { ++ updatesystrayicongeom(i, ev->width, ev->height); ++ resizebarwin(selmon); ++ updatesystray(); ++ } ++} ++ ++void + restack(Monitor *m) { + Client *c; + XEvent ev; +@@ -1398,25 +1558,35 @@ setclientstate(Client *c, long state) { } Bool @@ -419,7 +442,7 @@ Index: dwm/dwm.c } return exists; } -@@ -1429,7 +1585,7 @@ +@@ -1429,7 +1599,7 @@ setfocus(Client *c) { XA_WINDOW, 32, PropModeReplace, (unsigned char *) &(c->win), 1); } @@ -428,7 +451,7 @@ Index: dwm/dwm.c } void -@@ -1511,12 +1667,18 @@ +@@ -1511,12 +1681,18 @@ setup(void) { wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); @@ -447,7 +470,7 @@ Index: dwm/dwm.c /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); -@@ -1528,6 +1690,8 @@ +@@ -1528,6 +1704,8 @@ setup(void) { scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); @@ -456,7 +479,7 @@ Index: dwm/dwm.c /* init bars */ updatebars(); updatestatus(); -@@ -1583,6 +1747,22 @@ +@@ -1583,6 +1761,22 @@ spawn(const Arg *arg) { } } @@ -479,7 +502,7 @@ Index: dwm/dwm.c void tag(const Arg *arg) { if(selmon->sel && arg->ui & TAGMASK) { -@@ -1629,7 +1809,18 @@ +@@ -1629,7 +1823,18 @@ void togglebar(const Arg *arg) { selmon->showbar = !selmon->showbar; updatebarpos(selmon); @@ -499,7 +522,7 @@ Index: dwm/dwm.c arrange(selmon); } -@@ -1719,11 +1910,18 @@ +@@ -1719,11 +1924,18 @@ unmapnotify(XEvent *e) { else unmanage(c, False); } @@ -518,7 +541,7 @@ Index: dwm/dwm.c XSetWindowAttributes wa = { .override_redirect = True, .background_pixmap = ParentRelative, -@@ -1732,10 +1930,15 @@ +@@ -1732,10 +1944,15 @@ updatebars(void) { for(m = mons; m; m = m->next) { if (m->barwin) continue; @@ -535,7 +558,7 @@ Index: dwm/dwm.c XMapRaised(dpy, m->barwin); } } -@@ -1929,6 +2132,114 @@ +@@ -1929,6 +2146,117 @@ updatestatus(void) { } void @@ -627,14 +650,17 @@ Index: dwm/dwm.c + /* make sure the background color stays the same */ + wa.background_pixel = scheme[SchemeNorm].bg->rgb; + XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); ++ XMapRaised(dpy, i->win); + w += systrayspacing; -+ XMoveResizeWindow(dpy, i->win, (i->x = w), 0, i->w, i->h); ++ i->x = w; ++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); + w += i->w; + if(i->mon != m) + i->mon = m; + } + w = w ? w + systrayspacing : 1; + x -= w; ++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); + wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; + wc.stack_mode = Above; wc.sibling = m->barwin; + XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); @@ -650,7 +676,7 @@ Index: dwm/dwm.c updatewindowtype(Client *c) { Atom state = getatomprop(c, netatom[NetWMState]); Atom wtype = getatomprop(c, netatom[NetWMWindowType]); -@@ -1997,6 +2308,16 @@ +@@ -1997,6 +2325,16 @@ wintomon(Window w) { return selmon; } diff --git a/dwm.suckless.org/patches/dwm-6.1-tagintostack-allmaster.diff b/dwm.suckless.org/patches/dwm-6.1-tagintostack-allmaster.diff @@ -0,0 +1,32 @@ +diff --git a/dwm.c b/dwm.c +index 1bbb4b3..c4e2f0c 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -1663,6 +1663,27 @@ toggletag(const Arg *arg) { + void + toggleview(const Arg *arg) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ Client *const selected = selmon->sel; ++ ++ // clients in the master area should be the same after we add a new tag ++ Client **const masters = calloc(selmon->nmaster, sizeof(Client *)); ++ if (!masters) { ++ die("fatal: could not calloc() %u bytes \n", selmon->nmaster * sizeof(Client *)); ++ } ++ // collect (from last to first) references to all clients in the master area ++ Client *c; ++ size_t i; ++ for (c = nexttiled(selmon->clients), i = 0; c && i < selmon->nmaster; c = nexttiled(c->next), ++i) ++ masters[selmon->nmaster - (i + 1)] = c; ++ // put the master clients at the front of the list ++ // > go from the 'last' master to the 'first' ++ for (size_t i = 0; i < selmon->nmaster; ++i) ++ if (masters[i]) ++ pop(masters[i]); ++ free(masters); ++ ++ // we also want to be sure not to mutate the focus ++ focus(selected); + + if(newtagset) { + selmon->tagset[selmon->seltags] = newtagset; diff --git a/dwm.suckless.org/patches/dwm-6.1-tagintostack-onemaster.diff b/dwm.suckless.org/patches/dwm-6.1-tagintostack-onemaster.diff @@ -0,0 +1,20 @@ +diff --git a/dwm.c b/dwm.c +index 1bbb4b3..6dfad66 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -1664,6 +1664,15 @@ void + toggleview(const Arg *arg) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + ++ // the first visible client should be the same after we add a new tag ++ // we also want to be sure not to mutate the focus ++ Client *const c = nexttiled(selmon->clients); ++ if (c) { ++ Client * const selected = selmon->sel; ++ pop(c); ++ focus(selected); ++ } ++ + if(newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); diff --git a/dwm.suckless.org/patches/dwm-cdec978-alwaysfullscreen.diff b/dwm.suckless.org/patches/dwm-cdec978-alwaysfullscreen.diff @@ -0,0 +1,13 @@ +diff --git a/dwm.c b/dwm.c +index 1bbb4b3..fe5069d 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -829,7 +829,7 @@ void + focusstack(const Arg *arg) { + Client *c = NULL, *i; + +- if(!selmon->sel) ++ if(!selmon->sel || selmon->sel->isfullscreen) + return; + if(arg->i > 0) { + for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); diff --git a/dwm.suckless.org/patches/dwm-master_2013-08-27_cdec978-pertag-tab-v2a.diff b/dwm.suckless.org/patches/dwm-master_2013-08-27_cdec978-pertag-tab-v2a.diff @@ -0,0 +1,672 @@ +diff --git a/config.def.h b/config.def.h +index 875885b..406fdd8 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -12,10 +12,22 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const Bool toptab = False; /* False means bottom tab bar */ ++ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + ++/* default layout per tags */ ++/* The first element is for all-tag view, following i-th element corresponds to */ ++/* tags[i]. Layout is referred using the layouts array index.*/ ++static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ++ + static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class +@@ -29,7 +41,7 @@ static const Rule rules[] = { + /* layout(s) */ + static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ + static const int nmaster = 1; /* number of clients in master area */ +-static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ ++static const Bool resizehints = False; /* True means respect size hints in tiled resizals */ + + static const Layout layouts[] = { + /* symbol arrange function */ +@@ -59,6 +71,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -106,5 +119,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 6687011..9f5c274 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + Windows are grouped by tags. Each window can be tagged with one or multiple + tags. Selecting certain tags displays all windows with these tags. + .P +-Each screen contains a small status bar which displays all available tags, the +-layout, the title of the focused window, and the text read from the root window +-name property, if the screen is focused. A floating window is indicated with an +-empty square and a maximised floating window is indicated with a filled square +-before the windows title. The selected tags are indicated with a different +-color. The tags of the focused window are indicated with a filled square in the +-top left corner. The tags which are applied to one or more windows are +-indicated with an empty square in the top left corner. ++Each screen contains two small status bars. ++.P ++One bar displays all available tags, the layout, the title of the focused ++window, and the text read from the root window name property, if the screen is ++focused. A floating window is indicated with an empty square and a maximised ++floating window is indicated with a filled square before the windows title. The ++selected tags are indicated with a different color. The tags of the focused ++window are indicated with a filled square in the top left corner. The tags ++which are applied to one or more windows are indicated with an empty square in ++the top left corner. ++.P ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, that tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ command. + .TP + .B Button1 + click on a tag label to display all windows with that tag, click on the layout +-label toggles between tiled and floating layout. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 1bbb4b3..a9a11b2 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -63,7 +63,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -110,25 +110,36 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; ++ ++#define MAXTABS 50 ++ + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + Bool showbar; ++ Bool showtab; + Bool topbar; ++ Bool toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -163,12 +174,15 @@ static void detachstack(Client *c); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(void); + static void enternotify(XEvent *e); + static void expose(XEvent *e); + static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static void focuswin(const Arg* arg); + static Bool getrootptr(int *x, int *y); + static long getstate(Window w); + static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -205,6 +219,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void tabmode(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -239,6 +254,7 @@ static char stext[256]; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ ++static int th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -270,6 +286,15 @@ static Window root; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -389,6 +414,9 @@ arrange(Monitor *m) { + + void + arrangemon(Monitor *m) { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); ++ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if(m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -437,14 +465,32 @@ buttonpress(XEvent *e) { + else + click = ClkWinTitle; + } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } + else if((c = wintoclient(ev->window))) { + focus(c); + click = ClkClientWin; + } + for(i = 0; i < LENGTH(buttons); i++) + if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button +- && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) +- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); ++ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ ++ buttons[i].func(((click == ClkTagBar || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -499,6 +545,8 @@ cleanupmon(Monitor *mon) { + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -567,8 +615,11 @@ configurenotify(XEvent *e) { + if(updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for(m = mons; m; m = m->next) ++ //refreshing display of status bar. The tab bar is handled by the arrange() ++ //method, which is called below ++ for(m = mons; m; m = m->next){ + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -631,6 +682,7 @@ configurerequest(XEvent *e) { + Monitor * + createmon(void) { + Monitor *m; ++ int i; + + if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); +@@ -638,10 +690,31 @@ createmon(void) { + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; +- m->lt[0] = &layouts[0]; ++ m->ntabs = 0; ++ m->sellt = 0; ++ m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ } + return m; + } + +@@ -750,6 +823,104 @@ drawbars(void) { + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ int x = 0; ++ int w = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ w = m->tab_widths[i]; ++ drw_setscheme(drw, (c == m->sel) ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, th, c->name, 0); ++ x += w; ++ ++i; ++ } ++ ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ w = m->ww - view_info_w - x; ++ drw_text(drw, x, 0, w, th, NULL, 0); ++ ++ /* view info */ ++ x += w; ++ w = view_info_w; ++ drw_text(drw, x, 0, w, th, view_info, 0); ++ ++ drw_map(drw, m->tabwin, 0, 0, m->ww, th); ++} ++ ++void + enternotify(XEvent *e) { + Client *c; + Monitor *m; +@@ -773,8 +944,10 @@ expose(XEvent *e) { + Monitor *m; + XExposeEvent *ev = &e->xexpose; + +- if(ev->count == 0 && (m = wintomon(ev->window))) ++ if(ev->count == 0 && (m = wintomon(ev->window))){ + drawbar(m); ++ drawtab(m); ++ } + } + + void +@@ -801,6 +974,7 @@ focus(Client *c) { + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + void +@@ -851,6 +1025,19 @@ focusstack(const Arg *arg) { + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) { + int di; +@@ -958,7 +1145,7 @@ grabkeys(void) { + + void + incnmaster(const Arg *arg) { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1212,12 +1399,14 @@ propertynotify(XEvent *e) { + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if(c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if(ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1321,6 +1510,7 @@ restack(Monitor *m) { + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if(!m->sel) + return; + if(m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1462,10 +1652,13 @@ setfullscreen(Client *c, Bool fullscreen) { + + void + setlayout(const Arg *arg) { +- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } + if(arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if(selmon->sel) + arrange(selmon); +@@ -1483,7 +1676,7 @@ setmfact(const Arg *arg) { + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if(f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1501,6 +1694,7 @@ setup(void) { + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + bh = fnt->h + 2; ++ th = bh; + drw = drw_create(dpy, screen, root, sw, sh); + drw_setfont(drw, fnt); + updategeom(); +@@ -1627,13 +1821,23 @@ tile(Monitor *m) { + + void + togglebar(const Arg *arg) { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); + } + + void ++tabmode(const Arg *arg) { ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) { + if(!selmon->sel) + return; +@@ -1663,9 +1867,29 @@ toggletag(const Arg *arg) { + void + toggleview(const Arg *arg) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if(newtagset) { ++ if(newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -1737,20 +1961,43 @@ updatebars(void) { + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) { ++ Client *c; ++ int nvis = 0; ++ + m->wy = m->my; + m->wh = m->mh; + if(m->showbar) { + m->wh -= bh; + m->by = m->topbar ? m->wy : m->wy + m->wh; +- m->wy = m->topbar ? m->wy + bh : m->wy; +- } +- else ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + void +@@ -1960,11 +2207,33 @@ updatewmhints(Client *c) { + + void + view(const Arg *arg) { ++ int i; ++ unsigned int tmptag; ++ + if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if(arg->ui & TAGMASK) ++ if(arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if(arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -1990,7 +2259,7 @@ wintomon(Window w) { + if(w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for(m = mons; m; m = m->next) +- if(w == m->barwin) ++ if(w == m->barwin || w == m->tabwin) + return m; + if((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/dwm-master_2013-08-27_cdec978-tab-v2a.diff b/dwm.suckless.org/patches/dwm-master_2013-08-27_cdec978-tab-v2a.diff @@ -0,0 +1,505 @@ +diff --git a/config.def.h b/config.def.h +index 875885b..4f653c5 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -12,6 +12,13 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const Bool toptab = False; /* False means bottom tab bar */ ++ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +@@ -29,7 +36,7 @@ static const Rule rules[] = { + /* layout(s) */ + static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ + static const int nmaster = 1; /* number of clients in master area */ +-static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ ++static const Bool resizehints = False; /* True means respect size hints in tiled resizals */ + + static const Layout layouts[] = { + /* symbol arrange function */ +@@ -59,6 +66,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -106,5 +114,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 6687011..9f5c274 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + Windows are grouped by tags. Each window can be tagged with one or multiple + tags. Selecting certain tags displays all windows with these tags. + .P +-Each screen contains a small status bar which displays all available tags, the +-layout, the title of the focused window, and the text read from the root window +-name property, if the screen is focused. A floating window is indicated with an +-empty square and a maximised floating window is indicated with a filled square +-before the windows title. The selected tags are indicated with a different +-color. The tags of the focused window are indicated with a filled square in the +-top left corner. The tags which are applied to one or more windows are +-indicated with an empty square in the top left corner. ++Each screen contains two small status bars. ++.P ++One bar displays all available tags, the layout, the title of the focused ++window, and the text read from the root window name property, if the screen is ++focused. A floating window is indicated with an empty square and a maximised ++floating window is indicated with a filled square before the windows title. The ++selected tags are indicated with a different color. The tags of the focused ++window are indicated with a filled square in the top left corner. The tags ++which are applied to one or more windows are indicated with an empty square in ++the top left corner. ++.P ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, that tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ command. + .TP + .B Button1 + click on a tag label to display all windows with that tag, click on the layout +-label toggles between tiled and floating layout. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 1bbb4b3..b73d6ca 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -63,7 +63,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -110,24 +110,32 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + Bool showbar; ++ Bool showtab; + Bool topbar; ++ Bool toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; + }; + +@@ -163,12 +171,15 @@ static void detachstack(Client *c); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(void); + static void enternotify(XEvent *e); + static void expose(XEvent *e); + static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static void focuswin(const Arg* arg); + static Bool getrootptr(int *x, int *y); + static long getstate(Window w); + static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -205,6 +216,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void tabmode(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -239,6 +251,7 @@ static char stext[256]; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ ++static int th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -389,6 +402,9 @@ arrange(Monitor *m) { + + void + arrangemon(Monitor *m) { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); ++ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if(m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -437,14 +453,32 @@ buttonpress(XEvent *e) { + else + click = ClkWinTitle; + } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } + else if((c = wintoclient(ev->window))) { + focus(c); + click = ClkClientWin; + } + for(i = 0; i < LENGTH(buttons); i++) + if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button +- && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) +- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); ++ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ ++ buttons[i].func(((click == ClkTagBar || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -499,6 +533,8 @@ cleanupmon(Monitor *mon) { + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -567,8 +603,11 @@ configurenotify(XEvent *e) { + if(updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for(m = mons; m; m = m->next) ++ //refreshing display of status bar. The tab bar is handled by the arrange() ++ //method, which is called below ++ for(m = mons; m; m = m->next){ + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -638,7 +677,10 @@ createmon(void) { + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; ++ m->toptab = toptab; ++ m->ntabs = 0; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -750,6 +792,104 @@ drawbars(void) { + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ int x = 0; ++ int w = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ w = m->tab_widths[i]; ++ drw_setscheme(drw, (c == m->sel) ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, th, c->name, 0); ++ x += w; ++ ++i; ++ } ++ ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ w = m->ww - view_info_w - x; ++ drw_text(drw, x, 0, w, th, NULL, 0); ++ ++ /* view info */ ++ x += w; ++ w = view_info_w; ++ drw_text(drw, x, 0, w, th, view_info, 0); ++ ++ drw_map(drw, m->tabwin, 0, 0, m->ww, th); ++} ++ ++void + enternotify(XEvent *e) { + Client *c; + Monitor *m; +@@ -773,8 +913,10 @@ expose(XEvent *e) { + Monitor *m; + XExposeEvent *ev = &e->xexpose; + +- if(ev->count == 0 && (m = wintomon(ev->window))) ++ if(ev->count == 0 && (m = wintomon(ev->window))){ + drawbar(m); ++ drawtab(m); ++ } + } + + void +@@ -801,6 +943,7 @@ focus(Client *c) { + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + void +@@ -851,6 +994,19 @@ focusstack(const Arg *arg) { + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) { + int di; +@@ -1212,12 +1368,14 @@ propertynotify(XEvent *e) { + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if(c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if(ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1321,6 +1479,7 @@ restack(Monitor *m) { + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if(!m->sel) + return; + if(m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1501,6 +1660,7 @@ setup(void) { + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + bh = fnt->h + 2; ++ th = bh; + drw = drw_create(dpy, screen, root, sw, sh); + drw_setfont(drw, fnt); + updategeom(); +@@ -1634,6 +1794,16 @@ togglebar(const Arg *arg) { + } + + void ++tabmode(const Arg *arg) { ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) { + if(!selmon->sel) + return; +@@ -1737,20 +1907,43 @@ updatebars(void) { + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) { ++ Client *c; ++ int nvis = 0; ++ + m->wy = m->my; + m->wh = m->mh; + if(m->showbar) { + m->wh -= bh; + m->by = m->topbar ? m->wy : m->wy + m->wh; +- m->wy = m->topbar ? m->wy + bh : m->wy; +- } +- else ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + void +@@ -1990,7 +2183,7 @@ wintomon(Window w) { + if(w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for(m = mons; m; m = m->next) +- if(w == m->barwin) ++ if(w == m->barwin || w == m->tabwin) + return m; + if((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/dwm-nofullscreen.diff b/dwm.suckless.org/patches/dwm-nofullscreen.diff @@ -0,0 +1,11 @@ +--- dwm.c 2014-03-05 21:51:42.716156981 +0100 ++++ dwm.c-nofullscreen 2014-03-05 21:52:45.598560519 +0100 +@@ -1441,7 +1441,7 @@ setfullscreen(Client *c, Bool fullscreen + c->oldstate = c->isfloating; + c->oldbw = c->bw; + c->bw = 0; +- c->isfloating = True; ++ //c->isfloating = True; + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } diff --git a/dwm.suckless.org/patches/hide_vacant_tags.md b/dwm.suckless.org/patches/hide_vacant_tags.md @@ -0,0 +1,26 @@ +hide vacant tags +================ + +Description +----------- + +This patch prevents dwm from drawing tags with no clients +(i.e. vacant) on the bar. + +It also makes sure that pressing a tag on the bar behaves accordingly +by not reserving reactive regions on the bar for vacant tags. + +It also stops drawing empty rectangles on the bar for non-vacant +tags as there is no need anymore to distinguish vacant +tags and it offers a more visible contrast than if there were +filled/empty rectangles. + +Download +-------- + +* [dwm-6.1-hide_vacant_tags.diff](dwm-6.1-hide_vacant_tags.diff) (1169b) (20140607) + +Author +------ + +* [Ondřej Grover](mailto:ondrej.grover@gmail.com) diff --git a/dwm.suckless.org/patches/historical/taglayouts.md b/dwm.suckless.org/patches/historical/taglayouts.md @@ -18,4 +18,4 @@ This patch enables one layout per tag in contrast of one layout for all tags. - * http://na.srck.net/dwm * Updated by Jan Christoph Ebersbach - <jceb@e-jc.de> -[1]: /dwm/patches/pertag.html +[1]: /patches/pertag diff --git a/dwm.suckless.org/patches/index.md b/dwm.suckless.org/patches/index.md @@ -35,7 +35,7 @@ related projects * [awm](http://www.freaknet.org/alpt/src/alpt-wm/readme) -- (old) modified dwm with workspaces and /proc like interface * [bwm](http://lists.suckless.org/dwm/0708/3085.html) -- (old) modified dwm with extensive mouse support * [cons-wm](http://github.com/dharmatech/psilab/tree/master/cons-wm) -- minimalist wm in scheme (not tiled) -* [bug.n](http://developer.berlios.de/projects/bugn/) -- dwm for Windows written in AutoHotkey +* [bug.n](https://github.com/fuhsjr00/bug.n) -- dwm for Windows written in AutoHotkey * [dvtm](http://www.brain-dump.org/projects/dvtm/) -- virtual terminal manager (dwm on the console) * [dwm-gtx](http://s01.de/~gottox/index.cgi/proj_dwm) -- dwm branch with Xinerama support, pointer movement, different layout * [dwm-sprinkles](http://0mark.unserver.de/dwm-sprinkles/) -- dwm with colorfull bar, transparency, pre-configured pertag and more diff --git a/dwm.suckless.org/patches/keypressrelease.md b/dwm.suckless.org/patches/keypressrelease.md @@ -0,0 +1,37 @@ +keypressrelease +=== + +Description +--- + +This patch lets you specify whether a key binding should be executed at the _KeyPress_ or _KeyRelease_ event. +Executing on _KeyRelease_ fixes bugs such as `scrot -s` failing to execute from a key binding due to keys not being released in time[1][2]. + +Note that the new parameter must be added to all non-standard key bindings manually after patching. + +Usage +--- +A working `scrot -s` key binding: + + static const char *scrot[] = { "scrot", "-s", NULL }; + ... + { KeyRelease, 0, XK_Print, spawn, {.v = scrot } }, + +Or to only display the bar while the toggle key is held down (requires that it is hidden to start with), add: + + { KeyRelease, MODKEY, XK_b, togglebar, {0} }, + +Download +--- + + * [dwm-6.0-keypressrelease.diff](dwm-6.0-keypressrelease.diff) + * [dwm-6.0-keypressrelease.diff on GitHub](https://github.com/Ceryn/patches/blob/master/dwm/dwm-6.0-keypressrelease.diff) + +Author +------ + * Niklas Høj - `<niklas at hoej dot me>` + +--- + +[1] Error produced: "giblib error: couldn't grab keyboard: Resource temporarily unavailable" +[2] Old discussion thread: [http://lists.suckless.org/dev/1108/9185.html](http://lists.suckless.org/dev/1108/9185.html) diff --git a/dwm.suckless.org/patches/moveresize.md b/dwm.suckless.org/patches/moveresize.md @@ -59,7 +59,7 @@ sizes in a multi monitor setup. A second patch allows you to maximize windows. Download -------- Patches against different versions of dwm are available at -[dwm-clean-patches](https://bitbucket.org/jceb81/dwm-clean-patches/src). +[dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). * [dwm-6.1-moveresize.diff](dwm-6.1-moveresize.diff) (2095b) (20140209) * [dwm-10e232f9ace7-moveresize.diff](dwm-10e232f9ace7-moveresize.diff) (2025b) (20120406) diff --git a/dwm.suckless.org/patches/multimon-1-added-monitor-marker-to-bar.diff b/dwm.suckless.org/patches/multimon-1-added-monitor-marker-to-bar.diff @@ -0,0 +1,163 @@ +From 143e7f2f3caa047469c7219cd6b0cb704466683f Mon Sep 17 00:00:00 2001 +From: "Gary B. Genett" <me@garybgenett.net> +Date: Mon, 24 Mar 2014 13:47:59 -0700 +Subject: added monitor marker to bar +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------1.8.3.2" + +This is a multi-part message in MIME format. +--------------1.8.3.2 +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + config.def.h | 2 ++ + dwm.c | 13 +++++++++++-- + 2 files changed, 13 insertions(+), 2 deletions(-) + + +--------------1.8.3.2 +Content-Type: text/x-patch; name="0001-added-monitor-marker-to-bar.patch" +Content-Transfer-Encoding: 8bit +Content-Disposition: attachment; filename="0001-added-monitor-marker-to-bar.patch" + +diff --git a/config.def.h b/config.def.h +index 875885b864986b6b2c190f9e05d979887e563f93..af6bcfae52a8d1783158ae4f38f35b88025c04e1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -90,20 +90,22 @@ static Key keys[] = { + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, + }; + + /* button definitions */ + /* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ + static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, ++ { ClkMonNum, 0, Button1, focusmon, {.i = +1} }, ++ { ClkMonNum, 0, Button3, focusmon, {.i = -1} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, + }; +diff --git a/dwm.c b/dwm.c +index 1bbb4b35be25b0a10b8ffd093c55906b8aea96df..209dedc1417a29fb44c3ba5b6fa62f1b75b6a09f 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -56,21 +56,21 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_font_getexts_width(drw->font, X, strlen(X)) + drw->font->h) + + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ + enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkLtSymbol, ClkMonNum, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { + int i; + unsigned int ui; + float f; + const void *v; + } Arg; + + typedef struct { +@@ -231,21 +231,21 @@ static Monitor *wintomon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + + /* variables */ + static const char broken[] = "broken"; + static char stext[256]; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ +-static int bh, blw = 0; /* bar geometry */ ++static int bh, blw, bmw = 0; /* bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + [EnterNotify] = enternotify, + [Expose] = expose, +@@ -425,20 +425,22 @@ buttonpress(XEvent *e) { + i = x = 0; + do + x += TEXTW(tags[i]); + while(ev->x >= x && ++i < LENGTH(tags)); + if(i < LENGTH(tags)) { + click = ClkTagBar; + arg.ui = 1 << i; + } + else if(ev->x < x + blw) + click = ClkLtSymbol; ++ else if(ev->x < x + blw + bmw) ++ click = ClkMonNum; + else if(ev->x > selmon->ww - TEXTW(stext)) + click = ClkStatusText; + else + click = ClkWinTitle; + } + else if((c = wintoclient(ev->window))) { + focus(c); + click = ClkClientWin; + } + for(i = 0; i < LENGTH(buttons); i++) +@@ -707,28 +709,35 @@ drawbar(Monitor *m) { + drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i); + drw_rect(drw, x, 0, w, bh, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + occ & 1 << i, urg & 1 << i); + x += w; + } + w = blw = TEXTW(m->ltsymbol); + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, m->ltsymbol, 0); + x += w; ++ char custom[4] = {0}; // needs to be +1 of actual size, for some reason ++ snprintf(custom, sizeof(custom), "<%d>", m->num); ++ w = bmw = TEXTW(custom); ++ drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, bh, custom, 0); ++ x += w; + xx = x; + if(m == selmon) { /* status is only drawn on selected monitor */ + w = TEXTW(stext); + x = m->ww - w; + if(x < xx) { + x = xx; + w = m->ww - xx; + } ++ drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, stext, 0); + } + else + x = m->ww; + if((w = x - xx) > bh) { + x = xx; + if(m->sel) { + drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, m->sel->name, 0); + drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, 0); + +--------------1.8.3.2-- + + diff --git a/dwm.suckless.org/patches/multimon-2-added-n-view-wrappers-for-unified-multi-monitor.diff b/dwm.suckless.org/patches/multimon-2-added-n-view-wrappers-for-unified-multi-monitor.diff @@ -0,0 +1,181 @@ +From 2521a74714bb7c4b8787f30584f1565cc582928b Mon Sep 17 00:00:00 2001 +From: "Gary B. Genett" <me@garybgenett.net> +Date: Mon, 24 Mar 2014 13:57:47 -0700 +Subject: added n*view wrappers, for unified multi-monitor +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------1.8.3.2" + +This is a multi-part message in MIME format. +--------------1.8.3.2 +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + config.def.h | 5 +++++ + dwm.c | 24 ++++++++++++++++++++++++ + 2 files changed, 29 insertions(+) + + +--------------1.8.3.2 +Content-Type: text/x-patch; name="0002-added-n-view-wrappers-for-unified-multi-monitor.patch" +Content-Transfer-Encoding: 8bit +Content-Disposition: attachment; filename="0002-added-n-view-wrappers-for-unified-multi-monitor.patch" + +diff --git a/config.def.h b/config.def.h +index af6bcfae52a8d1783158ae4f38f35b88025c04e1..d3b6a4b7bbf244a9d824d99340e5fc6d9ecb8a56 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -32,24 +32,27 @@ static const int nmaster = 1; /* number of clients in master area */ + static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ + + static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, + }; + + /* key definitions */ ++#define WINKEY Mod4Mask + #define MODKEY Mod1Mask + #define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ ++ { MODKEY|WINKEY, KEY, nview, {.ui = 1 << TAG} }, \ ++ { MODKEY|WINKEY|ControlMask, KEY, ntoggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, + + /* helper for spawning shell commands in the pre dwm-5.0 fashion */ + #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + + /* commands */ + static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ + static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; + static const char *termcmd[] = { "st", NULL }; +@@ -99,14 +102,16 @@ static Button buttons[] = { + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkMonNum, 0, Button1, focusmon, {.i = +1} }, + { ClkMonNum, 0, Button3, focusmon, {.i = -1} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, ++ { ClkTagBar, MODKEY|WINKEY, Button1, nview, {0} }, ++ { ClkTagBar, MODKEY|WINKEY, Button3, ntoggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, + }; + +diff --git a/dwm.c b/dwm.c +index 209dedc1417a29fb44c3ba5b6fa62f1b75b6a09f..f6e9588d78a01e3263de54e94bd1559434a802c2 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -204,34 +204,36 @@ static void setmfact(const Arg *arg); + static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); + static void toggletag(const Arg *arg); ++static void ntoggleview(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, Bool setfocus); + static void unmanage(Client *c, Bool destroyed); + static void unmapnotify(XEvent *e); + static Bool updategeom(void); + static void updatebarpos(Monitor *m); + static void updatebars(void); + static void updateclientlist(void); + static void updatenumlockmask(void); + static void updatesizehints(Client *c); + static void updatestatus(void); + static void updatewindowtype(Client *c); + static void updatetitle(Client *c); + static void updatewmhints(Client *c); ++static void nview(const Arg *arg); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + + /* variables */ + static const char broken[] = "broken"; +@@ -1663,20 +1665,31 @@ toggletag(const Arg *arg) { + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if(newtags) { + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); + } + } + + void ++ntoggleview(const Arg *arg) { ++ const Arg n = {.i = +1}; ++ const int mon = selmon->num; ++ do { ++ focusmon(&n); ++ toggleview(arg); ++ } ++ while (selmon->num != mon); ++} ++ ++void + toggleview(const Arg *arg) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + + if(newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } + } + +@@ -1961,20 +1974,31 @@ updatewmhints(Client *c) { + c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; + if(wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else + c->neverfocus = False; + XFree(wmh); + } + } + + void ++nview(const Arg *arg) { ++ const Arg n = {.i = +1}; ++ const int mon = selmon->num; ++ do { ++ focusmon(&n); ++ view(arg); ++ } ++ while (selmon->num != mon); ++} ++ ++void + view(const Arg *arg) { + if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if(arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); + } + + +--------------1.8.3.2-- + + diff --git a/dwm.suckless.org/patches/multimon-3-added-reset_view-function.diff b/dwm.suckless.org/patches/multimon-3-added-reset_view-function.diff @@ -0,0 +1,168 @@ +From b9f79c3dd07b285e974b2dfdf2371a72467539bb Mon Sep 17 00:00:00 2001 +From: "Gary B. Genett" <me@garybgenett.net> +Date: Mon, 24 Mar 2014 14:27:40 -0700 +Subject: added reset_view function +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------1.8.3.2" + +This is a multi-part message in MIME format. +--------------1.8.3.2 +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + config.def.h | 8 ++++++++ + dwm.c | 21 +++++++++++++++++++++ + 2 files changed, 29 insertions(+) + + +--------------1.8.3.2 +Content-Type: text/x-patch; name="0003-added-reset_view-function.patch" +Content-Transfer-Encoding: 8bit +Content-Disposition: attachment; filename="0003-added-reset_view-function.patch" + +diff --git a/config.def.h b/config.def.h +index d3b6a4b7bbf244a9d824d99340e5fc6d9ecb8a56..92b1a461604c81c061f60780dc189a83dd697562 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -22,22 +22,28 @@ static const Rule rules[] = { + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, True, -1 }, + { "Firefox", NULL, NULL, 1 << 8, False, -1 }, + }; + + /* layout(s) */ + static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ + static const int nmaster = 1; /* number of clients in master area */ ++static const int nviews = 1; /* number of tags highlighted by default */ + static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ + ++static const int master[1]; /* nmaster override per monitor */ ++//static const int master[] = {1,-1}; /* monitor 0 = nmaster 1, monitor 1 = no nmaster (all vertical) */ ++static const int views[1]; /* nviews override per monitor */ ++//static const int views[] = {4,~0}; /* monitor 0 = nviews 4, monitor 1 = all (all highlighted) */ ++ + static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, + }; + + /* key definitions */ + #define WINKEY Mod4Mask + #define MODKEY Mod1Mask +@@ -84,30 +90,32 @@ static Key keys[] = { + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) ++ { MODKEY, XK_grave, reset_view, {0} }, + { MODKEY|ShiftMask, XK_q, quit, {0} }, + }; + + /* button definitions */ + /* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ + static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkMonNum, 0, Button1, focusmon, {.i = +1} }, ++ { ClkMonNum, 0, Button2, reset_view, {0} }, + { ClkMonNum, 0, Button3, focusmon, {.i = -1} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY|WINKEY, Button1, nview, {0} }, + { ClkTagBar, MODKEY|WINKEY, Button3, ntoggleview, {0} }, +diff --git a/dwm.c b/dwm.c +index f6e9588d78a01e3263de54e94bd1559434a802c2..2b3bf5f99c95180cfb5a3bb04b4181481fbe7bbd 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -227,20 +227,21 @@ static void updatewindowtype(Client *c); + static void updatetitle(Client *c); + static void updatewmhints(Client *c); + static void nview(const Arg *arg); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); ++static void reset_view(const Arg *arg); + + /* variables */ + static const char broken[] = "broken"; + static char stext[256]; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw, bmw = 0; /* bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -2069,28 +2070,48 @@ zoom(const Arg *arg) { + + if(!selmon->lt[selmon->sellt]->arrange + || (selmon->sel && selmon->sel->isfloating)) + return; + if(c == nexttiled(selmon->clients)) + if(!c || !(c = nexttiled(c->next))) + return; + pop(c); + } + ++void ++reset_view(const Arg *arg) { ++ const Arg n = {.i = +1}; ++ const Arg m = {.f = 1 + mfact}; ++ const int mon = selmon->num; ++ Arg i = {.i = 0}; ++ Arg v = {.ui = 0}; ++ do { ++ focusmon(&n); ++ i.i = (master[selmon->num] ? master[selmon->num] : nmaster) - selmon->nmaster; ++ incnmaster(&i); ++ setmfact(&m); ++ v.ui = (views[selmon->num] == ~0 ? ~0 : ((1 << (views[selmon->num] ? views[selmon->num] : nviews)) -1)); ++ view(&v); ++ } ++ while (selmon->num != mon); ++} ++ + int + main(int argc, char *argv[]) { + if(argc == 2 && !strcmp("-v", argv[1])) + die("dwm-"VERSION", © 2006-2012 dwm engineers, see LICENSE for details\n"); + else if(argc != 1) + die("usage: dwm [-v]\n"); + if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if(!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display\n"); + checkotherwm(); + setup(); + scan(); ++ const Arg r = {0}; ++ reset_view(&r); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; + } + +--------------1.8.3.2-- + + diff --git a/dwm.suckless.org/patches/multimon-4-added-statusall-toggle-replacing-need-for-patch.diff b/dwm.suckless.org/patches/multimon-4-added-statusall-toggle-replacing-need-for-patch.diff @@ -0,0 +1,195 @@ +From d318ffdc7ab7a365e548776a1d8ed5ccbd67cd42 Mon Sep 17 00:00:00 2001 +From: "Gary B. Genett" <me@garybgenett.net> +Date: Mon, 24 Mar 2014 14:44:04 -0700 +Subject: added statusall toggle, replacing need for patch +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------1.8.3.2" + +This is a multi-part message in MIME format. +--------------1.8.3.2 +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + config.def.h | 1 + + dwm.c | 12 ++++++------ + 2 files changed, 7 insertions(+), 6 deletions(-) + + +--------------1.8.3.2 +Content-Type: text/x-patch; name="0004-added-statusall-toggle-replacing-need-for-patch.patch" +Content-Transfer-Encoding: 8bit +Content-Disposition: attachment; filename="0004-added-statusall-toggle-replacing-need-for-patch.patch" + +diff --git a/config.def.h b/config.def.h +index 92b1a461604c81c061f60780dc189a83dd697562..b4759a569dc23754dd240da51dd12607ae93e0f3 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -24,20 +24,21 @@ static const Rule rules[] = { + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, True, -1 }, + { "Firefox", NULL, NULL, 1 << 8, False, -1 }, + }; + + /* layout(s) */ + static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ + static const int nmaster = 1; /* number of clients in master area */ + static const int nviews = 1; /* number of tags highlighted by default */ + static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ ++static const Bool statusall = False;/* True means status is shown in all bars, not just active monitor */ + + static const int master[1]; /* nmaster override per monitor */ + //static const int master[] = {1,-1}; /* monitor 0 = nmaster 1, monitor 1 = no nmaster (all vertical) */ + static const int views[1]; /* nviews override per monitor */ + //static const int views[] = {4,~0}; /* monitor 0 = nviews 4, monitor 1 = all (all highlighted) */ + + static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ +diff --git a/dwm.c b/dwm.c +index 2b3bf5f99c95180cfb5a3bb04b4181481fbe7bbd..92aa91a75a39cf1ed298a2279db9974a4f456129 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -719,21 +719,21 @@ drawbar(Monitor *m) { + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, m->ltsymbol, 0); + x += w; + char custom[4] = {0}; // needs to be +1 of actual size, for some reason + snprintf(custom, sizeof(custom), "<%d>", m->num); + w = bmw = TEXTW(custom); + drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, custom, 0); + x += w; + xx = x; +- if(m == selmon) { /* status is only drawn on selected monitor */ ++ if(m == selmon || statusall) { /* status is only drawn on selected monitor, unless statusall is true */ + w = TEXTW(stext); + x = m->ww - w; + if(x < xx) { + x = xx; + w = m->ww - xx; + } + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, stext, 0); + } + else +@@ -779,21 +779,21 @@ enternotify(XEvent *e) { + return; + focus(c); + } + + void + expose(XEvent *e) { + Monitor *m; + XExposeEvent *ev = &e->xexpose; + + if(ev->count == 0 && (m = wintomon(ev->window))) +- drawbar(m); ++ statusall ? drawbars() : drawbar(m); + } + + void + focus(Client *c) { + if(!c || !ISVISIBLE(c)) + for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); + /* was if(selmon->sel) */ + if(selmon->sel && selmon->sel != c) + unfocus(selmon->sel, False); + if(c) { +@@ -1222,21 +1222,21 @@ propertynotify(XEvent *e) { + updatesizehints(c); + break; + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); + break; + } + if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if(c == c->mon->sel) +- drawbar(c->mon); ++ statusall ? drawbars() : drawbar(c->mon); + } + if(ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); + } + } + + void + quit(const Arg *arg) { + running = False; + } +@@ -1325,21 +1325,21 @@ resizemouse(const Arg *arg) { + focus(NULL); + } + } + + void + restack(Monitor *m) { + Client *c; + XEvent ev; + XWindowChanges wc; + +- drawbar(m); ++ statusall ? drawbars() : drawbar(m); + if(!m->sel) + return; + if(m->sel->isfloating || !m->lt[m->sellt]->arrange) + XRaiseWindow(dpy, m->sel->win); + if(m->lt[m->sellt]->arrange) { + wc.stack_mode = Below; + wc.sibling = m->barwin; + for(c = m->stack; c; c = c->snext) + if(!c->isfloating && ISVISIBLE(c)) { + XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); +@@ -1475,21 +1475,21 @@ setfullscreen(Client *c, Bool fullscreen) { + void + setlayout(const Arg *arg) { + if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if(arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if(selmon->sel) + arrange(selmon); + else +- drawbar(selmon); ++ statusall ? drawbars() : drawbar(selmon); + } + + /* arg > 1.0 will set mfact absolutly */ + void + setmfact(const Arg *arg) { + float f; + + if(!arg || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; +@@ -1941,21 +1941,21 @@ updatetitle(Client *c) { + if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) + gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); + if(c->name[0] == '\0') /* hack to mark broken clients */ + strcpy(c->name, broken); + } + + void + updatestatus(void) { + if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); +- drawbar(selmon); ++ statusall ? drawbars() : drawbar(selmon); + } + + void + updatewindowtype(Client *c) { + Atom state = getatomprop(c, netatom[NetWMState]); + Atom wtype = getatomprop(c, netatom[NetWMWindowType]); + + if(state == netatom[NetWMFullscreen]) + setfullscreen(c, True); + if(wtype == netatom[NetWMWindowTypeDialog]) + +--------------1.8.3.2-- + + diff --git a/dwm.suckless.org/patches/multimon.md b/dwm.suckless.org/patches/multimon.md @@ -0,0 +1,61 @@ +multimon +======== + +Last Updated: 2014-03-25 + +Description +----------- + +These patches provide enhancements for working in a multi-monitor environment. + + * monitor marker + * Adds a small token to the bar that displays the dwm monitor number. + * The token has a mouse binding, just like the rest of the bar objects. + * unified view + * Provides two wrapper functions that work across all monitors simultaneously. + * Can change/toggle the view for all monitors, creating a unified workspace. + * reset view + * Function and settings for a "default view", for checking on primary tasks which may have been shuffled out of view doing more focused work. + * Per-monitor default settings for nmaster and tags. + * status all + * Show/update the status on all bars. + * Based on [statusbar on all monitors](http://dwm.suckless.org/patches/statusallmons), but uses a configurable boolean. + +Each can be applied independently, if desired, except for "reset view" which references "ClkMonNum" from "unified view" in "config.def.h". Simply remove the reference to get it to apply and compile. + +Example configuration settings with comments are included in "config.def.h" within each patch. + +The default settings and behavior of dwm are not modified by these patches. They provide enhancements and new options only, so there should be minimal conflict with other dwm patches. + +Usage +----- + +Each patch can be applied using "patch -p1" or "git am": + + cd dwm; patch -p1 < multimon-1-added-monitor-marker-to-bar.diff + +-OR- + + cd dwm; git pull; git am multimon-1-added-monitor-marker-to-bar.diff + +There are default settings and bindings in "config.def.h" which you will likely want to customize. + +Download +-------- + +Each of the patches was created by "format-patch" based on commit: [cdec9782a1789bd5c3a84772fd59abb9da288597](http://git.suckless.org/dwm/commit/?id=cdec9782a1789bd5c3a84772fd59abb9da288597) + + * monitor marker (6228b): [multimon-1-added-monitor-marker-to-bar.diff](multimon-1-added-monitor-marker-to-bar.diff) ([GitHub](https://github.com/garybgenett/.dwm/commit/143e7f2f3caa047469c7219cd6b0cb704466683f)) + * unified view (6558b): [multimon-2-added-n-view-wrappers-for-unified-multi-monitor.diff](multimon-2-added-n-view-wrappers-for-unified-multi-monitor.diff) ([GitHub](https://github.com/garybgenett/.dwm/commit/2521a74714bb7c4b8787f30584f1565cc582928b)) + * reset view (6816b): [multimon-3-added-reset_view-function.diff](multimon-3-added-reset_view-function.diff) ([GitHub](https://github.com/garybgenett/.dwm/commit/b9f79c3dd07b285e974b2dfdf2371a72467539bb)) + * status all (6165b): [multimon-4-added-statusall-toggle-replacing-need-for-patch.diff](multimon-4-added-statusall-toggle-replacing-need-for-patch.diff) ([GitHub](https://github.com/garybgenett/.dwm/commit/d318ffdc7ab7a365e548776a1d8ed5ccbd67cd42)) + +The patches are intended to be applied in order, one after the other, but can also be used independently. + +Author +------ + + * Gary B. Genett - [me@garybgenett.net](mailto:me@garybgenett.net) + +--- +Original Submission: [http://lists.suckless.org/dev/1403/20488.html](http://lists.suckless.org/dev/1403/20488.html) diff --git a/dwm.suckless.org/patches/nametag.md b/dwm.suckless.org/patches/nametag.md @@ -6,13 +6,17 @@ Description This patch allows you to change the names of dwm's tags while it's running. By default there is a 16 byte limit on tag names, and it uses dmenu to prompt for tag names. The 6.1 patch is for the current tip (cdec9782a1789bd5c3a84772fd59abb9da288597). It works with 6.0 but you should add -D_POSIX_C_SOURCE=2 to CPPFLAGS or you will get implicit delcaration warnings for popen and pclose. +The `prepend` version prepends the tag name with a short string which is used as a format string for `sprintf` which gets the tag number as the argument. By default a tag name "foo" given to tag 5 will become tag "5:foo". + Download -------- * [dwm-6.1-nametag.diff](dwm-6.1-nametag.diff) (2.3k) (20131002) +* [dwm-6.1-nametag-prepend.diff](dwm-6.1-nametag-prepend.diff) (2525b) (20140607) * [dwm-5.7.2-nametag.diff](dwm-5.7.2-nametag.diff) (2.5k) (20091029) Author ------ * Evan Gates (emg) <[evan.gates@gmail.com](mailto:evan.gates@gmail.com)> +* prepend version by [Ondřej Grover](mailto:ondrej.grover@gmail.com) diff --git a/dwm.suckless.org/patches/nofullscreen.m4 b/dwm.suckless.org/patches/nofullscreen.m4 @@ -0,0 +1,19 @@ +nofullscreen +============ + +Description +----------- + +Prevent clients becoming floaters when going into fullscreen, +to keep them more manageable by dwm; useful if you work mainly +in monocle layout and don't want to lose control. + +Download +-------- + +* [dwm-nofullscreen.diff](dwm-nofullscreen.diff) (389b) (20140305) + +Author +------ + +* Michael Hauser - aware water @ gmail diff --git a/dwm.suckless.org/patches/pertag.md b/dwm.suckless.org/patches/pertag.md @@ -9,10 +9,11 @@ mwfact, barpos and nmaster per tag. Download -------- Patches against different versions of dwm are available at -[dwm-clean-patches](https://bitbucket.org/jceb81/dwm-clean-patches/src). +[dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). * [dwm-6.1-pertag.diff](dwm-6.1-pertag.diff) (6630b) (20140209) * [dwm-10e232f9ace7-pertag.diff](dwm-10e232f9ace7-pertag.diff) (5955b) (20120406) + * [dwm-6.0-pertag_without_bar.diff](dwm-6.0-pertag_without_bar.diff) (5578b) (20140530) * [dwm-6.0-pertag.diff](dwm-6.0-pertag.diff) (5955b) (20120406) * [dwm-r1578-pertag.diff][9] (nmaster included in mainline) * [dwm-5.8.2-pertag\_without\_bar.diff][8] diff --git a/dwm.suckless.org/patches/runorraise.md b/dwm.suckless.org/patches/runorraise.md @@ -11,12 +11,12 @@ or how recently it has been used, or even whether it’s running or not. Usage ----- -1. In your config.h: +1 In your config.h: static const char *emacs[] = { "emacsclient", "-c", NULL, NULL, "Emacs" }; static const char *browser[] = { "firefox", NULL, NULL, NULL, "Firefox" }; -1. In your keybindings add something like: +2 In your keybindings add something like: { Modkey, XK_e, runorraise, {.v = emacs } }, { Modkey, XK_f, runorraise, {.v = firefox } }, diff --git a/dwm.suckless.org/patches/tagintostack.md b/dwm.suckless.org/patches/tagintostack.md @@ -0,0 +1,21 @@ +tagintostack +=============== + +Description +----------- +`tagintostack` new clients attach into the stack area when you toggle +a new tag into view. This means your master area will remain unchanged when +toggling views. +* the `allmaster` patch will cause all clients in the master area to be left +alone +* the `onemaster` patch will cause the first client in the master area to be left +alone (this is a much simpler piece of code) + +Download +-------- +* [dwm-6.1-tagintostack-allmaster.diff](dwm-6.1-tagintostack-allmaster.diff) (568b) (20140306) +* [dwm-6.1-tagintostack-onemaster.diff](dwm-6.1-tagintostack-onemaster.diff) (1138b) (20140306) + +Author +------ +* Aaron Burrow - <burrows.labs@gmail.com> diff --git a/st.suckless.org/faq.md b/st.suckless.org/faq.md @@ -0,0 +1,5 @@ +<abbr title="Frequently Asked Questions">FAQ</abbr> +=== + +The FAQ is maintained in the st git repository and can be read +[here](http://git.suckless.org/st/tree/FAQ). diff --git a/st.suckless.org/index.md b/st.suckless.org/index.md @@ -47,12 +47,6 @@ Configuration The configuration is done in `config.h` (like in dwm). See the comments in the generated `config.h` to edit it to your needs. - -<abbr title="Frequently Asked Questions">FAQ</abbr> ---------------- - -[Canonical FAQ](http://git.suckless.org/st/tree/FAQ) - ## Why does st not handle utmp entries? Use the excellent tool of [utmp](http://git.suckless.org/utmp/) for this task. @@ -146,7 +140,7 @@ Links Download -------- -* [st 0.4.1](http://dl.suckless.org/st/st-0.4.1.tar.gz) (2013-04-20) +* [st 0.5](http://dl.suckless.org/st/st-0.5.tar.gz) (2014-04-05) * [MIT/X Consortium license](http://git.suckless.org/st/plain/LICENSE) Development diff --git a/st.suckless.org/patches/argbbg.md b/st.suckless.org/patches/argbbg.md @@ -1,6 +1,8 @@ argbbg ====== +[![Screenshot](st-argbbg.png)](st-argbbg.png) + ## Description ## This patch allows users to change the opacity of the background. Note that **you need an X composite manager** to make this patch effective. (e.g. compton, xcompmgr) @@ -12,7 +14,8 @@ Note that **you need an X composite manager** to make this patch effective. (e.g ## Download ## * [st-0.4.1-argbbg.diff](st-0.4.1-argbbg.diff) + * [st-0.5-argbbg.diff](st-0.5-argbbg.diff) ## Author ## - * Eon S. Jeon - esjeon@lavabit.com - + * Eon S. Jeon - esjeon@hyunmu.am + * pr - protodev@gmx.net (st-0.5 port) diff --git a/st.suckless.org/patches/hide_X_cursor.md b/st.suckless.org/patches/hide_X_cursor.md @@ -0,0 +1,19 @@ +Hide X cursor +============= + +Description +----------- + +Hide the X cursor whenever a key is pressed and show it back when the mouse is +moved in the terminal window. + +Download +-------- + +* [st-0.5-hidexcursor.diff](st-0.5-hidexcursor.diff) +* [st-git-hidexcursor.diff](st-git-hidexcursor.diff) + +Author +------ + + * Ivan Delalande - colona diff --git a/st.suckless.org/patches/solarized_color_scheme.md b/st.suckless.org/patches/solarized_color_scheme.md @@ -0,0 +1,56 @@ +Solarized color scheme +====================== + +Description +----------- + +[Solarized][1] is a color scheme by Ethan Schoonover and exists in a +dark and a light variant. These patches make the solarized colors +available on st. + + +Notes +----- + +No matter if you choose the light or dark theme, to get the correct +colors, you *always* have to apply the [patch to st.c][7] (if you're +using the latest git version of st, use [this patch to st.c][3]). Then, +apply one of the patches for either the [light][4] or the [dark][5] +version of solarized. + +These patches apply to the latest git of st, but should apply to older +versions as well. + +Once applied, only the terminal colors are changed. For applications +such as tmux or vim, you may need to adjust the colors there as well. +You find more information in my [thread][2] at the arch linux forums. + + +Example +------- + +[![Screenshot](st-solarized-light.png)](st-solarized-light.png) +[![Screenshot](st-solarized-dark.png)](st-solarized-dark.png) + +The font is [Source Code Pro][6]. + +Download +-------- + + * [st-0.5-no-bold-colors.diff][7] + * [st-no-bold-colors.diff][3] + * [st-solarized-light.diff][4] + * [st-solarized-dark.diff][5] + +[1]: http://ethanschoonover.com/solarized +[2]: https://bbs.archlinux.org/viewtopic.php?id=164108 +[3]: st-no-bold-colors.diff +[4]: st-solarized-light.diff +[5]: st-solarized-dark.diff +[6]: http://en.wikipedia.org/wiki/Source_Code_Pro +[7]: st-0.5-no-bold-colors.diff + +Author +------ + + * Nils Reu&szlig;e - nilsreusse @ gmail diff --git a/st.suckless.org/patches/st-0.5-argbbg.diff b/st.suckless.org/patches/st-0.5-argbbg.diff @@ -0,0 +1,170 @@ +diff --git a/config.def.h b/config.def.h +index d1c20bd..cc9f34d 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -25,6 +25,8 @@ static char termname[] = "st-256color"; + + static unsigned int tabspaces = 8; + ++/* background opacity */ ++static const int alpha = 0xdd; + + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { +@@ -52,6 +54,7 @@ static const char *colorname[] = { + + /* more colors can be added after 255 to use with DefaultXX */ + "#cccccc", ++ "black", + }; + + +@@ -60,7 +63,7 @@ static const char *colorname[] = { + * foreground, background, cursor + */ + static unsigned int defaultfg = 7; +-static unsigned int defaultbg = 0; ++static unsigned int defaultbg = 257; + static unsigned int defaultcs = 256; + + /* +diff --git a/config.mk b/config.mk +index 9431de2..0b92bf2 100644 +--- a/config.mk ++++ b/config.mk +@@ -14,7 +14,7 @@ X11LIB = /usr/X11R6/lib + INCS = -I. -I/usr/include -I${X11INC} \ + `pkg-config --cflags fontconfig` \ + `pkg-config --cflags freetype2` +-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft \ ++LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft -lXrender \ + `pkg-config --libs fontconfig` \ + `pkg-config --libs freetype2` + + +diff --git a/st.c b/st.c +index 392f12d..5b05a5f 100644 +--- a/st.c ++++ b/st.c +@@ -65,6 +65,7 @@ char *argv0; + #define XK_ANY_MOD UINT_MAX + #define XK_NO_MOD 0 + #define XK_SWITCH_MOD (1<<13) ++#define OPAQUE 0Xff + + #define REDRAW_TIMEOUT (80*1000) /* 80 ms */ + +@@ -79,6 +80,7 @@ char *argv0; + #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) + #define IS_SET(flag) ((term.mode & (flag)) != 0) + #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000) ++#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL) + #define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x)) + + #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) +@@ -255,6 +257,7 @@ typedef struct { + int w, h; /* window width and height */ + int ch; /* char height */ + int cw; /* char width */ ++ int depth; /* bit depth */ + char state; /* focus, redraw, visible */ + } XWindow; + +@@ -2706,8 +2709,7 @@ xresize(int col, int row) { + xw.th = MAX(1, row * xw.ch); + + XFreePixmap(xw.dpy, xw.buf); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, xw.depth); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, xw.w, xw.h); + } +@@ -2738,6 +2740,13 @@ xloadcols(void) { + } + } + ++ /* set alpha value of bg color */ ++ if (USE_ARGB) { ++ dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE; //0xcccc; ++ dc.col[defaultbg].pixel &= 0x00111111; ++ dc.col[defaultbg].pixel |= alpha << 24; // 0xcc000000; ++ } ++ + /* load colors [16-255] ; same colors as xterm */ + for(i = 16, r = 0; r < 6; r++) { + for(g = 0; g < 6; g++) { +@@ -2992,7 +3001,38 @@ xinit(void) { + if(!(xw.dpy = XOpenDisplay(NULL))) + die("Can't open display\n"); + xw.scr = XDefaultScreen(xw.dpy); +- xw.vis = XDefaultVisual(xw.dpy, xw.scr); ++ xw.depth = (USE_ARGB)? 32: XDefaultDepth(xw.dpy, xw.scr); ++ if (! USE_ARGB) ++ xw.vis = XDefaultVisual(xw.dpy, xw.scr); ++ else { ++ XVisualInfo *vis; ++ XRenderPictFormat *fmt; ++ int nvi; ++ int i; ++ ++ XVisualInfo tpl = { ++ .screen = xw.scr, ++ .depth = 32, ++ .class = TrueColor ++ }; ++ ++ vis = XGetVisualInfo(xw.dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &tpl, &nvi); ++ xw.vis = NULL; ++ for(i = 0; i < nvi; i ++) { ++ fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual); ++ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) { ++ xw.vis = vis[i].visual; ++ break; ++ } ++ } ++ ++ XFree(vis); ++ ++ if (! xw.vis) { ++ fprintf(stderr, "Couldn't find ARGB visual.\n"); ++ exit(1); ++ } ++ } + + /* font */ + if(!FcInit()) +@@ -3002,7 +3042,10 @@ xinit(void) { + xloadfonts(usedfont, 0); + + /* colors */ +- xw.cmap = XDefaultColormap(xw.dpy, xw.scr); ++ if (! USE_ARGB) ++ xw.cmap = XDefaultColormap(xw.dpy, xw.scr); ++ else ++ xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr), xw.vis, None); + xloadcols(); + + /* adjust fixed window geometry */ +@@ -3036,16 +3079,17 @@ xinit(void) { + parent = opt_embed ? strtol(opt_embed, NULL, 0) : \ + XRootWindow(xw.dpy, xw.scr); + xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy, +- xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, ++ xw.w, xw.h, 0, xw.depth, InputOutput, + xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity + | CWEventMask | CWColormap, &xw.attrs); + + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; +- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, ++ xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, xw.depth); ++ dc.gc = XCreateGC(xw.dpy, ++ (USE_ARGB)? xw.buf: parent, ++ GCGraphicsExposures, + &gcvalues); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, +- DefaultDepth(xw.dpy, xw.scr)); + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); + diff --git a/st.suckless.org/patches/st-0.5-hidexcursor.diff b/st.suckless.org/patches/st-0.5-hidexcursor.diff @@ -0,0 +1,96 @@ +From d081963fc75e1656f5ee4305947384a00b9e5f39 Mon Sep 17 00:00:00 2001 +From: Colona <colona@ycc.fr> +Date: Mon, 9 Jun 2014 00:55:54 -0700 +Subject: [PATCH] Hide X cursor when typing. + +Hide the X cursor when typing in the terminal. The cursor is displayed again +when the mouse is moved. +--- + st.c | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/st.c b/st.c +index 392f12d..52deb92 100644 +--- a/st.c ++++ b/st.c +@@ -248,6 +248,8 @@ typedef struct { + Draw draw; + Visual *vis; + XSetWindowAttributes attrs; ++ Cursor cursor, bcursor; /* visible and blank cursors */ ++ bool cursorstate; /* is cursor currently visible */ + int scr; + bool isfixed; /* is fixed geometry? */ + int fx, fy, fw, fh; /* fixed geometry */ +@@ -1112,6 +1114,13 @@ void + bmotion(XEvent *e) { + int oldey, oldex, oldsby, oldsey; + ++ if(!xw.cursorstate) { ++ XDefineCursor(xw.dpy, xw.win, xw.cursor); ++ xw.cursorstate = true; ++ if(!IS_SET(MODE_MOUSEMANY)) ++ xsetpointermotion(0); ++ } ++ + if(IS_SET(MODE_MOUSE)) { + mousereport(e); + return; +@@ -2984,10 +2993,12 @@ xzoom(const Arg *arg) { + void + xinit(void) { + XGCValues gcvalues; +- Cursor cursor; + Window parent; + int sw, sh; + pid_t thispid = getpid(); ++ XColor xcwhite = {.red = 0xffff, .green = 0xffff, .blue = 0xffff}; ++ XColor xcblack = {.red = 0x0000, .green = 0x0000, .blue = 0x0000}; ++ Pixmap blankpm; + + if(!(xw.dpy = XOpenDisplay(NULL))) + die("Can't open display\n"); +@@ -3071,11 +3082,13 @@ xinit(void) { + die("XCreateIC failed. Could not obtain input method.\n"); + + /* white cursor, black outline */ +- cursor = XCreateFontCursor(xw.dpy, XC_xterm); +- XDefineCursor(xw.dpy, xw.win, cursor); +- XRecolorCursor(xw.dpy, cursor, +- &(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff}, +- &(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000}); ++ xw.cursor = XCreateFontCursor(xw.dpy, XC_xterm); ++ XDefineCursor(xw.dpy, xw.win, xw.cursor); ++ XRecolorCursor(xw.dpy, xw.cursor, &xcwhite, &xcblack); ++ xw.cursorstate = true; ++ blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1); ++ xw.bcursor = XCreatePixmapCursor(xw.dpy, blankpm, blankpm, ++ &xcblack, &xcblack, 0, 0); + + xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); + xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); +@@ -3537,6 +3550,8 @@ unmap(XEvent *ev) { + + void + xsetpointermotion(int set) { ++ if(!set && !xw.cursorstate) ++ return; + MODBIT(xw.attrs.event_mask, set, PointerMotionMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); + } +@@ -3630,6 +3645,12 @@ kpress(XEvent *ev) { + Status status; + Shortcut *bp; + ++ if(xw.cursorstate) { ++ XDefineCursor(xw.dpy, xw.win, xw.bcursor); ++ xsetpointermotion(1); ++ xw.cursorstate = false; ++ } ++ + if(IS_SET(MODE_KBDLOCK)) + return; + +-- +2.0.0 + diff --git a/st.suckless.org/patches/st-0.5-no-bold-colors.diff b/st.suckless.org/patches/st-0.5-no-bold-colors.diff @@ -0,0 +1,12 @@ +diff --git a/st.c b/st.c +--- a/st.c ++++ b/st.c +@@ -3203,7 +3203,7 @@ + if(base.mode & ATTR_BOLD) { + if(BETWEEN(base.fg, 0, 7)) { + /* basic system colors */ +- fg = &dc.col[base.fg + 8]; ++ fg = &dc.col[base.fg]; + } else if(BETWEEN(base.fg, 16, 195)) { + /* 256 colors */ + fg = &dc.col[base.fg + 36]; diff --git a/st.suckless.org/patches/st-argbbg.png b/st.suckless.org/patches/st-argbbg.png Binary files differ. diff --git a/st.suckless.org/patches/st-git-hidexcursor.diff b/st.suckless.org/patches/st-git-hidexcursor.diff @@ -0,0 +1,95 @@ +From 724b832c56384bb770fe6bd09ef38c7ac5657228 Mon Sep 17 00:00:00 2001 +From: Colona <colona@ycc.fr> +Date: Mon, 9 Jun 2014 01:00:20 -0700 +Subject: [PATCH] Hide X cursor when typing. + +Hide the X cursor when typing in the terminal. The cursor is displayed again +when the mouse is moved. +--- + st.c | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/st.c b/st.c +index 3681776..53b7e70 100644 +--- a/st.c ++++ b/st.c +@@ -249,6 +249,8 @@ typedef struct { + Draw draw; + Visual *vis; + XSetWindowAttributes attrs; ++ Cursor cursor, bcursor; /* visible and blank cursors */ ++ bool cursorstate; /* is cursor currently visible */ + int scr; + bool isfixed; /* is fixed geometry? */ + int l, t; /* left and top offset */ +@@ -1115,6 +1117,13 @@ void + bmotion(XEvent *e) { + int oldey, oldex, oldsby, oldsey; + ++ if(!xw.cursorstate) { ++ XDefineCursor(xw.dpy, xw.win, xw.cursor); ++ xw.cursorstate = true; ++ if(!IS_SET(MODE_MOUSEMANY)) ++ xsetpointermotion(0); ++ } ++ + if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + mousereport(e); + return; +@@ -2998,9 +3007,11 @@ xzoom(const Arg *arg) { + void + xinit(void) { + XGCValues gcvalues; +- Cursor cursor; + Window parent; + pid_t thispid = getpid(); ++ XColor xcwhite = {.red = 0xffff, .green = 0xffff, .blue = 0xffff}; ++ XColor xcblack = {.red = 0x0000, .green = 0x0000, .blue = 0x0000}; ++ Pixmap blankpm; + + if(!(xw.dpy = XOpenDisplay(NULL))) + die("Can't open display\n"); +@@ -3073,11 +3084,13 @@ xinit(void) { + die("XCreateIC failed. Could not obtain input method.\n"); + + /* white cursor, black outline */ +- cursor = XCreateFontCursor(xw.dpy, XC_xterm); +- XDefineCursor(xw.dpy, xw.win, cursor); +- XRecolorCursor(xw.dpy, cursor, +- &(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff}, +- &(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000}); ++ xw.cursor = XCreateFontCursor(xw.dpy, XC_xterm); ++ XDefineCursor(xw.dpy, xw.win, xw.cursor); ++ XRecolorCursor(xw.dpy, xw.cursor, &xcwhite, &xcblack); ++ xw.cursorstate = true; ++ blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1); ++ xw.bcursor = XCreatePixmapCursor(xw.dpy, blankpm, blankpm, ++ &xcblack, &xcblack, 0, 0); + + xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); + xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); +@@ -3533,6 +3546,8 @@ unmap(XEvent *ev) { + + void + xsetpointermotion(int set) { ++ if(!set && !xw.cursorstate) ++ return; + MODBIT(xw.attrs.event_mask, set, PointerMotionMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); + } +@@ -3626,6 +3641,12 @@ kpress(XEvent *ev) { + Status status; + Shortcut *bp; + ++ if(xw.cursorstate) { ++ XDefineCursor(xw.dpy, xw.win, xw.bcursor); ++ xsetpointermotion(1); ++ xw.cursorstate = false; ++ } ++ + if(IS_SET(MODE_KBDLOCK)) + return; + +-- +2.0.0 + diff --git a/st.suckless.org/patches/st-no-bold-colors.diff b/st.suckless.org/patches/st-no-bold-colors.diff @@ -0,0 +1,12 @@ +diff --git a/st.c b/st.c +--- a/st.c ++++ b/st.c +@@ -3164,7 +3164,7 @@ + * to bright system colors [8-15] + */ + if(BETWEEN(base.fg, 0, 7)) +- fg = &dc.col[base.fg + 8]; ++ fg = &dc.col[base.fg]; + + if(base.mode & ATTR_ITALIC) { + font = &dc.ibfont; diff --git a/st.suckless.org/patches/st-on-openbsd.diff b/st.suckless.org/patches/st-on-openbsd.diff @@ -0,0 +1,25 @@ +diff --git a/Makefile b/Makefile +--- a/Makefile ++++ b/Makefile +@@ -49,7 +49,8 @@ + @sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1 + @chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1 + @echo Please see the README file regarding the terminfo entry of st. +- @tic -s st.info ++ @sed 's/st\([^t].*\)/st-git\1/g' st.info > st-git.info ++ @tic -s st-git.info + + uninstall: + @echo removing executable file from ${DESTDIR}${PREFIX}/bin +diff --git a/config.def.h b/config.def.h +--- a/config.def.h ++++ b/config.def.h +@@ -44,7 +44,7 @@ + static int bellvolume = 0; + + /* TERM value */ +-static char termname[] = "st-256color"; ++static char termname[] = "st-git-256color"; + + static unsigned int tabspaces = 8; + diff --git a/st.suckless.org/patches/st-solarized-dark.diff b/st.suckless.org/patches/st-solarized-dark.diff @@ -0,0 +1,64 @@ +diff --git a/config.def.h b/config.def.h +--- a/config.def.h ++++ b/config.def.h +@@ -51,30 +51,23 @@ + + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { +- /* 8 normal colors */ +- "black", +- "red3", +- "green3", +- "yellow3", +- "blue2", +- "magenta3", +- "cyan3", +- "gray90", +- +- /* 8 bright colors */ +- "gray50", +- "red", +- "green", +- "yellow", +- "#5c5cff", +- "magenta", +- "cyan", +- "white", +- +- [255] = 0, +- +- /* more colors can be added after 255 to use with DefaultXX */ +- "#cccccc", ++ /* solarized dark */ ++ "#073642", /* 0: black */ ++ "#dc322f", /* 1: red */ ++ "#859900", /* 2: green */ ++ "#b58900", /* 3: yellow */ ++ "#268bd2", /* 4: blue */ ++ "#d33682", /* 5: magenta */ ++ "#2aa198", /* 6: cyan */ ++ "#eee8d5", /* 7: white */ ++ "#002b36", /* 8: brblack */ ++ "#cb4b16", /* 9: brred */ ++ "#586e75", /* 10: brgreen */ ++ "#657b83", /* 11: bryellow */ ++ "#839496", /* 12: brblue */ ++ "#6c71c4", /* 13: brmagenta*/ ++ "#93a1a1", /* 14: brcyan */ ++ "#fdf6e3", /* 15: brwhite */ + }; + + +@@ -82,9 +75,9 @@ + * Default colors (colorname index) + * foreground, background, cursor + */ +-static unsigned int defaultfg = 7; +-static unsigned int defaultbg = 0; +-static unsigned int defaultcs = 256; ++static unsigned int defaultfg = 12; ++static unsigned int defaultbg = 8; ++static unsigned int defaultcs = 14; + + /* + * Colors used, when the specific fg == defaultfg. So in reverse mode this diff --git a/st.suckless.org/patches/st-solarized-dark.png b/st.suckless.org/patches/st-solarized-dark.png Binary files differ. diff --git a/st.suckless.org/patches/st-solarized-light.diff b/st.suckless.org/patches/st-solarized-light.diff @@ -0,0 +1,64 @@ +diff --git a/config.def.h b/config.def.h +--- a/config.def.h ++++ b/config.def.h +@@ -51,30 +51,23 @@ + + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { +- /* 8 normal colors */ +- "black", +- "red3", +- "green3", +- "yellow3", +- "blue2", +- "magenta3", +- "cyan3", +- "gray90", +- +- /* 8 bright colors */ +- "gray50", +- "red", +- "green", +- "yellow", +- "#5c5cff", +- "magenta", +- "cyan", +- "white", +- +- [255] = 0, +- +- /* more colors can be added after 255 to use with DefaultXX */ +- "#cccccc", ++ /* solarized light */ ++ "#eee8d5", /* 0: black */ ++ "#dc322f", /* 1: red */ ++ "#859900", /* 2: green */ ++ "#b58900", /* 3: yellow */ ++ "#268bd2", /* 4: blue */ ++ "#d33682", /* 5: magenta */ ++ "#2aa198", /* 6: cyan */ ++ "#073642", /* 7: white */ ++ "#fdf6e3", /* 8: brblack */ ++ "#cb4b16", /* 9: brred */ ++ "#93a1a1", /* 10: brgreen */ ++ "#839496", /* 11: bryellow */ ++ "#657b83", /* 12: brblue */ ++ "#6c71c4", /* 13: brmagenta*/ ++ "#586e75", /* 14: brcyan */ ++ "#002b36", /* 15: brwhite */ + }; + + +@@ -82,9 +75,9 @@ + * Default colors (colorname index) + * foreground, background, cursor + */ +-static unsigned int defaultfg = 7; +-static unsigned int defaultbg = 0; +-static unsigned int defaultcs = 256; ++static unsigned int defaultfg = 12; ++static unsigned int defaultbg = 8; ++static unsigned int defaultcs = 14; + + /* + * Colors used, when the specific fg == defaultfg. So in reverse mode this diff --git a/st.suckless.org/patches/st-solarized-light.png b/st.suckless.org/patches/st-solarized-light.png Binary files differ. diff --git a/st.suckless.org/patches/st_on_openbsd.md b/st.suckless.org/patches/st_on_openbsd.md @@ -0,0 +1,42 @@ +st on OpenBSD +============= + +Description +----------- + +On OpenBSD, terminfo descriptions are searched for in terminfo +databases, before terminfo files are considered. At present, +the terminfo information stored in the systemwide terminfo db +are from st version 0.1.1, conflicting with newer versions of +st and thus causing misbehaviour. This patch renames the name +of st to st-git, so that no terminfo description can be found +in the OpenBSD database, and therefore the right information is +loaded from the installed terminfo file. + + +Notes +----- + +I tested this diff with the latest code from git, but the principle +applies to the released versions of st as well, i just have not tried +them. Once a new stable version of st is out, the corresponding +changes to st.info can be pushed upstream (to ncurses) and then be +merged back to OpenBSD, making this patch obsolete for future stable +versions of st. More information on the issue can be found in this +[thread][1]. + + + +Download +-------- + +* [st-on-openbsd.diff][2] + +[1]: http://marc.info/?l=openbsd-misc&m=139540215025526&w=2 +[2]: st-on-openbsd.diff + + +Author +------ + + * Nils Reuße - nilsreusse @ gmail diff --git a/st.suckless.org/screenshots/20h-2012-s.png b/st.suckless.org/screenshots/20h-2012-s.png Binary files differ. diff --git a/st.suckless.org/screenshots/hendry-s.png b/st.suckless.org/screenshots/hendry-s.png Binary files differ. diff --git a/st.suckless.org/screenshots/index.md b/st.suckless.org/screenshots/index.md @@ -1,6 +1,6 @@ [![Screenshot](putain-ouais-s.png)](putain-ouais.png) -[![Screenshot](hendry.png)] +[![Screenshot](hendry-s.png)](hendry.png) -[![Screenshot](20h-2012.png)] +[![Screenshot](20h-2012-s.png)](20h-2012.png) diff --git a/sta.li/masterplan.md b/sta.li/masterplan.md @@ -20,9 +20,10 @@ Steps ----------------------------------------- Steps in this direction have been done in the -[sabotage](https://github.com/rofl0r/sabotage) and -[bootstrap](https://github.com/pikhq/bootstrap-linux) -Linux distribution. They should serve as a base for further +[sabotage](https://github.com/rofl0r/sabotage), +[bootstrap](https://github.com/pikhq/bootstrap-linux) and +[morpheus](http://morpheus.2f30.org) +Linux distributions. They should serve as a base for further a further extension to make a base environment which can be used by the average suckless user. @@ -55,4 +56,3 @@ Maintaining an Open Source community isn't just maintaining the status quo. It needs templates and tutorials on how to spread the suckless ways of thinking and being productive. The web is not a part of this. - diff --git a/sta.li/sandbox.md b/sta.li/sandbox.md @@ -27,8 +27,8 @@ Ideas Quick Ideas ----------- -* use mdev for device management - * add a »dev« command for controlling mdev +* use nldev + mdev/smdev for device management + * add a »dev« command for controlling mdev/smdev * make some minor/major/netlink extractor to a script * use busybox as first userland, then gradually move to sbase + ubase * use svc for services @@ -40,4 +40,3 @@ Needed application replacements * new bluetooth stack without dbus * simple mDNS without dbus - diff --git a/sta.li/technologies.md b/sta.li/technologies.md @@ -8,8 +8,8 @@ are: Be as simple as possible and as useful as possible. * [sbase](http://git.suckless.org/sbase/) * [ubase](http://git.suckless.org/ubase/) * init + * [sinit](http://git.suckless.org/sinit/) * [cinit](http://www.nico.schottelius.org/software/cinit/) - * [sinit](http://git.2f30.org/sinit/) * services * [runit](http://smarden.org/runit/) * [svc](http://git.r-36.net/svc/) diff --git a/suckless.org/index.md b/suckless.org/index.md @@ -5,6 +5,19 @@ Read more about our [philosophy](/philosophy) and join us on the [mailing list]( News ==== +2014-05-01 +---------- + +[ubase 0.1](http://tools.suckless.org/ubase) released: [download](http://dl.suckless.org/ubase/ubase-0.1.tar.gz) + +2014-04-18 +---------- +[sinit 0.9](http://tools.suckless.org/sinit) released: [download](http://dl.suckless.org/sinit/sinit-0.9.tar.gz) + +2014-04-05 +---------- +[st 0.5](http://st.suckless.org) released: [download](http://dl.suckless.org/st/st-0.5.tar.gz) + 2014-01-21 ---------- [tabbed 0.6](http://tools.suckless.org/tabbed) released: [download](http://dl.suckless.org/tools/tabbed-0.6.tar.gz) diff --git a/suckless.org/other_projects.md b/suckless.org/other_projects.md @@ -17,7 +17,7 @@ There are several other projects which are inspired by the spirit of suckless. * [passman](http://nibble.develsec.org/hg/toys/file/) - password manager + other nibble suckless toys * [pcw](https://bitbucket.org/emg/pcw) - popup chat windows (ii front end) * [ptar](https://github.com/joodan-van-github/ptar) - plain-text archives: like tar, but better -* [sdhcp](http://galos.no-ip.org/sdhcp) - tiny dchp client +* [sdhcp](http://galos.no-ip.org/sdhcp) - tiny dhcp client * [slpm](https://github.com/radare/slpm) - suckless package manager * [sltar](https://github.com/Gottox/sltar) - suckless tar * [bgs](https://github.com/Gottox/bgs) - background setter @@ -28,6 +28,8 @@ There are several other projects which are inspired by the spirit of suckless. * [ssg](http://nibble.develsec.org/projects/ssg.html) - slide generation system with markdown-like syntax * [sup](http://git.suckless.org/sup) - minimalistic sudo replacement * [sw](http://nibble.develsec.org/projects/sw.html) - minimalistic web framework +* [swx](http://yeuxdelibad.net/Programmation/swx_en.html) - static site + generator (inspired from sw) * [xicon](http://hg.youterm.com/xicon/) (dead link) - small icon-based dzen-like utility * [xkev](https://github.com/vlaadbrain/xkev) - simply simulate KeyPress/KeyRelease * [xbmouse](https://github.com/vlaadbrain/xbmouse) - simply bind a mouse button to a command diff --git a/suckless.org/people/Sin.md b/suckless.org/people/Sin.md @@ -1,7 +1,7 @@ sin === -I am the original author and maintainer of [ubase](http://git.suckless.org/ubase). -I also maintain and actively contribute to [sbase](http://git.suckless.org/sbase). +I am the original author and maintainer of [ubase](http://tools.suckless.org/ubase) and [sinit](http://tools.suckless.org/sinit). +I also maintain and actively contribute to [sbase](http://tools.suckless.org/sbase). Some of my other projects are hosted at [2f30](http://git.2f30.org). diff --git a/suckless.org/people/cls.md b/suckless.org/people/cls.md @@ -2,4 +2,4 @@ cls === I'm the lead developer of [dmenu](http://tools.suckless.org/dmenu) and -[sbase](http://git.suckless.org/sbase), I help out with [dwm](http://dwm.suckless.org), and I'm the maintainer of [lsw](http://tools.suckless.org/lsw) and [tabbed](http://tools.suckless.org/tabbed). I think that's about it. ☺ +original author of [sbase](http://git.suckless.org/sbase), I help out with [dwm](http://dwm.suckless.org), and I'm the maintainer of [lsw](http://tools.suckless.org/lsw) and [tabbed](http://tools.suckless.org/tabbed). I think that's about it. ☺ diff --git a/suckless.org/project_ideas.md b/suckless.org/project_ideas.md @@ -34,28 +34,6 @@ The listed ideas generally require good knowledge of C and experience with Unix-like operating systems. The difficulty ranges from medium to high. An academic background in computer science is desirable but not essential. -### Port [stali](http://sta.li) to use bionic - -So far [static linux](http://sta.li) requires [uclibc](http://www.uclibc.org) for most userland -tools and glibc for some exceptions. We'd like to replace the uclibc dependency -with bionic from android. - -This project can be achieved on a tool by tool basis because it will require -some code patching. - -***Requirements:*** Good C/Unix knowledge is necessary. - -### Port [9base](http://tools.suckless.org/9base) to use bionic - -So far 9base uses the hosts C library. We'd like to replace the host libc -dependency with bionic from android. - -This project can be extended to do the same in -[plan9port](http://swtch.com/plan9port/) by Russ Cox, if the progress is fast -in achieving this. - -***Requirements:*** Good C/Unix knowledge is essential. - ### Write ld wrapper or replacement for static linking The GNU autotools such as automake and autoconf are completely unusable in @@ -123,19 +101,6 @@ structure: ***Requirements:*** Good C/Shell/HTML knowledge would be desirable. -### Yet another less sucking editor - -Although vi(m) does its job, it has become a monster over the years. We -believe there is a gap between [ed](http://man.cat-v.org/plan_9/1/ed), -[sam](http://sam.cat-v.org), [acme](http://acme.cat-v.org) and vim which must -be filled with a completely new, less-sucking editor. - -It has been [suggested](http://lists.suckless.org/dev/0911/2255.html) that -"...a curses interface for the sam protocol would be interesting and perhaps -even useful..." - -***Requirements:*** Good C knowledge and knowledge of I/O APIs is essential. - ### Improve sltar [sltar](https://github.com/Gottox/sltar) is a simplified tar diff --git a/suckless.org/rocks.md b/suckless.org/rocks.md @@ -11,8 +11,8 @@ compatible with other suckless projects. libc implementations -------------------- -* [uClibc](http://www.uclibc.org/) - strives to be a minimalist C library suitable for embedded computing * [musl](http://www.musl-libc.org/) - standard C library that attempts to be even smaller than uClibc +* [uClibc](http://www.uclibc.org/) - strives to be a minimalist C library suitable for embedded computing * See also: [embedded libc comparison](http://www.etalabs.net/compare_libcs.html) Compression @@ -33,6 +33,7 @@ Miscellaneous * [libev](http://software.schmorp.de/pkg/libev.html) - high performance event-loop modeled after libevent but much smaller (dual licensed under 2-clause BSD and GPL) * [termbox](https://github.com/nsf/termbox) - simple ncurses-like library for creating TUIs * [ccv](https://github.com/liuliu/ccv) - C-based/Cached/Core Computer Vision Library, A Modern Computer Vision Library +* [morpheus](http://morpheus.2f30.org) - a statically linked musl based Linux distro Programs ======== @@ -70,8 +71,7 @@ Feed aggregators IRC Clients ----------- * [Irc](http://swtch.com/irc/) -* [acme:SAC](http://caerwyn.com/acme/index.html) -* [ii](/programs/ii.html) - A FIFO based IRC client which is part of the suckless.org project. +* [ii](http://tools.suckless.org/ii/) - A FIFO based IRC client which is part of the suckless.org project. * [ircc](http://www.r-36.net/src/Various/ircc.tgz) - A no-frills, ncurses free, console-based IRC client. * [ircrc](http://plan9.bell-labs.com/sources/contrib/fgb/rc/ircrc) - An rc-based IRC client similar to ircc. Needs minor modification to run on UNIX. * [irssi](http://www.irssi.org/) diff --git a/surf.suckless.org/files/autologin.md b/surf.suckless.org/files/autologin.md @@ -6,7 +6,7 @@ remove your passwords from the script!!!__ * Twitter - #!/bin/sh + #!/bin/bash read -p "Name: " name read -p "Password: " -s pass echo diff --git a/surf.suckless.org/files/kiosk_mode.md b/surf.suckless.org/files/kiosk_mode.md @@ -61,7 +61,7 @@ following file to '/home/kiosk/.i3/config': set $mod Mod4 # shut down system with systemd/polkit - bindsym Control+Shift+E exec /usr/bin/systemctl poweroff + bindsym Control+Shift+C exec /usr/bin/systemctl poweroff # make surf start in fullscreen for_window [class="Surf"] fullscreen diff --git a/surf.suckless.org/patches/chromekeys.md b/surf.suckless.org/patches/chromekeys.md @@ -0,0 +1,21 @@ +chrome keys +=========== + +Description +----------- + +This patch offers alternative keybindings that are both more Vim-like +and more Chrome-like. Specifically, mod-{h,j,k,l} (small jump) and +mod-{b,f} (page jump) are mapped to navigation within the current +window, mod-o and mod-i navigate the history (as they do in Vim), +mod-u is view source, and mod-shift-u opens the inspector. + +Download +-------- + +* [surf-0.6-chromekeys.diff](surf-0.6-chromekeys.diff) (20140519) + +Author +------ + +* Steven Dee (mrdomino) <[steve@smartercode.net](mailto:steve@smartercode.net)> diff --git a/surf.suckless.org/patches/surf-0.6-chromekeys.diff b/surf.suckless.org/patches/surf-0.6-chromekeys.diff @@ -0,0 +1,106 @@ +diff --git a/config.def.h b/config.def.h +index 80a0feb..f8dc533 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -71,23 +71,23 @@ static Key keys[] = { + { MODKEY, GDK_minus, zoom, { .i = -1 } }, + { MODKEY, GDK_plus, zoom, { .i = +1 } }, + +- { MODKEY, GDK_l, navigate, { .i = +1 } }, +- { MODKEY, GDK_h, navigate, { .i = -1 } }, ++ { MODKEY, GDK_i, navigate, { .i = +1 } }, ++ { MODKEY, GDK_o, navigate, { .i = -1 } }, + + { MODKEY, GDK_j, scroll_v, { .i = +1 } }, + { MODKEY, GDK_k, scroll_v, { .i = -1 } }, + { MODKEY, GDK_b, scroll_v, { .i = -10000 } }, ++ { MODKEY, GDK_f, scroll_v, { .i = +10000 } }, + { MODKEY, GDK_space, scroll_v, { .i = +10000 } }, +- { MODKEY, GDK_i, scroll_h, { .i = +1 } }, +- { MODKEY, GDK_u, scroll_h, { .i = -1 } }, ++ { MODKEY, GDK_l, scroll_h, { .i = +1 } }, ++ { MODKEY, GDK_h, scroll_h, { .i = -1 } }, + + { 0, GDK_F11, fullscreen, { 0 } }, + { 0, GDK_Escape, stop, { 0 } }, +- { MODKEY, GDK_o, source, { 0 } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_o, inspector, { 0 } }, ++ { MODKEY, GDK_u, source, { 0 } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_u, inspector, { 0 } }, + + { MODKEY, GDK_g, spawn, SETPROP("_SURF_URI", "_SURF_GO") }, +- { MODKEY, GDK_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND") }, + { MODKEY, GDK_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND") }, + + { MODKEY, GDK_n, find, { .b = TRUE } }, +diff --git a/surf.1 b/surf.1 +index 1530ec6..8d1caf4 100644 +--- a/surf.1 ++++ b/surf.1 +@@ -114,10 +114,10 @@ which surf should use. + .B Escape + Stops loading current page or stops download. + .TP +-.B Ctrl\-h ++.B Ctrl\-o + Walks back the history. + .TP +-.B Ctrl\-l ++.B Ctrl\-i + Walks forward the history. + .TP + .B Ctrl\-k +@@ -126,17 +126,20 @@ Scrolls page upwards. + .B Ctrl\-j + Scrolls page downwards. + .TP ++.B Ctrl\-h ++Scroll horizontally to the left. ++.TP ++.B Ctrl\-l ++Scroll horizontally to the right. ++.TP + .B Ctrl\-b + Scroll up one whole page view. + .TP +-.B Ctrl\-Space ++.B Ctrl\-f or Ctrl\-Space + Scroll down one whole page view. + .TP +-.B Ctrl\-i +-Scroll horizontally to the right. +-.TP + .B Ctrl\-u +-Scroll horizontally to the left. ++Show the sourcecode of the current page. + .TP + .B Ctrl\-Shift\-k or Ctrl\-+ + Zooms page in. +@@ -147,7 +150,7 @@ Zooms page out + .B Ctrl\-Shift\-q + Resets Zoom + .TP +-.B Ctrl\-f and Ctrl\-\e ++.B Ctrl\-/ + Opens the search-bar. + .TP + .B Ctrl\-n +@@ -174,9 +177,6 @@ Reloads the website without using the cache. + .B Ctrl\-y + Copies current URI to primary selection. + .TP +-.B Ctrl\-o +-Show the sourcecode of the current page. +-.TP + .B Ctrl\-Shift\-a + Toggle through the the + .I cookie policies. +@@ -196,7 +196,7 @@ Toggle if the + .I stylefile + file should be loaded. This will reload the page. + .TP +-.B Ctrl\-Shift\-o ++.B Ctrl\-Shift\-u + Open the Web Inspector (Developer Tools) window for the current page. + .TP + .B Ctrl\-Shift\-s diff --git a/tools.suckless.org/dmenu/patches/dmenu-git-xft.diff b/tools.suckless.org/dmenu/patches/dmenu-git-xft.diff @@ -0,0 +1,467 @@ +From ef0b72fc2725cdfcb731837bf411fe343abe33e7 Mon Sep 17 00:00:00 2001 +From: Hiltjo Posthuma <hiltjo@codemadness.org> +Date: Thu, 27 Mar 2014 15:02:33 +0100 +Subject: [PATCH] xft: adjust xft patch against current git version + +Signed-off-by: Hiltjo Posthuma <hiltjo@codemadness.org> +--- + config.mk | 8 +++-- + dmenu.1 | 2 +- + dmenu.c | 56 ++++++++++++++++++++------------ + draw.c | 110 +++++++++++++++++++++++++++++++++++++++++--------------------- + draw.h | 19 +++++++---- + 5 files changed, 129 insertions(+), 66 deletions(-) + +diff --git a/config.mk b/config.mk +index c0d466b..04e2dce 100644 +--- a/config.mk ++++ b/config.mk +@@ -12,9 +12,13 @@ X11LIB = /usr/X11R6/lib + XINERAMALIBS = -lXinerama + XINERAMAFLAGS = -DXINERAMA + ++# Xft, comment if you don't want it ++XFTINC = -I/usr/include/freetype2 ++XFTLIBS = -lXft -lXrender -lfreetype -lz -lfontconfig ++ + # includes and libs +-INCS = -I${X11INC} +-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ++INCS = -I${X11INC} ${XFTINC} ++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${XFTLIBS} + + # flags + CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +diff --git a/dmenu.1 b/dmenu.1 +index bbee17d..bc6bb1a 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -58,7 +58,7 @@ dmenu is displayed on the monitor supplied. + defines the prompt to be displayed to the left of the input field. + .TP + .BI \-fn " font" +-defines the font or font set used. ++defines the font or font set used. eg. "fixed" or "Monospace-12:normal" (a xft font) + .TP + .BI \-nb " color" + defines the normal background color. +diff --git a/dmenu.c b/dmenu.c +index 8d9bbb6..463e022 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -17,6 +17,7 @@ + * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) + #define MIN(a,b) ((a) < (b) ? (a) : (b)) + #define MAX(a,b) ((a) > (b) ? (a) : (b)) ++#define DEFFONT "fixed" /* xft example: "Monospace-11" */ + + typedef struct Item Item; + struct Item { +@@ -27,6 +28,7 @@ struct Item { + + static void appenditem(Item *item, Item **list, Item **last); + static void calcoffsets(void); ++static void cleanup(void); + static char *cistrstr(const char *s, const char *sub); + static void drawmenu(void); + static void grabkeyboard(void); +@@ -44,9 +46,9 @@ static char text[BUFSIZ] = ""; + static int bh, mw, mh; + static int inputw, promptw; + static size_t cursor = 0; +-static unsigned long normcol[ColLast]; +-static unsigned long selcol[ColLast]; +-static unsigned long outcol[ColLast]; ++static ColorSet *normcol; ++static ColorSet *selcol; ++static ColorSet *outcol; + static Atom clip, utf8; + static DC *dc; + static Item *items = NULL; +@@ -55,6 +57,8 @@ static Item *prev, *curr, *next, *sel; + static Window win; + static XIC xic; + static int mon = -1; ++static Bool running = True; ++static int ret = EXIT_SUCCESS; + + #include "config.h" + +@@ -103,7 +107,10 @@ main(int argc, char *argv[]) { + usage(); + + dc = initdc(); +- initfont(dc, font); ++ initfont(dc, font ? font : DEFFONT); ++ normcol = initcolor(dc, normfgcolor, normbgcolor); ++ selcol = initcolor(dc, selfgcolor, selbgcolor); ++ outcol = initcolor(dc, outfgcolor, outbgcolor); + + if(fast) { + grabkeyboard(); +@@ -116,7 +123,8 @@ main(int argc, char *argv[]) { + setup(); + run(); + +- return 1; /* unreachable */ ++ cleanup(); ++ return ret; + } + + void +@@ -159,6 +167,15 @@ cistrstr(const char *s, const char *sub) { + } + + void ++cleanup(void) { ++ freecol(dc, normcol); ++ freecol(dc, selcol); ++ XDestroyWindow(dc->dpy, win); ++ XUngrabKeyboard(dc->dpy, CurrentTime); ++ freedc(dc); ++} ++ ++void + drawmenu(void) { + int curpos; + Item *item; +@@ -166,7 +183,7 @@ drawmenu(void) { + dc->x = 0; + dc->y = 0; + dc->h = bh; +- drawrect(dc, 0, 0, mw, mh, True, BG(dc, normcol)); ++ drawrect(dc, 0, 0, mw, mh, True, normcol->BG); + + if(prompt && *prompt) { + dc->w = promptw; +@@ -177,7 +194,7 @@ drawmenu(void) { + dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw; + drawtext(dc, text, normcol); + if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w) +- drawrect(dc, curpos, 2, 1, dc->h - 4, True, FG(dc, normcol)); ++ drawrect(dc, curpos, 2, 1, dc->h - 4, True, normcol->FG); + + if(lines > 0) { + /* draw vertical list */ +@@ -281,9 +298,12 @@ keypress(XKeyEvent *ev) { + return; + case XK_Return: + case XK_KP_Enter: ++ ret = EXIT_SUCCESS; ++ running = False; + break; + case XK_bracketleft: +- exit(EXIT_FAILURE); ++ ret = EXIT_FAILURE; ++ running = False; + default: + return; + } +@@ -330,7 +350,8 @@ keypress(XKeyEvent *ev) { + sel = matchend; + break; + case XK_Escape: +- exit(EXIT_FAILURE); ++ ret = EXIT_FAILURE; ++ running = False; + case XK_Home: + if(sel == matches) { + cursor = 0; +@@ -368,8 +389,10 @@ keypress(XKeyEvent *ev) { + case XK_Return: + case XK_KP_Enter: + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); +- if(!(ev->state & ControlMask)) +- exit(EXIT_SUCCESS); ++ if(!(ev->state & ControlMask)) { ++ ret = EXIT_SUCCESS; ++ running = False; ++ } + sel->out = True; + break; + case XK_Right: +@@ -504,7 +527,7 @@ void + run(void) { + XEvent ev; + +- while(!XNextEvent(dc->dpy, &ev)) { ++ while(running && !XNextEvent(dc->dpy, &ev)) { + if(XFilterEvent(&ev, win)) + continue; + switch(ev.type) { +@@ -538,13 +561,6 @@ setup(void) { + XineramaScreenInfo *info; + #endif + +- normcol[ColBG] = getcolor(dc, normbgcolor); +- normcol[ColFG] = getcolor(dc, normfgcolor); +- selcol[ColBG] = getcolor(dc, selbgcolor); +- selcol[ColFG] = getcolor(dc, selfgcolor); +- outcol[ColBG] = getcolor(dc, outbgcolor); +- outcol[ColFG] = getcolor(dc, outfgcolor); +- + clip = XInternAtom(dc->dpy, "CLIPBOARD", False); + utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); + +@@ -600,7 +616,7 @@ setup(void) { + + /* create menu window */ + swa.override_redirect = True; +- swa.background_pixel = normcol[ColBG]; ++ swa.background_pixel = normcol->BG; + swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; + win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, + DefaultDepth(dc->dpy, screen), CopyFromParent, +diff --git a/draw.c b/draw.c +index 76f0c54..09e66ea 100644 +--- a/draw.c ++++ b/draw.c +@@ -9,9 +9,6 @@ + + #define MAX(a, b) ((a) > (b) ? (a) : (b)) + #define MIN(a, b) ((a) < (b) ? (a) : (b)) +-#define DEFAULTFN "fixed" +- +-static Bool loadfont(DC *dc, const char *fontstr); + + void + drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsigned long color) { +@@ -23,7 +20,7 @@ drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsign + } + + void +-drawtext(DC *dc, const char *text, unsigned long col[ColLast]) { ++drawtext(DC *dc, const char *text, ColorSet *col) { + char buf[BUFSIZ]; + size_t mn, n = strlen(text); + +@@ -35,19 +32,24 @@ drawtext(DC *dc, const char *text, unsigned long col[ColLast]) { + if(mn < n) + for(n = MAX(mn-3, 0); n < mn; buf[n++] = '.'); + +- drawrect(dc, 0, 0, dc->w, dc->h, True, BG(dc, col)); ++ drawrect(dc, 0, 0, dc->w, dc->h, True, col->BG); + drawtextn(dc, buf, mn, col); + } + + void +-drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]) { ++drawtextn(DC *dc, const char *text, size_t n, ColorSet *col) { + int x = dc->x + dc->font.height/2; + int y = dc->y + dc->font.ascent+1; + +- XSetForeground(dc->dpy, dc->gc, FG(dc, col)); +- if(dc->font.set) ++ XSetForeground(dc->dpy, dc->gc, col->FG); ++ if(dc->font.xft_font) { ++ if(!dc->xftdraw) ++ eprintf("error, xft drawable does not exist"); ++ XftDrawStringUtf8(dc->xftdraw, &col->FG_xft, ++ dc->font.xft_font, x, y, (unsigned char*)text, n); ++ } else if(dc->font.set) { + XmbDrawString(dc->dpy, dc->canvas, dc->font.set, dc->gc, x, y, text, n); +- else { ++ } else { + XSetFont(dc->dpy, dc->gc, dc->font.xfont->fid); + XDrawString(dc->dpy, dc->canvas, dc->gc, x, y, text, n); + } +@@ -69,16 +71,33 @@ eprintf(const char *fmt, ...) { + } + + void ++freecol(DC *dc, ColorSet *col) { ++ if(col) { ++ if(&col->FG_xft) ++ XftColorFree(dc->dpy, DefaultVisual(dc->dpy, DefaultScreen(dc->dpy)), ++ DefaultColormap(dc->dpy, DefaultScreen(dc->dpy)), &col->FG_xft); ++ free(col); ++ } ++} ++ ++void + freedc(DC *dc) { ++ if(dc->font.xft_font) { ++ XftFontClose(dc->dpy, dc->font.xft_font); ++ XftDrawDestroy(dc->xftdraw); ++ } + if(dc->font.set) + XFreeFontSet(dc->dpy, dc->font.set); + if(dc->font.xfont) + XFreeFont(dc->dpy, dc->font.xfont); + if(dc->canvas) + XFreePixmap(dc->dpy, dc->canvas); +- XFreeGC(dc->dpy, dc->gc); +- XCloseDisplay(dc->dpy); +- free(dc); ++ if(dc->gc) ++ XFreeGC(dc->dpy, dc->gc); ++ if(dc->dpy) ++ XCloseDisplay(dc->dpy); ++ if(dc) ++ free(dc); + } + + unsigned long +@@ -91,6 +110,20 @@ getcolor(DC *dc, const char *colstr) { + return color.pixel; + } + ++ColorSet * ++initcolor(DC *dc, const char * foreground, const char * background) { ++ ColorSet * col = (ColorSet *)malloc(sizeof(ColorSet)); ++ if(!col) ++ eprintf("error, cannot allocate memory for color set"); ++ col->BG = getcolor(dc, background); ++ col->FG = getcolor(dc, foreground); ++ if(dc->font.xft_font) ++ if(!XftColorAllocName(dc->dpy, DefaultVisual(dc->dpy, DefaultScreen(dc->dpy)), ++ DefaultColormap(dc->dpy, DefaultScreen(dc->dpy)), foreground, &col->FG_xft)) ++ eprintf("error, cannot allocate xft font color '%s'\n", foreground); ++ return col; ++} ++ + DC * + initdc(void) { + DC *dc; +@@ -109,39 +142,33 @@ initdc(void) { + + void + initfont(DC *dc, const char *fontstr) { +- if(!loadfont(dc, fontstr ? fontstr : DEFAULTFN)) { +- if(fontstr != NULL) +- fprintf(stderr, "cannot load font '%s'\n", fontstr); +- if(fontstr == NULL || !loadfont(dc, DEFAULTFN)) +- eprintf("cannot load font '%s'\n", DEFAULTFN); +- } +- dc->font.height = dc->font.ascent + dc->font.descent; +-} +- +-Bool +-loadfont(DC *dc, const char *fontstr) { + char *def, **missing, **names; + int i, n; + XFontStruct **xfonts; + +- if(!*fontstr) +- return False; +- if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { ++ missing = NULL; ++ if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { ++ dc->font.ascent = dc->font.xfont->ascent; ++ dc->font.descent = dc->font.xfont->descent; ++ dc->font.width = dc->font.xfont->max_bounds.width; ++ } else if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { + n = XFontsOfFontSet(dc->font.set, &xfonts, &names); + for(i = 0; i < n; i++) { +- dc->font.ascent = MAX(dc->font.ascent, xfonts[i]->ascent); ++ dc->font.ascent= MAX(dc->font.ascent,xfonts[i]->ascent); + dc->font.descent = MAX(dc->font.descent, xfonts[i]->descent); +- dc->font.width = MAX(dc->font.width, xfonts[i]->max_bounds.width); ++ dc->font.width = MAX(dc->font.width, xfonts[i]->max_bounds.width); + } +- } +- else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { +- dc->font.ascent = dc->font.xfont->ascent; +- dc->font.descent = dc->font.xfont->descent; +- dc->font.width = dc->font.xfont->max_bounds.width; ++ } else if((dc->font.xft_font = XftFontOpenName(dc->dpy, DefaultScreen(dc->dpy), fontstr))) { ++ dc->font.ascent = dc->font.xft_font->ascent; ++ dc->font.descent = dc->font.xft_font->descent; ++ dc->font.width = dc->font.xft_font->max_advance_width; ++ } else { ++ eprintf("cannot load font '%s'\n", fontstr); + } + if(missing) + XFreeStringList(missing); +- return dc->font.set || dc->font.xfont; ++ dc->font.height = dc->font.ascent + dc->font.descent; ++ return; + } + + void +@@ -151,20 +178,29 @@ mapdc(DC *dc, Window win, unsigned int w, unsigned int h) { + + void + resizedc(DC *dc, unsigned int w, unsigned int h) { ++ int screen = DefaultScreen(dc->dpy); + if(dc->canvas) + XFreePixmap(dc->dpy, dc->canvas); + + dc->w = w; + dc->h = h; + dc->canvas = XCreatePixmap(dc->dpy, DefaultRootWindow(dc->dpy), w, h, +- DefaultDepth(dc->dpy, DefaultScreen(dc->dpy))); ++ DefaultDepth(dc->dpy, screen)); ++ if(dc->font.xft_font && !(dc->xftdraw)) { ++ dc->xftdraw = XftDrawCreate(dc->dpy, dc->canvas, DefaultVisual(dc->dpy,screen), DefaultColormap(dc->dpy,screen)); ++ if(!(dc->xftdraw)) ++ eprintf("error, cannot create xft drawable\n"); ++ } + } + + int + textnw(DC *dc, const char *text, size_t len) { +- if(dc->font.set) { ++ if(dc->font.xft_font) { ++ XGlyphInfo gi; ++ XftTextExtentsUtf8(dc->dpy, dc->font.xft_font, (const FcChar8*)text, len, &gi); ++ return gi.width; ++ } else if(dc->font.set) { + XRectangle r; +- + XmbTextExtents(dc->font.set, text, len, NULL, &r); + return r.width; + } +diff --git a/draw.h b/draw.h +index 43a57bf..1b4f21a 100644 +--- a/draw.h ++++ b/draw.h +@@ -1,9 +1,6 @@ + /* See LICENSE file for copyright and license details. */ + +-#define FG(dc, col) ((col)[(dc)->invert ? ColBG : ColFG]) +-#define BG(dc, col) ((col)[(dc)->invert ? ColFG : ColBG]) +- +-enum { ColBG, ColFG, ColBorder, ColLast }; ++#include <X11/Xft/Xft.h> + + typedef struct { + int x, y, w, h; +@@ -11,6 +8,7 @@ typedef struct { + Display *dpy; + GC gc; + Pixmap canvas; ++ XftDraw *xftdraw; + struct { + int ascent; + int descent; +@@ -18,15 +16,24 @@ typedef struct { + int width; + XFontSet set; + XFontStruct *xfont; ++ XftFont *xft_font; + } font; + } DC; /* draw context */ + ++typedef struct { ++ unsigned long FG; ++ XftColor FG_xft; ++ unsigned long BG; ++} ColorSet; ++ + void drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsigned long color); +-void drawtext(DC *dc, const char *text, unsigned long col[ColLast]); +-void drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]); ++void drawtext(DC *dc, const char *text, ColorSet *col); ++void drawtextn(DC *dc, const char *text, size_t n, ColorSet *col); ++void freecol(DC *dc, ColorSet *col); + void eprintf(const char *fmt, ...); + void freedc(DC *dc); + unsigned long getcolor(DC *dc, const char *colstr); ++ColorSet *initcolor(DC *dc, const char *foreground, const char *background); + DC *initdc(void); + void initfont(DC *dc, const char *fontstr); + void mapdc(DC *dc, Window win, unsigned int w, unsigned int h); +-- +1.9.1 + diff --git a/tools.suckless.org/dmenu/patches/xft.md b/tools.suckless.org/dmenu/patches/xft.md @@ -17,6 +17,7 @@ For example, 28pt Sans: Download -------- +* [dmenu git](dmenu-git-xft.diff) applies cleanly against 5ed5e90bfb7760f24661281cf7156087afbe49d3 * [dmenu 4.5](dmenu-4.5-xft.diff) * [dmenu 4.5 for debian](dmenu-4.5-xft-debian.diff) * [dmenu 4.4.1](dmenu-4.4.1-xft.diff) diff --git a/tools.suckless.org/dmenu/scripts/index.md b/tools.suckless.org/dmenu/scripts/index.md @@ -6,10 +6,15 @@ dmenu's user, feel free to add your own scripts, or comment existents. Download -------- +* [passmenu](http://git.zx2c4.com/password-store/tree/contrib/dmenu) + : get password from pass. * [run-recent](run-recent) : List recent commands first. End a command with ";" to run it in e terminal. [source](https://bbs.archlinux.org/viewtopic.php?id=56646&p=12) * [todo](todo): one task per line. Write a new task, or valid an old task to remove it. - - +* [dmenu_path_recent](https://github.com/ema/dotfiles/blob/master/bin/dmenu_path) + : dmenu_path implementation listing recent commands first. Similar to + [run-recent](run-recent), but it uses atime to find recently executed commands + rather than a cache. As such, it also takes into account programs executed from + the terminal. diff --git a/tools.suckless.org/ii/usage.md b/tools.suckless.org/ii/usage.md @@ -47,3 +47,8 @@ xii --- [xii](http://github.com/younix/xii) is a simple X11 frontend for ii. It is written in plain C based on Xaw and Xt library. + +hysteria +-------- +[hysteria](http://git.2f30.org/hysteria/) is another set of scripts +(mostly shell) which provide support for highlighting, autojoining, etc. diff --git a/tools.suckless.org/sbase.md b/tools.suckless.org/sbase.md @@ -0,0 +1,83 @@ +sbase +===== +sbase is a collection of unix tools that are inherently portable +across UNIX and UNIX-like systems. + +The following programs are currently implemented: + +* basename +* cal +* cat +* chgrp +* chmod +* chown +* chroot +* cksum +* cmp +* cols +* comm +* cp +* cut +* date +* dirname +* du +* echo +* env +* expand +* false +* fold +* grep +* head +* hostname +* kill +* ln +* ls +* md5sum +* mkdir +* mkfifo +* mktemp +* mv +* nice +* nl +* nohup +* paste +* printenv +* pwd +* readlink +* renice +* rm +* rmdir +* sleep +* setsid +* sort +* split +* sponge +* strings +* sync +* tail +* tar +* tee +* test +* touch +* tr +* true +* tty +* uudecode +* uuencode +* uname +* unexpand +* uniq +* unlink +* seq +* sha1sum +* sha256sum +* sha512sum +* wc +* xargs +* yes + +The overall SLOC is about 6kSLOC, so this userland is about the same size as GNU ls. + +Download +-------- +* <code>git clone [http://git.suckless.org/sbase](http://git.suckless.org/sbase)</code> diff --git a/tools.suckless.org/sinit.md b/tools.suckless.org/sinit.md @@ -0,0 +1,23 @@ +sinit - suckless init +===================== + +sinit is a simple init, initially based on Rich Felker's minimal [init](https://gist.github.com/rofl0r/6168719). + +Download +-------- +* [sinit 0.9](http://dl.suckless.org/sinit/sinit-0.9.tar.gz) (2.5kB) (20140418) + +Development +----------- +You can [browse](http://git.suckless.org/sinit) its source code repository or get +a copy using the following command: + +`git clone http://git.suckless.org/sinit` + +sinit is currently considered complete and finished, no further development is +expected to happen. + +Contact +------- +E-mail [sin@2f30.org](mailto:sin@2f30.org) or post your issue to the +[dev@suckless.org](mailto:dev@suckless.org) mailing list. diff --git a/tools.suckless.org/ubase.md b/tools.suckless.org/ubase.md @@ -0,0 +1,61 @@ +ubase +===== +ubase is a collection of tools similar in spirit to util-linux but +much simpler. + +The following programs are currently implemented: + +* chvt +* clear +* ctrlaltdel +* dd +* df +* dmesg +* eject +* fallocate +* free +* getty +* halt +* hwclock +* id +* insmod +* killall5 +* login +* lsmod +* lsusb +* mknod +* mkswap +* mount +* mountpoint +* pagesize +* passwd +* pidof +* pivot_root +* ps +* respawn +* rmmod +* stat +* su +* swapoff +* swapon +* switch_root +* sysctl +* truncate +* umount +* unshare +* uptime +* watch +* who + +Download +-------- +* [ubase 0.1](http://dl.suckless.org/ubase/ubase-0.1.tar.gz) (31kB) (20140501) + +Development +----------- +* <code>git clone [http://git.suckless.org/ubase](http://git.suckless.org/ubase)</code> + +Contact +------- +E-mail [sin@2f30.org](mailto:sin@2f30.org) or post your issue to the +[dev@suckless.org](mailto:dev@suckless.org) mailing list.