commit 38fdd48a0d254359e594a99ecc6990f801b065c4 parent 0ee04abe764f0293cae1390edd4dabec6898af55 Author: Philippe Gras <philippe.gras@free.fr> Date: Sun, 6 Mar 2016 00:11:41 +0100 Merge remote-tracking branch 'origin/master' Diffstat:
287 files changed, 14146 insertions(+), 6224 deletions(-)
diff --git a/dwm.suckless.org/dwmgetstatus.md b/dwm.suckless.org/dwmgetstatus.md @@ -9,8 +9,8 @@ Below is the script to do this: #!/bin/sh - xprop -root -f WM_NAME "8u" \ - | sed -n -r 's/WM_NAME\(STRING\) = \"(.*)\"/\1/p' + xprop -root -notype -f WM_NAME "8u" \ + | sed -n -r 's/WM_NAME = \"(.*)\"/\1/p' Link: [dwmgetstatus.sh](http://dwm.suckless.org/dwmgetstatus.sh) diff --git a/dwm.suckless.org/dwmgetstatus.sh b/dwm.suckless.org/dwmgetstatus.sh @@ -1,4 +1,4 @@ #!/bin/sh -xprop -root -f WM_NAME "8u" | sed -n -r 's/WM_NAME\(STRING\) = \"(.*)\"/\1/p' +xprop -root -notype -f WM_NAME "8u" | sed -n -r 's/WM_NAME = \"(.*)\"/\1/p' diff --git a/dwm.suckless.org/dwmstatus/dwmclock-netstat.c b/dwm.suckless.org/dwmstatus/dwmclock-netstat.c @@ -0,0 +1,140 @@ +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <time.h> +#include <locale.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdint.h> +#include <inttypes.h> +#include <math.h> + +#define IFNAMSIZ 16 + + +static const char* determine_def_if(void) { + FILE *f; + const char* ret = 0; + static char buf[IFNAMSIZ]; + char filebuf[256]; + f = fopen("/proc/net/route", "r"); + if (f) { + while (fgets(filebuf, sizeof filebuf, f)) { + char *tab = strchr(filebuf, '\t'); + if (tab && !strncmp(tab + 1, "00000000", 8)) { + memcpy(buf, filebuf, tab - filebuf); + buf[tab - filebuf] = 0; + ret = buf; + break; + } + } + fclose(f); + } + return ret; +} + +static uint64_t readfile(const char* filename) { + FILE* f; + uint64_t ret = 0, tmp; + f = fopen(filename, "r"); + if (f) { + if (fscanf(f, "%"SCNu64, &tmp) == 1) + ret = tmp; + fclose(f); + } + return ret; +} + +static uint64_t get_rx_bytes(const char* interface) +{ + char fnbuf[sizeof "/sys/class/net//statistics/rx_bytes" + IFNAMSIZ]; + strcpy(fnbuf, "/sys/class/net/"); + strcat(fnbuf, interface); + strcat(fnbuf, "/statistics/rx_bytes"); + return readfile(fnbuf); +} + +static uint64_t get_tx_bytes(const char* interface) +{ + char fnbuf[sizeof "/sys/class/net//statistics/rx_bytes" + IFNAMSIZ]; + strcpy(fnbuf, "/sys/class/net/"); + strcat(fnbuf, interface); + strcat(fnbuf, "/statistics/tx_bytes"); + return readfile(fnbuf); +} + +static int get_suff(uint64_t x) +{ + int r = -1 + !x; + while (x) { + r++; + x >>= 10; + } + return r; +} + +int main(void) { + Display *dpy; + Window root; + int loadfd; + + setlocale(LC_ALL, ""); + dpy = XOpenDisplay(0); + if (dpy) { + struct timespec tm, s; + ssize_t rv; + char oldif[IFNAMSIZ] = {0}; + uint64_t rxb, txb; + static const char suffixes[] = " KMGT"; // let's stay real here + root = XDefaultRootWindow(dpy); + clock_gettime(CLOCK_REALTIME, &tm); + s.tv_sec = 0; + s.tv_nsec = 1000000000 - tm.tv_nsec; + do rv = nanosleep(&s, &s); + while (rv == -1 && s.tv_nsec); + for (;;) { + char buf[100]; // estimate + const char *thisif = determine_def_if(); + uint64_t currxb, curtxb; + int idx; + int i; + if (thisif) + { + if (strcmp(thisif, oldif)) + { + strcpy(oldif, thisif); + rxb = txb = 0; + } + i = 0; + buf[i++] = oldif[0]; + buf[i++] = ' '; + buf[i++] = 'v'; + currxb = get_rx_bytes(oldif); + curtxb = get_tx_bytes(oldif); + idx = get_suff(currxb - rxb); + i += snprintf(buf + i, sizeof buf - i, "%.1f%c", (double)(currxb - rxb) / pow(1024, idx), suffixes[idx]); + rxb = currxb; + buf[i++] = ' '; + buf[i++] = '^'; + idx = get_suff(curtxb - txb); + i += snprintf(buf + i, sizeof buf - i, "%.1f%c", (double)(curtxb - txb) / pow(1024, idx), suffixes[idx]); + txb = curtxb; + } + else + buf[i++] = 'n'; + buf[i++] = ' '; + buf[i++] = '|'; + buf[i++] = ' '; + time_t t; + size_t l; + t = time(0); + l = strftime(buf + i, sizeof buf - i, "%c", localtime(&t)); + XStoreName(dpy, root, buf); + XSync(dpy, False); + sleep(1); + } + } +} diff --git a/dwm.suckless.org/dwmstatus/index.md b/dwm.suckless.org/dwmstatus/index.md @@ -22,10 +22,11 @@ Please add your own version of dwmstatus here. * [dwm-bar.c](https://github.com/wifiextender/dwm-bar) - Display overall usage about: cpu and cpu temperature, ram, disk, installed packages, kernel, motherboard voltage, system fans and their speed in RPM, motherboard (name, vendor, temperature), volume and time. I've wrote the code myself, so it is unique. * [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 -* [suspend-statusbar.c](suspend-statusbar.c) - loadavg, wifi, battery and date. If battery goes below threshold - run suspend command +* [suspend-statusbar.c](https://github.com/akozadaev/dwm-statusbar) - 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 * [go-dwmstatus](https://github.com/oniichaNj/go-dwmstatus) - A Go bar that prints current MPD song, load averages, time/date and battery percentage. * [barM](barM.c) - can display all, time/date, ram usage, output of commands (the New BarMonitor). +* [slstatus](https://github.com/drkh5h/slstatus) - *s*uck*l*ess *s*tatus - written in pure c without any system() - includes wifi percentage, battery, cpu usage and temperature, ram usage, alsa volume and time / date Helper functions ---------------- diff --git a/dwm.suckless.org/dwmstatus/profil-dwmstatus-1.0.c b/dwm.suckless.org/dwmstatus/profil-dwmstatus-1.0.c @@ -18,7 +18,7 @@ void setstatus(char *str) { float getfreq(char *file) { FILE *fd; - char *freq; + char *freq; float ret; freq = malloc(10); @@ -55,11 +55,11 @@ char *getdatetime() { fprintf(stderr, "strftime is 0.\n"); exit(1); } - + return buf; } -int getbattery() { +float getbattery() { FILE *fd; int energy_now, energy_full, voltage_now; @@ -107,14 +107,14 @@ int main(void) { if((status = malloc(200)) == NULL) exit(1); - + for (;;sleep(1)) { cpu0 = getfreq("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"); cpu1 = getfreq("/sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq"); datetime = getdatetime(); bat0 = getbattery(); - snprintf(status, 200, "%0.2f, %0.2f | %d%% | %s", cpu0, cpu1, bat0, datetime); + snprintf(status, 200, "%0.2f, %0.2f | %.2lf%% | %s", cpu0, cpu1, bat0, datetime); free(datetime); setstatus(status); diff --git a/dwm.suckless.org/dwmstatus/suspend-statusbar.c b/dwm.suckless.org/dwmstatus/suspend-statusbar.c @@ -1,219 +0,0 @@ -/* statusbar.c */ -/* Copyright (C) 2012 Alex Kozadaev [akozadaev at yahoo com] */ -/* git clone git@github.com:akozadaev/dwm-statusbar.git */ - -#include "build_host.h" - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <time.h> -#include <signal.h> -#include <X11/Xlib.h> - -/* =================================================================== -autoconfiguration - snippet from Makefile - -BATPATH=`find /sys -name BAT0 -print0 -quit` -LNKPATH=`find /sys/class/net/wlan0/ -name operstate -print0 -quit` -LAPATH=`find /proc -name loadavg -print0 -quit` - -# git@github.com:akozadaev/boxsuspend.git -BOXSUSPEND=`which boxsuspend` - - -build_host.h: - @echo "#define BUILD_HOST \"`hostname`\"" > build_host.h - @echo "#define BUILD_OS \"`uname`\"" >> build_host.h - @echo "#define BUILD_PLATFORM \"`uname -m`\"" >> build_host.h - @echo "#define BUILD_KERNEL \"`uname -r`\"" >> build_host.h - @echo "#define LA_PATH \"${LAPATH}\"" >> build_host.h - @echo "#define BAT_NOW \"${BATPATH}/charge_now\"" >> build_host.h - @echo "#define BAT_FULL \"${BATPATH}/charge_full\"" >> build_host.h - @echo "#define BAT_STAT \"${BATPATH}/status\"" >> build_host.h - @echo "#define LNK_PATH \"${LNKPATH}\"" >> build_host.h - @echo "#define BOX_SUSPEND \"${BOXSUSPEND}\"" >> build_host.h -=================================================================== */ - -/* version 0.64 */ - -#define THRESHOLD 8 -#define TIMEOUT 40 -#define SUSPEND { BOX_SUSPEND, NULL } /* BOX_SUSPEND gets configured in Makefile */ - -#define LABUF 14 -#define DTBUF 20 -#define LNKBUF 8 -#define STR 64 - -/* Available statuses - * - * Charging - * Discharging - * Unknown - * Full - */ -typedef enum { - C, D, U, F -} status_t; - - -static void spawn(const char **params) __attribute__ ((unused)); -static void set_status(char *str); -static void open_display(void) __attribute__ ((unused)); -static void close_display() __attribute__ ((unused)); -static void get_datetime(char *buf); -static status_t get_status(); -static int read_int(const char *path); -static void read_str(const char *path, char *buf, size_t sz); - -static Display *dpy; - -int -main(void) -{ - int timer = 0; - float bat; /* battery status */ - char lnk[STR] = { 0 }; /* wifi link */ - char la[STR] = { 0 }; /* load average */ - char dt[STR] = { 0 }; /* date/time */ - char stat[STR] = { 0 }; /* full string */ - status_t st; /* battery status */ - char status[] = { '+', '-', '?', '=' }; /* should be the same order as the enum above (C, D, U, F) */ - -#ifndef DEBUG - open_display(); -#endif - - while (!sleep(1)) { - read_str(LA_PATH, la, LABUF); /* load average */ - read_str(LNK_PATH, lnk, LNKBUF); /* link status */ - get_datetime(dt); /* date/time */ - bat = ((float)read_int(BAT_NOW) / - read_int(BAT_FULL)) * 100.0f; /* battery */ - st = get_status(); /* battery status (charging/discharging/full/etc) */ - - if (st == D && bat < THRESHOLD) { - snprintf(stat, STR, "LOW BATTERY: suspending after %d ", TIMEOUT - timer); - set_status(stat); - if (timer >= TIMEOUT) { -#ifndef DEBUG - spawn((const char*[])SUSPEND); -#else - puts("sleeping"); -#endif - timer = 0; - } else - timer++; - } else { - snprintf(stat, STR, "%s | %s | %c%0.1f%% | %s", la, lnk, status[st], - (bat > 100) ? 100 : bat, dt); - set_status(stat); - timer = 0; /* reseting the standby timer */ - } - } - -#ifndef DEBUG - close_display(); -#endif - return 0; -} - -static void -spawn(const char **params) { - if (fork() == 0) { - setsid(); - execv(params[0], (char**)params); - exit(0); - } -} - -static void -set_status(char *str) -{ -#ifndef DEBUG - XStoreName(dpy, DefaultRootWindow(dpy), str); - XSync(dpy, False); -#else - puts(str); -#endif -} - -static void -open_display(void) -{ - if (!(dpy = XOpenDisplay(NULL))) - exit(1); - signal(SIGINT, close_display); - signal(SIGTERM, close_display); -} - -static void -close_display() -{ - XCloseDisplay(dpy); - exit(0); -} - -static void -get_datetime(char *buf) -{ - time_t rawtime; - time(&rawtime); - snprintf(buf, DTBUF, "%s", ctime(&rawtime)); -} - -static status_t -get_status() -{ - FILE *bs; - char st; - - if ((bs = fopen(BAT_STAT, "r")) == NULL) - return U; - - st = fgetc(bs); - fclose(bs); - - switch(st) { - case 'C': return C; /* Charging */ - case 'D': return D; /* Discharging */ - case 'F': return F; /* Full */ - default : return U; /* Unknown */ - } -} - -static int -read_int(const char *path) -{ - int i = 0; - FILE *fh; - - if (!(fh = fopen(path, "r"))) - return -1; - - fscanf(fh, "%d", &i); - fclose(fh); - return i; -} - -static void -read_str(const char *path, char *buf, size_t sz) -{ - FILE *fh; - char ch = 0; - int idx = 0; - - if (!(fh = fopen(path, "r"))) return; - - while ((ch = fgetc(fh)) != EOF && ch != '\0' && ch != '\n' && idx < sz) { - buf[idx++] = ch; - } - - buf[idx] = '\0'; - fclose(fh); -} - -/* EOF */ - diff --git a/dwm.suckless.org/index.md b/dwm.suckless.org/index.md @@ -51,7 +51,7 @@ Links Download -------- * [MIT/X Consortium license](http://git.suckless.org/dwm/plain/LICENSE) -* [dwm 6.0](http://dl.suckless.org/dwm/dwm-6.0.tar.gz) (20kb) (20111219) +* [dwm 6.1](http://dl.suckless.org/dwm/dwm-6.1.tar.gz) (25kb) (20151109) * See also [dmenu](http://tools.suckless.org/dmenu) Support diff --git a/dwm.suckless.org/patches/ansistatuscolors.md b/dwm.suckless.org/patches/ansistatuscolors.md @@ -2,7 +2,7 @@ ## Description ## -Lets you put colored text in your status bar, but you don''t have define them in your config.h. Instead, just put the ansi escape sequence in the output of your status bar script to print in color, as you would in a terminal. +Lets you put colored text in your status bar, but you don't have define them in your config.h. Instead, just put the ansi escape sequence in the output of your status bar script to print in color, as you would in a terminal. ## Configuration ## @@ -14,7 +14,7 @@ apply it to dwm.c like so: ## Usage ## -Just like you''d use them for colorizing a shell script. +Just like you'd use them for colorizing a shell script. more info is here: [http://www.frexx.de/xterm-256-notes/](http://www.frexx.de/xterm-256-notes/) @@ -55,8 +55,8 @@ the code is one of the following: 16-231 - xterm 256-color rgb color 232-255 - grayscale -in vim, to create a literal 'escape' character, type ctrl-v, esc. -in perl/python/c, within a string literal, it''s "\x1b". +in vim, to create a literal 'escape' character, type ctrl-v, esc. +in perl/python/c, within a string literal, it's "\x1b". ### Example ### #!/usr/bin/env python diff --git a/dwm.suckless.org/patches/attachabove.md b/dwm.suckless.org/patches/attachabove.md @@ -11,10 +11,10 @@ Download Patches against different versions of dwm are available at [dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). - * [dwm-6.1-attachabove.diff](dwm-6.1-attachabove.diff) (1786b) (20140209) - * [dwm-10e232f9ace7-attachabove.diff](dwm-10e232f9ace7-attachabove.diff) (1709b) (20120406) + * [dwm-6.1-attachabove.diff](dwm-6.1-attachabove.diff) (1829b) (20151122) + * [dwm-git-20120406-attachabove.diff](dwm-git-20120406-attachabove.diff) (1709b) * [dwm-6.0-attachabove.diff](dwm-6.0-attachabove.diff) (1707b) (20120406) - * [dwm-5.6.1-attachabove.diff](dwm-5.6.1-attachabove.diff) (1.1K) (20090817) + * [dwm-5.6.1-attachabove.diff](historical/dwm-5.6.1-attachabove.diff) (1.1K) (20090817) Author ------ diff --git a/dwm.suckless.org/patches/attachaside.md b/dwm.suckless.org/patches/attachaside.md @@ -12,7 +12,7 @@ area instead of always becoming the new master. It's basically an | | | | | P | | | | - | N +-------| + | N +-------+ | | | | | | | | | @@ -55,8 +55,8 @@ improved to also attach to the stack on unfocused tags. ### Original * [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) +* [dwm-5.7.2-attachaside.diff](historical/dwm-5.7.2-attachaside.diff) (1.1K) (20091215) +* [dwm-5.6.1-attachaside.diff](historical/dwm-5.6.1-attachaside.diff) (1.1K) (20090915) Authors ------- diff --git a/dwm.suckless.org/patches/better-borders.md b/dwm.suckless.org/patches/better-borders.md @@ -12,10 +12,13 @@ as the monitor and marks them full-screen even if their X properties indicate otherwise. This eliminates nuisance borders that appear with some games and applications while in full-screen mode. +Thanks to Alesandar Metodiev for reporting a bug that lead to the patch being +rewritten. + Download -------- - * [dwm-6.1-better-borders.diff](dwm-6.1-better-borders.diff) (2014-07-13) + * [dwm-6.1-better-borders.diff](dwm-6.1-better-borders.diff) (2015-12-27) Author ------ diff --git a/dwm.suckless.org/patches/center.md b/dwm.suckless.org/patches/center.md @@ -10,7 +10,8 @@ monitor. Download -------- -* [dwm-cdec978-center.diff](dwm-cdec978-center.diff) (2k) (20140123) +* [dwm-6.1-center.diff](dwm-6.1-center.diff) (2k) (20151114) +* [dwm-cdec978-center.diff](historical/dwm-cdec978-center.diff) (2k) (20140123) Author ------ diff --git a/dwm.suckless.org/patches/centeredmaster.c b/dwm.suckless.org/patches/centeredmaster.c @@ -0,0 +1,91 @@ +void +centeredfloatingmaster(Monitor *m) { + unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; + Client *c; + + // Count number of clients in the selected monitor + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + + // initialize nmaster area + if(n > m->nmaster) { + // go mfact box in the center if more than nmaster clients + if(m->ww > m->wh) { + mw = m->nmaster ? m->ww * m->mfact : 0; + mh = m->nmaster ? m->wh * 0.9 : 0; + } else { + mh = m->nmaster ? m->wh * m->mfact : 0; + mw = m->nmaster ? m->ww * 0.9 : 0; + } + mx = mxo = (m->ww - mw) / 2; + my = myo = (m->wh - mh) / 2; + } else { + // Go fullscreen if all clients are in the master area + mh = m->wh; + mw = m->ww; + mx = mxo = 0; + my = myo = 0; + } + for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { + // nmaster clients are stacked horizontally, in the center of the screen + w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), mh - (2*c->bw), False); + mx += WIDTH(c); + } else { + // Stack clients are stacked horizontally + w = (m->ww - tx) / (n - i); + resize(c, m->wx + tx, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); + tx += WIDTH(c); + } +} + +void +centeredmaster(Monitor *m) { + unsigned int i, n, h, mw, mx, my, oty, ety, tw; + Client *c; + + // Count number of clients in the selected monitor + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + + // initialize areas + mw = m->ww; + mx = 0; + my = 0; + tw = mw; + + if(n > m->nmaster) { + // go mfact box in the center if more than nmaster clients + mw = m->nmaster ? m->ww * m->mfact : 0; + tw = m->ww - mw; + + if (n - m->nmaster > 1) { // only one client + mx = (m->ww - mw) / 2; + tw = (m->ww - mw) / 2; + } + } + + oty = 0; + ety = 0; + for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { + // nmaster clients are stacked verticaly, in the center of the screen + h = (m->wh - my) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); + my += HEIGHT(c); + } else { + // Stack clients are stacked verticaly + if ((i - m->nmaster) % 2 ) { + h = (m->wh - ety) / ( (1 + n - i) / 2); + resize(c, m->wx, m->wy + ety, tw - (2*c->bw), h - (2*c->bw), False); + ety += HEIGHT(c); + } else { + h = (m->wh - oty) / ((1 + n - i) / 2); + resize(c, m->wx + mx + mw, m->wy + oty, tw - (2*c->bw), h - (2*c->bw), False); + oty += HEIGHT(c); + } + } +} diff --git a/dwm.suckless.org/patches/centeredmaster.md b/dwm.suckless.org/patches/centeredmaster.md @@ -1,19 +1,47 @@ # centeredmaster -`centeredmaster` layout patch makes the nmaster area centered -on screen, using `mfact * monitor width & height`, over an -horizontally tiled `stack` area, pretty much like -a "scratchpad". +## `centeredmaster` -I find it useful on large screens (say 1920px wide), where -`monocle` or `htile` feels either too large or makes me type in -a corner of the screen. +makes the nmaster area centered +on screen, using `mfact * monitor width & height`, with the stacked windows +distributed on left and right. -With `centeredmaster`, for instance, I can set my editor in the -center, while keeping an eye on what's happening in the windows -behind (logs, tests, ...). +With one client in master: + +------------------------------+ + |+--------++--------++--------+| + || || || || + || || || || + || || || || + || S2 || M || S1 || + || || || || + || || || || + || || || || + || || || || + |+--------++--------++--------+| + +------------------------------+ +With two clients in master: + + +------------------------------+ + |+--------++--------++--------+| + || || || || + || || M1 || || + || || || || + || |+--------+| || + || |+--------+| || + || || || || + || || M2 || || + || || || || + |+--------++--------++--------+| + +------------------------------+ + +## `centeredfloatingmaster` + +makes the nmaster area centered +on screen, using `mfact * monitor width & height`, over an +horizontally tiled `stack` area, pretty much like +a "scratchpad". With one client in master: @@ -46,19 +74,21 @@ With two clients in master: +------------------------------+ -## Links - -* [dwm-6.1-centeredmaster.diff](dwm-6.1-centeredmaster.diff) - 4K, 2015/08/15 - - -[jerome](http://blog.jardinmagique.info) <jerome@gcu.info> - - +I find it useful on large screens (say 1920px wide), where +`monocle` or `htile` feels either too large or makes me type in +a corner of the screen. +With `centeredmaster`, for instance, I can set my editor in the +center, while keeping an eye on what's happening in the windows +behind (logs, tests, ...). +## Links +* [centeredmaster.c](centeredmaster.c) - 2015/11/22 +* [dwm-6.1-centeredmaster.diff](dwm-6.1-centeredmaster.diff) - 2015/11/21 +[jerome](http://blog.jardinmagique.info) <jerome@gcu.info> diff --git a/dwm.suckless.org/patches/combo.md b/dwm.suckless.org/patches/combo.md @@ -18,11 +18,13 @@ and view so you could replace all usages if you wanted. Download -------- - * [dwm-5.9-combo.diff](dwm-5.9-combo.diff) (2010-10-30) - * [dwm-6.0-combo.diff](dwm-6.0-combo.diff) (2012-10-09) + * [dwm-5.9-combo.diff](dwm-5.9-combo.diff) - 2010-10-30 + * [dwm-6.0-combo.diff](dwm-6.0-combo.diff) - 2012-10-09 + * [dwm-6.1-combo.diff](dwm-6.1-combo.diff) - 2016-01-22 Author ------ * Wolf Tivy - wolf at tivy dot com. * Dan McNair - cosfx at h0v3 dot net (mechanical update to 6.0) + * Matthew Boswell - mordervomubel+suckless at lockmail dot us (mechanical update to 6.1) diff --git a/dwm.suckless.org/patches/dualstatus.md b/dwm.suckless.org/patches/dualstatus.md @@ -11,7 +11,7 @@ xsetroot -name "top text;bottom text" Download -------- - * [dwm-6.1-dualstatus.diff](dwm-6.1-dualstatus.diff) (4688b) (20130908) + * [dwm-6.1-dualstatus.diff](dwm-6.1-dualstatus.diff) (4683b) (20151110) * [dwm-6.0-dualstatus.diff](dwm-6.0-dualstatus.diff) (4794b) (20130908) Screenshot diff --git a/dwm.suckless.org/patches/dwm-10e232f9ace7-push.diff b/dwm.suckless.org/patches/dwm-10e232f9ace7-push.diff @@ -1,65 +0,0 @@ -URL: http://dwm.suckless.org/patches/push -pushup and pushdown provide a way to move clients inside the clients list. - -diff -r 10e232f9ace7 push.c ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/push.c Fri Apr 06 08:16:39 2012 +0200 -@@ -0,0 +1,58 @@ -+static Client * -+prevtiled(Client *c) { -+ Client *p, *r; -+ -+ for(p = selmon->clients, r = NULL; p && p != c; p = p->next) -+ if(!p->isfloating && ISVISIBLE(p)) -+ r = p; -+ return r; -+} -+ -+static void -+pushup(const Arg *arg) { -+ Client *sel = selmon->sel; -+ Client *c; -+ -+ if(!sel || sel->isfloating) -+ return; -+ if((c = prevtiled(sel))) { -+ /* attach before c */ -+ detach(sel); -+ sel->next = c; -+ if(selmon->clients == c) -+ selmon->clients = sel; -+ else { -+ for(c = selmon->clients; c->next != sel->next; c = c->next); -+ c->next = sel; -+ } -+ } else { -+ /* move to the end */ -+ for(c = sel; c->next; c = c->next); -+ detach(sel); -+ sel->next = NULL; -+ c->next = sel; -+ } -+ focus(sel); -+ arrange(selmon); -+} -+ -+static void -+pushdown(const Arg *arg) { -+ Client *sel = selmon->sel; -+ Client *c; -+ -+ if(!sel || sel->isfloating) -+ return; -+ if((c = nexttiled(sel->next))) { -+ /* attach after c */ -+ detach(sel); -+ sel->next = c->next; -+ c->next = sel; -+ } else { -+ /* move to the front */ -+ detach(sel); -+ attach(sel); -+ } -+ focus(sel); -+ arrange(selmon); -+} diff --git a/dwm.suckless.org/patches/dwm-14343e69cc59-systray.diff b/dwm.suckless.org/patches/dwm-14343e69cc59-systray.diff @@ -1,687 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index eaae8f3..42f4165 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -15,6 +15,10 @@ static const char selbgcolor[] = "#005577"; - static const char selfgcolor[] = "#eeeeee"; - static const unsigned int borderpx = 1; /* border pixel of windows */ - static const unsigned int snap = 32; /* snap pixel */ -+static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ -+static const unsigned int systrayspacing = 2; /* systray spacing */ -+static const Bool systraypinningfailfirst = True; /* True: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ -+static const Bool showsystray = True; /* False means no systray */ - static const Bool showbar = True; /* False means no bar */ - static const Bool topbar = True; /* False means bottom bar */ - -diff --git a/dwm.c b/dwm.c -index 169adcb..859143e 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -57,12 +57,30 @@ - #define TAGMASK ((1 << LENGTH(tags)) - 1) - #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) - -+#define SYSTEM_TRAY_REQUEST_DOCK 0 -+#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 -+ -+/* XEMBED messages */ -+#define XEMBED_EMBEDDED_NOTIFY 0 -+#define XEMBED_WINDOW_ACTIVATE 1 -+#define XEMBED_FOCUS_IN 4 -+#define XEMBED_MODALITY_ON 10 -+ -+#define XEMBED_MAPPED (1 << 0) -+#define XEMBED_WINDOW_ACTIVATE 1 -+#define XEMBED_WINDOW_DEACTIVATE 2 -+ -+#define VERSION_MAJOR 0 -+#define VERSION_MINOR 0 -+#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR -+ - /* 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 { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, -+ NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, NetWMWindowType, -+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -+enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ - enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ - enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, - ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -@@ -141,6 +159,12 @@ typedef struct { - int monitor; - } Rule; - -+typedef struct Systray Systray; -+struct Systray { -+ Window win; -+ Client *icons; -+}; -+ - /* function declarations */ - static void applyrules(Client *c); - static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact); -@@ -170,8 +194,10 @@ static void focus(Client *c); - static void focusin(XEvent *e); - static void focusmon(const Arg *arg); - static void focusstack(const Arg *arg); -+static Atom getatomprop(Client *c, Atom prop); - static Bool getrootptr(int *x, int *y); - static long getstate(Window w); -+static unsigned int getsystraywidth(); - static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); - static void grabbuttons(Client *c, Bool focused); - static void grabkeys(void); -@@ -189,13 +215,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); -+static void removesystrayicon(Client *i); - static void resize(Client *c, int x, int y, int w, int h, Bool interact); -+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); --static Bool sendevent(Client *c, Atom proto); -+static Bool sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); - static void sendmon(Client *c, Monitor *m); - static void setclientstate(Client *c, long state); - static void setfocus(Client *c); -@@ -206,6 +235,7 @@ static void setup(void); - static void showhide(Client *c); - static void sigchld(int unused); - static void spawn(const Arg *arg); -+static Monitor *systraytomon(Monitor *m); - static void tag(const Arg *arg); - static void tagmon(const Arg *arg); - static void tile(Monitor *); -@@ -223,18 +253,24 @@ static void updateclientlist(void); - static void updatenumlockmask(void); - static void updatesizehints(Client *c); - static void updatestatus(void); -+static void updatesystray(void); -+static void updatesystrayicongeom(Client *i, int w, int h); -+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); - static void updatewindowtype(Client *c); - static void updatetitle(Client *c); - static void updatewmhints(Client *c); - static void view(const Arg *arg); - static Client *wintoclient(Window w); - static Monitor *wintomon(Window w); -+static Client *wintosystrayicon(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 Systray *systray = NULL; -+static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; - static const char broken[] = "broken"; - static char stext[256]; - static int screen; -@@ -256,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { - [MapRequest] = maprequest, - [MotionNotify] = motionnotify, - [PropertyNotify] = propertynotify, -+ [ResizeRequest] = resizerequest, - [UnmapNotify] = unmapnotify - }; --static Atom wmatom[WMLast], netatom[NetLast]; -+static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; - static Bool running = True; - static Cur *cursor[CurLast]; - static ClrScheme scheme[SchemeLast]; -@@ -471,6 +508,11 @@ cleanup(void) { - XUngrabKey(dpy, AnyKey, AnyModifier, root); - while(mons) - cleanupmon(mons); -+ if(showsystray) { -+ XUnmapWindow(dpy, systray->win); -+ XDestroyWindow(dpy, systray->win); -+ free(systray); -+ } - drw_cur_free(drw, cursor[CurNormal]); - drw_cur_free(drw, cursor[CurResize]); - drw_cur_free(drw, cursor[CurMove]); -@@ -515,9 +557,49 @@ clearurgent(Client *c) { - - void - clientmessage(XEvent *e) { -+ XWindowAttributes wa; -+ XSetWindowAttributes swa; - XClientMessageEvent *cme = &e->xclient; - Client *c = wintoclient(cme->window); - -+ if(showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { -+ /* add systray icons */ -+ if(cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { -+ if(!(c = (Client *)calloc(1, sizeof(Client)))) -+ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); -+ c->win = cme->data.l[2]; -+ c->mon = selmon; -+ c->next = systray->icons; -+ systray->icons = c; -+ XGetWindowAttributes(dpy, c->win, &wa); -+ c->x = c->oldx = c->y = c->oldy = 0; -+ c->w = c->oldw = wa.width; -+ c->h = c->oldh = wa.height; -+ c->oldbw = wa.border_width; -+ c->bw = 0; -+ c->isfloating = True; -+ /* reuse tags field as mapped status */ -+ c->tags = 1; -+ updatesizehints(c); -+ updatesystrayicongeom(c, wa.width, wa.height); -+ XAddToSaveSet(dpy, c->win); -+ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); -+ XReparentWindow(dpy, c->win, systray->win, 0, 0); -+ /* use parents background color */ -+ swa.background_pixel = scheme[SchemeNorm].bg->pix; -+ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ /* FIXME not sure if I have to send these events, too */ -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ XSync(dpy, False); -+ resizebarwin(selmon); -+ updatesystray(); -+ setclientstate(c, NormalState); -+ } -+ return; -+ } - if(!c) - return; - if(cme->message_type == netatom[NetWMState]) { -@@ -567,7 +649,7 @@ configurenotify(XEvent *e) { - drw_resize(drw, sw, bh); - updatebars(); - for(m = mons; m; m = m->next) -- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); -+ resizebarwin(m); - focus(NULL); - arrange(NULL); - } -@@ -651,6 +733,11 @@ destroynotify(XEvent *e) { - - if((c = wintoclient(ev->window))) - unmanage(c, True); -+ else if((c = wintosystrayicon(ev->window))) { -+ removesystrayicon(c); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - } - - void -@@ -695,6 +782,7 @@ drawbar(Monitor *m) { - unsigned int i, occ = 0, urg = 0; - Client *c; - -+ resizebarwin(m); - for(c = m->clients; c; c = c->next) { - occ |= c->tags; - if(c->isurgent) -@@ -717,6 +805,9 @@ drawbar(Monitor *m) { - 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; -@@ -746,6 +837,7 @@ drawbars(void) { - - for(m = mons; m; m = m->next) - drawbar(m); -+ updatesystray(); - } - - void -@@ -772,8 +864,11 @@ 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); -+ if(m == selmon) -+ updatesystray(); -+ } - } - - void -@@ -856,10 +951,17 @@ getatomprop(Client *c, Atom prop) { - unsigned long dl; - unsigned char *p = NULL; - Atom da, atom = None; -+ /* FIXME getatomprop should return the number of items and a pointer to -+ * the stored data instead of this workaround */ -+ Atom req = XA_ATOM; -+ if(prop == xatom[XembedInfo]) -+ req = xatom[XembedInfo]; - -- if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, -+ if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, - &da, &di, &dl, &dl, &p) == Success && p) { - atom = *(Atom *)p; -+ if(da == xatom[XembedInfo] && dl == 2) -+ atom = ((Atom *)p)[1]; - XFree(p); - } - return atom; -@@ -891,6 +993,15 @@ getstate(Window w) { - return result; - } - -+unsigned int -+getsystraywidth() { -+ unsigned int w = 0; -+ Client *i; -+ if(showsystray) -+ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; -+ return w ? w + systrayspacing : 1; -+} -+ - Bool - gettextprop(Window w, Atom atom, char *text, unsigned int size) { - char **list = NULL; -@@ -991,7 +1102,7 @@ void - killclient(const Arg *arg) { - if(!selmon->sel) - return; -- if(!sendevent(selmon->sel, wmatom[WMDelete])) { -+ if(!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { - XGrabServer(dpy); - XSetErrorHandler(xerrordummy); - XSetCloseDownMode(dpy, DestroyAll); -@@ -1077,6 +1188,12 @@ void - maprequest(XEvent *e) { - static XWindowAttributes wa; - XMapRequestEvent *ev = &e->xmaprequest; -+ Client *i; -+ if((i = wintosystrayicon(ev->window))) { -+ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - - if(!XGetWindowAttributes(dpy, ev->window, &wa)) - return; -@@ -1198,6 +1315,16 @@ propertynotify(XEvent *e) { - Window trans; - XPropertyEvent *ev = &e->xproperty; - -+ if((c = wintosystrayicon(ev->window))) { -+ if(ev->atom == XA_WM_NORMAL_HINTS) { -+ updatesizehints(c); -+ updatesystrayicongeom(c, c->w, c->h); -+ } -+ else -+ updatesystrayiconstate(c, ev); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - if((ev->window == root) && (ev->atom == XA_WM_NAME)) - updatestatus(); - else if(ev->state == PropertyDelete) -@@ -1247,12 +1374,33 @@ recttomon(int x, int y, int w, int h) { - } - - void -+removesystrayicon(Client *i) { -+ Client **ii; -+ -+ if(!showsystray || !i) -+ return; -+ for(ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); -+ if(ii) -+ *ii = i->next; -+ free(i); -+} -+ -+ -+void - resize(Client *c, int x, int y, int w, int h, Bool interact) { - if(applysizehints(c, &x, &y, &w, &h, interact)) - resizeclient(c, x, y, w, h); - } - - void -+resizebarwin(Monitor *m) { -+ unsigned int w = m->ww; -+ if(showsystray && m == systraytomon(m)) -+ w -= getsystraywidth(); -+ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); -+} -+ -+void - resizeclient(Client *c, int x, int y, int w, int h) { - XWindowChanges wc; - -@@ -1323,6 +1471,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; -@@ -1406,25 +1566,35 @@ setclientstate(Client *c, long state) { - } - - Bool --sendevent(Client *c, Atom proto) { -+sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) { - int n; -- Atom *protocols; -+ Atom *protocols, mt; - Bool exists = False; - XEvent ev; - -- if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { -- while(!exists && n--) -- exists = protocols[n] == proto; -- XFree(protocols); -+ if(proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { -+ mt = wmatom[WMProtocols]; -+ if(XGetWMProtocols(dpy, w, &protocols, &n)) { -+ while(!exists && n--) -+ exists = protocols[n] == proto; -+ XFree(protocols); -+ } -+ } -+ else { -+ exists = True; -+ mt = proto; - } - if(exists) { - ev.type = ClientMessage; -- ev.xclient.window = c->win; -- ev.xclient.message_type = wmatom[WMProtocols]; -+ ev.xclient.window = w; -+ ev.xclient.message_type = mt; - ev.xclient.format = 32; -- ev.xclient.data.l[0] = proto; -- ev.xclient.data.l[1] = CurrentTime; -- XSendEvent(dpy, c->win, False, NoEventMask, &ev); -+ ev.xclient.data.l[0] = d0; -+ ev.xclient.data.l[1] = d1; -+ ev.xclient.data.l[2] = d2; -+ ev.xclient.data.l[3] = d3; -+ ev.xclient.data.l[4] = d4; -+ XSendEvent(dpy, w, False, mask, &ev); - } - return exists; - } -@@ -1437,7 +1607,7 @@ setfocus(Client *c) { - XA_WINDOW, 32, PropModeReplace, - (unsigned char *) &(c->win), 1); - } -- sendevent(c, wmatom[WMTakeFocus]); -+ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); - } - - void -@@ -1520,12 +1690,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); -+ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); -+ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); -+ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); - netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); - netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); - netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); - netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); - netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); - netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); -+ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); -+ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); -+ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); - /* init cursors */ - cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); - cursor[CurResize] = drw_cur_create(drw, XC_sizing); -@@ -1537,6 +1713,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); -+ /* init system tray */ -+ updatesystray(); - /* init bars */ - updatebars(); - updatestatus(); -@@ -1592,6 +1770,22 @@ spawn(const Arg *arg) { - } - } - -+Monitor * -+systraytomon(Monitor *m) { -+ Monitor *t; -+ int i, n; -+ if(!systraypinning) { -+ if(!m) -+ return selmon; -+ return m == selmon ? m : NULL; -+ } -+ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; -+ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; -+ if(systraypinningfailfirst && n < systraypinning) -+ return mons; -+ return t; -+} -+ - void - tag(const Arg *arg) { - if(selmon->sel && arg->ui & TAGMASK) { -@@ -1638,7 +1832,18 @@ void - togglebar(const Arg *arg) { - selmon->showbar = !selmon->showbar; - updatebarpos(selmon); -- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); -+ resizebarwin(selmon); -+ if(showsystray) { -+ XWindowChanges wc; -+ if(!selmon->showbar) -+ wc.y = -bh; -+ else if(selmon->showbar) { -+ wc.y = 0; -+ if(!selmon->topbar) -+ wc.y = selmon->mh - bh; -+ } -+ XConfigureWindow(dpy, systray->win, CWY, &wc); -+ } - arrange(selmon); - } - -@@ -1728,11 +1933,18 @@ unmapnotify(XEvent *e) { - else - unmanage(c, False); - } -+ else if((c = wintosystrayicon(ev->window))) { -+ removesystrayicon(c); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - } - - void - updatebars(void) { -+ unsigned int w; - Monitor *m; -+ - XSetWindowAttributes wa = { - .override_redirect = True, - .background_pixmap = ParentRelative, -@@ -1741,10 +1953,15 @@ updatebars(void) { - for(m = mons; m; m = m->next) { - if (m->barwin) - continue; -- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), -+ w = m->ww; -+ if(showsystray && m == systraytomon(m)) -+ w -= getsystraywidth(); -+ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), - CopyFromParent, DefaultVisual(dpy, screen), - CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); - XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); -+ if(showsystray && m == systraytomon(m)) -+ XMapRaised(dpy, systray->win); - XMapRaised(dpy, m->barwin); - } - } -@@ -1938,6 +2155,117 @@ updatestatus(void) { - } - - void -+updatesystrayicongeom(Client *i, int w, int h) { -+ if(i) { -+ i->h = bh; -+ if(w == h) -+ i->w = bh; -+ else if(h == bh) -+ i->w = w; -+ else -+ i->w = (int) ((float)bh * ((float)w / (float)h)); -+ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); -+ /* force icons into the systray dimenons if they don't want to */ -+ if(i->h > bh) { -+ if(i->w == i->h) -+ i->w = bh; -+ else -+ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); -+ i->h = bh; -+ } -+ } -+} -+ -+void -+updatesystrayiconstate(Client *i, XPropertyEvent *ev) { -+ long flags; -+ int code = 0; -+ -+ if(!showsystray || !i || ev->atom != xatom[XembedInfo] || -+ !(flags = getatomprop(i, xatom[XembedInfo]))) -+ return; -+ -+ if(flags & XEMBED_MAPPED && !i->tags) { -+ i->tags = 1; -+ code = XEMBED_WINDOW_ACTIVATE; -+ XMapRaised(dpy, i->win); -+ setclientstate(i, NormalState); -+ } -+ else if(!(flags & XEMBED_MAPPED) && i->tags) { -+ i->tags = 0; -+ code = XEMBED_WINDOW_DEACTIVATE; -+ XUnmapWindow(dpy, i->win); -+ setclientstate(i, WithdrawnState); -+ } -+ else -+ return; -+ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, -+ systray->win, XEMBED_EMBEDDED_VERSION); -+} -+ -+void -+updatesystray(void) { -+ XSetWindowAttributes wa; -+ XWindowChanges wc; -+ Client *i; -+ Monitor *m = systraytomon(NULL); -+ unsigned int x = m->mx + m->mw; -+ unsigned int w = 1; -+ -+ if(!showsystray) -+ return; -+ if(!systray) { -+ /* init systray */ -+ if(!(systray = (Systray *)calloc(1, sizeof(Systray)))) -+ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); -+ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel].bg->pix); -+ wa.event_mask = ButtonPressMask | ExposureMask; -+ wa.override_redirect = True; -+ wa.background_pixel = scheme[SchemeNorm].bg->pix; -+ XSelectInput(dpy, systray->win, SubstructureNotifyMask); -+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, -+ PropModeReplace, (unsigned char *)&systrayorientation, 1); -+ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); -+ XMapRaised(dpy, systray->win); -+ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); -+ if(XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { -+ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); -+ XSync(dpy, False); -+ } -+ else { -+ fprintf(stderr, "dwm: unable to obtain system tray.\n"); -+ free(systray); -+ systray = NULL; -+ return; -+ } -+ } -+ for(w = 0, i = systray->icons; i; i = i->next) { -+ /* make sure the background color stays the same */ -+ wa.background_pixel = scheme[SchemeNorm].bg->pix; -+ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); -+ XMapRaised(dpy, i->win); -+ w += systrayspacing; -+ 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); -+ XMapWindow(dpy, systray->win); -+ XMapSubwindows(dpy, systray->win); -+ /* redraw background */ -+ XSetForeground(dpy, drw->gc, scheme[SchemeNorm].bg->pix); -+ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); -+ XSync(dpy, False); -+} -+ -+void - updatewindowtype(Client *c) { - Atom state = getatomprop(c, netatom[NetWMState]); - Atom wtype = getatomprop(c, netatom[NetWMWindowType]); -@@ -2006,6 +2334,16 @@ wintomon(Window w) { - return selmon; - } - -+Client * -+wintosystrayicon(Window w) { -+ Client *i = NULL; -+ -+ if(!showsystray || !w) -+ return i; -+ for(i = systray->icons; i && i->win != w; i = i->next) ; -+ return i; -+} -+ - /* There's no way to check accesses to destroyed windows, thus those cases are - * ignored (especially on UnmapNotify's). Other types of errors call Xlibs - * default error handler, which may call exit. */ diff --git a/dwm.suckless.org/patches/dwm-20151110-5ed9c48-keycode.patch b/dwm.suckless.org/patches/dwm-20151110-5ed9c48-keycode.patch @@ -0,0 +1,146 @@ +From 6a9c5bc422a68a40d5eb2b873fa01d59d6c5bd50 Mon Sep 17 00:00:00 2001 +From: Quentin Rameau <quinq@fifth.space> +Date: Tue, 10 Nov 2015 19:09:20 +0100 +Subject: [PATCH] Use keycodes instead of keysyms + +--- + config.def.h | 68 ++++++++++++++++++++++++++++++------------------------------ + dwm.c | 15 +++++--------- + 2 files changed, 39 insertions(+), 44 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 7054c06..f59d1eb 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -58,40 +58,40 @@ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, + static const char *termcmd[] = { "st", 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 } }, +- 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|ShiftMask, XK_q, quit, {0} }, ++ /* modifier key function argument */ ++ { MODKEY, 33, spawn, {.v = dmenucmd } }, // p ++ { MODKEY|ShiftMask, 36, spawn, {.v = termcmd } }, // Return ++ { MODKEY, 56, togglebar, {0} }, // b ++ { MODKEY, 44, focusstack, {.i = +1 } }, // j ++ { MODKEY, 45, focusstack, {.i = -1 } }, // k ++ { MODKEY, 31, incnmaster, {.i = +1 } }, // i ++ { MODKEY, 40, incnmaster, {.i = -1 } }, // d ++ { MODKEY, 43, setmfact, {.f = -0.05} }, // h ++ { MODKEY, 46, setmfact, {.f = +0.05} }, // l ++ { MODKEY, 36, zoom, {0} }, // Return ++ { MODKEY, 23, view, {0} }, // Tab ++ { MODKEY|ShiftMask, 54, killclient, {0} }, // c ++ { MODKEY, 28, setlayout, {.v = &layouts[0]} }, // t ++ { MODKEY, 41, setlayout, {.v = &layouts[1]} }, // f ++ { MODKEY, 58, setlayout, {.v = &layouts[2]} }, // m ++ { MODKEY, 65, setlayout, {0} }, // space ++ { MODKEY|ShiftMask, 65, togglefloating, {0} }, // space ++ { MODKEY, 19, view, {.ui = ~0 } }, // 0 ++ { MODKEY|ShiftMask, 19, tag, {.ui = ~0 } }, // 0 ++ { MODKEY, 59, focusmon, {.i = -1 } }, // comma ++ { MODKEY, 60, focusmon, {.i = +1 } }, // period ++ { MODKEY|ShiftMask, 59, tagmon, {.i = -1 } }, // comma ++ { MODKEY|ShiftMask, 60, tagmon, {.i = +1 } }, // period ++ TAGKEYS( 10, 0) // 1 ++ TAGKEYS( 11, 1) // 2 ++ TAGKEYS( 12, 2) // 3 ++ TAGKEYS( 13, 3) // 4 ++ TAGKEYS( 14, 4) // 5 ++ TAGKEYS( 15, 5) // 6 ++ TAGKEYS( 16, 6) // 7 ++ TAGKEYS( 17, 7) // 8 ++ TAGKEYS( 18, 8) // 9 ++ { MODKEY|ShiftMask, 24, quit, {0} }, // q + }; + + /* button definitions */ +diff --git a/dwm.c b/dwm.c +index 0362114..60dd817 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -31,7 +31,6 @@ + #include <sys/types.h> + #include <sys/wait.h> + #include <X11/cursorfont.h> +-#include <X11/keysym.h> + #include <X11/Xatom.h> + #include <X11/Xlib.h> + #include <X11/Xproto.h> +@@ -101,7 +100,7 @@ struct Client { + + typedef struct { + unsigned int mod; +- KeySym keysym; ++ KeyCode keycode; + void (*func)(const Arg *); + const Arg arg; + } Key; +@@ -967,14 +966,12 @@ grabkeys(void) + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; +- KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < LENGTH(keys); i++) +- if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) +- for (j = 0; j < LENGTH(modifiers); j++) +- XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, +- True, GrabModeAsync, GrabModeAsync); ++ for (j = 0; j < LENGTH(modifiers); j++) ++ XGrabKey(dpy, keys[i].keycode, keys[i].mod | modifiers[j], root, ++ True, GrabModeAsync, GrabModeAsync); + } + } + +@@ -1001,13 +998,11 @@ void + keypress(XEvent *e) + { + unsigned int i; +- KeySym keysym; + XKeyEvent *ev; + + ev = &e->xkey; +- keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for (i = 0; i < LENGTH(keys); i++) +- if (keysym == keys[i].keysym ++ if (ev->keycode == keys[i].keycode + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) + keys[i].func(&(keys[i].arg)); +-- +2.6.2 + diff --git a/dwm.suckless.org/patches/dwm-3465bed290ab-maximize_vert_horz.diff b/dwm.suckless.org/patches/dwm-3465bed290ab-maximize_vert_horz.diff @@ -0,0 +1,73 @@ +Author: Jan Christoph Ebersbach <jceb@e-jc.de> +URL: http://dwm.suckless.org/patches/historical/moveresize +These patches provide helper functions for moving and resizing floating windows +using keybindings. + +Index: dwm/dwm.c +=================================================================== +--- dwm/dwm.c.orig 2014-02-09 15:24:12.552116979 +0100 ++++ dwm/dwm.c 2014-02-09 15:24:12.548116979 +0100 +@@ -92,7 +92,7 @@ + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; +- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int ismax, wasfloating, isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; +@@ -1077,6 +1077,8 @@ + updatewmhints(c); + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); ++ c->wasfloating = 0; ++ c->ismax = 0; + if (!c->isfloating) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) +Index: dwm/maximize.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ dwm/maximize.c 2014-02-09 15:24:12.548116979 +0100 +@@ -0,0 +1,41 @@ ++void ++maximize(int x, int y, int w, int h) { ++ XEvent ev; ++ ++ if(!selmon->sel || selmon->sel->isfixed) ++ return; ++ XRaiseWindow(dpy, selmon->sel->win); ++ if(!selmon->sel->ismax) { ++ if(!selmon->lt[selmon->sellt]->arrange || selmon->sel->isfloating) ++ selmon->sel->wasfloating = 1; ++ else { ++ togglefloating(NULL); ++ selmon->sel->wasfloating = 0; ++ } ++ resize(selmon->sel, x, y, w, h, 1); ++ selmon->sel->ismax = 1; ++ } ++ else { ++ resize(selmon->sel, selmon->sel->oldx, selmon->sel->oldy, selmon->sel->oldw, selmon->sel->oldh, 1); ++ if(!selmon->sel->wasfloating) ++ togglefloating(NULL); ++ selmon->sel->ismax = 0; ++ } ++ drawbar(selmon); ++ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); ++} ++ ++void ++togglemaximize(const Arg *arg) { ++ maximize(selmon->wx, selmon->wy, selmon->ww - 2 * borderpx, selmon->wh - 2 * borderpx); ++} ++ ++void ++toggleverticalmax(const Arg *arg) { ++ maximize(selmon->sel->x, selmon->wy, selmon->sel->w, selmon->wh - 2 * borderpx); ++} ++ ++void ++togglehorizontalmax(const Arg *arg) { ++ maximize(selmon->wx, selmon->sel->y, selmon->ww - 2 * borderpx, selmon->sel->h); ++} diff --git a/dwm.suckless.org/patches/dwm-35db6d8-fancybar.diff b/dwm.suckless.org/patches/dwm-35db6d8-fancybar.diff @@ -1,69 +0,0 @@ -diff --git a/dwm.c b/dwm.c -index f896170..3da4cf2 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -692,11 +692,13 @@ dirtomon(int dir) { - - void - drawbar(Monitor *m) { -- int x, xx, w; -- unsigned int i, occ = 0, urg = 0; -+ int x, xx, w, tw, mw; -+ unsigned int i, occ = 0, urg = 0, n = 0, extra = 0; - Client *c; - - for(c = m->clients; c; c = c->next) { -+ if(ISVISIBLE(c)) -+ n++; - occ |= c->tags; - if(c->isurgent) - urg |= c->tags; -@@ -728,15 +730,40 @@ drawbar(Monitor *m) { - 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); -- } -- else { -- drw_setscheme(drw, &scheme[SchemeNorm]); -- drw_text(drw, x, 0, w, bh, NULL, 0); -+ if(n > 0) { -+ tw = m->sel->name ? TEXTW(m->sel->name) : 0; -+ mw = (tw >= w || n == 1) ? 0 : (w - tw) / (n - 1); -+ -+ i = 0; -+ for(c = m->clients; c; c = c->next) { -+ if(!ISVISIBLE(c) || c == m->sel) -+ continue; -+ tw = TEXTW(c->name); -+ if(tw < mw) -+ extra += (mw - tw); -+ else -+ i++; -+ } -+ if(i > 0) -+ mw += extra / i; -+ -+ for(c = m->clients; c; c = c->next) { -+ if(!ISVISIBLE(c)) -+ continue; -+ xx = x + w; -+ tw = TEXTW(c->name); -+ w = MIN(m->sel == c ? w : mw, tw); -+ -+ drw_setscheme(drw, m->sel == c ? &scheme[SchemeSel] : &scheme[SchemeNorm]); -+ drw_text(drw, x, 0, w, bh, c->name, 0); -+ drw_rect(drw, x, 0, w, bh, c->isfixed, c->isfloating, 0); -+ -+ x += w; -+ w = xx - x; -+ } - } -+ drw_setscheme(drw, &scheme[SchemeNorm]); -+ drw_text(drw, x, 0, w, bh, NULL, 0); - } - drw_map(drw, m->barwin, 0, 0, m->ww, bh); - } diff --git a/dwm.suckless.org/patches/dwm-6.0-xft.diff b/dwm.suckless.org/patches/dwm-6.0-xft.diff @@ -1,229 +0,0 @@ ---- ../dwm-o/dwm-6.0/dwm.c 2011-12-19 10:02:46.000000000 -0500 -+++ dwm.c 2012-05-16 22:33:00.043394484 -0400 -@@ -39,6 +39,7 @@ - #ifdef XINERAMA - #include <X11/extensions/Xinerama.h> - #endif /* XINERAMA */ -+#include <X11/Xft/Xft.h> - - /* macros */ - #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) -@@ -99,16 +100,15 @@ - - typedef struct { - int x, y, w, h; -- unsigned long norm[ColLast]; -- unsigned long sel[ColLast]; -+ XftColor norm[ColLast]; -+ XftColor sel[ColLast]; - Drawable drawable; - GC gc; - struct { - int ascent; - int descent; - int height; -- XFontSet set; -- XFontStruct *xfont; -+ XftFont *xfont; - } font; - } DC; /* draw context */ - -@@ -178,15 +178,15 @@ - static Monitor *dirtomon(int dir); - static void drawbar(Monitor *m); - static void drawbars(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 drawsquare(Bool filled, Bool empty, Bool invert, XftColor col[ColLast]); -+static void drawtext(const char *text, XftColor col[ColLast], Bool invert); - 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 unsigned long getcolor(const char *colstr); -+static XftColor getcolor(const char *colstr); - static Bool getrootptr(int *x, int *y); - static long getstate(Window w); - static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); -@@ -485,10 +485,6 @@ - for(m = mons; m; m = m->next) - while(m->stack) - unmanage(m->stack, False); -- if(dc.font.set) -- XFreeFontSet(dpy, dc.font.set); -- else -- XFreeFont(dpy, dc.font.xfont); - XUngrabKey(dpy, AnyKey, AnyModifier, root); - XFreePixmap(dpy, dc.drawable); - XFreeGC(dpy, dc.gc); -@@ -719,7 +715,7 @@ - drawbar(Monitor *m) { - int x; - unsigned int i, occ = 0, urg = 0; -- unsigned long *col; -+ XftColor *col; - Client *c; - - for(c = m->clients; c; c = c->next) { -@@ -774,10 +770,10 @@ - } - - void --drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { -+drawsquare(Bool filled, Bool empty, Bool invert, XftColor col[ColLast]) { - int x; - -- XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); -+ XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG].pixel); - x = (dc.font.ascent + dc.font.descent + 2) / 4; - if(filled) - XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1); -@@ -786,11 +782,12 @@ - } - - void --drawtext(const char *text, unsigned long col[ColLast], Bool invert) { -+drawtext(const char *text, XftColor col[ColLast], Bool invert) { - char buf[256]; - int i, x, y, h, len, olen; -+ XftDraw *d; - -- XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); -+ XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG].pixel); - XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); - if(!text) - return; -@@ -805,11 +802,11 @@ - memcpy(buf, text, len); - if(len < olen) - 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); -- else -- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); -+ -+ d = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy, screen), DefaultColormap(dpy,screen)); -+ -+ XftDrawStringUtf8(d, &col[invert ? ColBG : ColFG], dc.font.xfont, x, y, (XftChar8 *) buf, len); -+ XftDrawDestroy(d); - } - - void -@@ -855,7 +852,7 @@ - detachstack(c); - attachstack(c); - grabbuttons(c, True); -- XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); -+ XSetWindowBorder(dpy, c->win, dc.sel[ColBorder].pixel); - setfocus(c); - } - else -@@ -926,14 +923,14 @@ - return atom; - } - --unsigned long -+XftColor - getcolor(const char *colstr) { -- Colormap cmap = DefaultColormap(dpy, screen); -- XColor color; -+ XftColor color; - -- if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) -+ if(!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), colstr, &color)) - die("error, cannot allocate color '%s'\n", colstr); -- return color.pixel; -+ -+ return color; - } - - Bool -@@ -1034,35 +1031,13 @@ - - void - initfont(const char *fontstr) { -- char *def, **missing; -- int n; - -- dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); -- if(missing) { -- while(n--) -- fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); -- XFreeStringList(missing); -- } -- if(dc.font.set) { -- XFontStruct **xfonts; -- char **font_names; -- -- dc.font.ascent = dc.font.descent = 0; -- XExtentsOfFontSet(dc.font.set); -- n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); -- while(n--) { -- dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); -- dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent); -- xfonts++; -- } -- } -- else { -- if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) -- && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) -- die("error, cannot load font: '%s'\n", fontstr); -- dc.font.ascent = dc.font.xfont->ascent; -- dc.font.descent = dc.font.xfont->descent; -- } -+ if(!(dc.font.xfont = XftFontOpenName(dpy,screen,fontstr)) -+ && !(dc.font.xfont = XftFontOpenName(dpy,screen,"fixed"))) -+ die("error, cannot load font: '%s'\n", fontstr); -+ -+ dc.font.ascent = dc.font.xfont->ascent; -+ dc.font.descent = dc.font.xfont->descent; - dc.font.height = dc.font.ascent + dc.font.descent; - } - -@@ -1144,7 +1119,7 @@ - - wc.border_width = c->bw; - XConfigureWindow(dpy, w, CWBorderWidth, &wc); -- XSetWindowBorder(dpy, w, dc.norm[ColBorder]); -+ XSetWindowBorder(dpy, w, dc.norm[ColBorder].pixel); - configure(c); /* propagates border_width, if size doesn't change */ - updatewindowtype(c); - updatesizehints(c); -@@ -1621,8 +1596,6 @@ - dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); - dc.gc = XCreateGC(dpy, root, 0, NULL); - XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); -- if(!dc.font.set) -- XSetFont(dpy, dc.gc, dc.font.xfont->fid); - /* init bars */ - updatebars(); - updatestatus(); -@@ -1692,13 +1665,9 @@ - - int - textnw(const char *text, unsigned int len) { -- XRectangle r; -- -- if(dc.font.set) { -- XmbTextExtents(dc.font.set, text, len, NULL, &r); -- return r.width; -- } -- return XTextWidth(dc.font.xfont, text, len); -+ XGlyphInfo ext; -+ XftTextExtentsUtf8(dpy, dc.font.xfont, (XftChar8 *) text, len, &ext); -+ return ext.xOff; - } - - void -@@ -1776,7 +1745,7 @@ - if(!c) - return; - grabbuttons(c, False); -- XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]); -+ XSetWindowBorder(dpy, c->win, dc.norm[ColBorder].pixel); - if(setfocus) - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); - } diff --git a/dwm.suckless.org/patches/dwm-6.1-attachabove.diff b/dwm.suckless.org/patches/dwm-6.1-attachabove.diff @@ -1,13 +1,11 @@ Author: Jan Christoph Ebersbach <jceb@e-jc.de> URL: http://dwm.suckless.org/patches/attachabove attachabove makes new clients attach above the selected client (instead of -always becoming the new master) – basically how Xmonad does it. +always becoming the new master) - basically how Xmonad does it. -Index: dwm/dwm.c -=================================================================== ---- dwm/dwm.c.orig 2014-02-09 15:24:20.560117200 +0100 -+++ dwm/dwm.c 2014-02-09 15:24:20.552117200 +0100 -@@ -146,6 +146,7 @@ +--- dwm/dwm.c.orig 2015-11-22 10:48:28.288368772 -0700 ++++ dwm/dwm.c 2015-11-22 10:51:45.308360761 -0700 +@@ -147,6 +147,7 @@ static int applysizehints(Client *c, int static void arrange(Monitor *m); static void arrangemon(Monitor *m); static void attach(Client *c); @@ -15,11 +13,12 @@ Index: dwm/dwm.c static void attachstack(Client *c); static void buttonpress(XEvent *e); static void checkotherwm(void); -@@ -401,6 +402,19 @@ +@@ -406,6 +407,20 @@ attach(Client *c) } void -+attachabove(Client *c) { ++attachabove(Client *c) ++{ + if(c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating) { + attach(c); + return; @@ -32,19 +31,19 @@ Index: dwm/dwm.c +} + +void - attachstack(Client *c) { + attachstack(Client *c) + { c->snext = c->mon->stack; - c->mon->stack = c; -@@ -1051,7 +1065,7 @@ +@@ -1076,7 +1091,7 @@ manage(Window w, XWindowAttributes *wa) c->isfloating = c->oldstate = trans != None || c->isfixed; - if(c->isfloating) + if (c->isfloating) XRaiseWindow(dpy, c->win); - attach(c); + attachabove(c); attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); -@@ -1383,7 +1397,7 @@ +@@ -1434,7 +1449,7 @@ sendmon(Client *c, Monitor *m) detachstack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ @@ -53,7 +52,7 @@ Index: dwm/dwm.c attachstack(c); focus(NULL); arrange(NULL); -@@ -1818,7 +1832,7 @@ +@@ -1891,7 +1906,7 @@ updategeom(void) m->clients = c->next; detachstack(c); c->mon = mons; @@ -61,4 +60,4 @@ Index: dwm/dwm.c + attachabove(c); attachstack(c); } - if(m == selmon) + if (m == selmon) diff --git a/dwm.suckless.org/patches/dwm-6.1-better-borders.diff b/dwm.suckless.org/patches/dwm-6.1-better-borders.diff @@ -4,89 +4,88 @@ window is visible. Additionally, any windows that are the same size as the monitor are considered full-screen and their borders removed accordingly. diff --git a/dwm.c b/dwm.c -index ffc8864..3ce8ebe 100644 +index 0362114..03fddb6 100644 --- a/dwm.c +++ b/dwm.c -@@ -308,6 +308,34 @@ applyrules(Client *c) { - c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; - } - -+void -+adjustborders(Monitor *m) { -+ Client *c, *l = NULL; -+ int visible = 0; -+ -+ for(c = m->clients; c; c = c->next) { -+ if (ISVISIBLE(c) && !c->isfloating && m->lt[m->sellt]->arrange) { -+ if (m->lt[m->sellt]->arrange == monocle) { -+ visible = 1; -+ c->oldbw = c->bw; -+ c->bw = 0; -+ } else { -+ visible++; -+ c->oldbw = c->bw; +@@ -393,9 +393,24 @@ arrange(Monitor *m) + void + arrangemon(Monitor *m) + { ++ int n = 0; ++ Client *c; + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); +- if (m->lt[m->sellt]->arrange) +- m->lt[m->sellt]->arrange(m); ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if (n > 1 || !m->lt[m->sellt]->arrange) { ++ for (c = m->clients; c; c = c->next) { ++ if (ISVISIBLE(c) && (!m->lt[m->sellt]->arrange || !c->isfloating) && (c->bw != borderpx)) { ++ c->oldbw = c->oldbw; + c->bw = borderpx; ++ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw)); + } -+ -+ l = c; + } ++ if (m->lt[m->sellt]->arrange) { ++ m->lt[m->sellt]->arrange(m); ++ } ++ } else { ++ monocle(m); + } -+ -+ if (l && visible == 1 && l->bw) { -+ l->oldbw = l->bw; -+ l->bw = 0; -+ resizeclient(l, l->x, l->y, l->w, l->h); -+ } -+} -+ - Bool - applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { - Bool baseismin; -@@ -376,10 +404,13 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { + } void - arrange(Monitor *m) { -- if(m) -+ if(m) { -+ adjustborders(m); - showhide(m->stack); -- else for(m = mons; m; m = m->next) -+ } else for(m = mons; m; m = m->next) { -+ adjustborders(m); - showhide(m->stack); -+ } - if(m) { - arrangemon(m); - restack(m); -@@ -1036,7 +1067,20 @@ manage(Window w, XWindowAttributes *wa) { - /* 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->bw = borderpx; -+ -+ updatewindowtype(c); -+ if (c->isfloating) { -+ c->bw = c->isfullscreen ? 0 : borderpx; -+ } else { -+ c->bw = 0; -+ for(t = c->mon->clients; t; t = c->next) { -+ if (!t->isfloating && c != t && c->tags & t->tags) { -+ c->bw = borderpx; -+ break; -+ } +@@ -1117,16 +1132,25 @@ maprequest(XEvent *e) + void + monocle(Monitor *m) + { +- unsigned int n = 0; ++ unsigned int n = 0, r = 0; + Client *c; + + for (c = m->clients; c; c = c->next) + if (ISVISIBLE(c)) + n++; +- if (n > 0) /* override layout symbol */ ++ if (n > 0 && m->lt[m->sellt]->arrange == monocle) /* override layout symbol */ + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); +- for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) +- resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); ++ for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) { ++ if (c->bw) { ++ c->oldbw = c->bw; ++ c->bw = 0; ++ r = 1; ++ } ++ resize(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw), False); ++ if(r) { ++ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw)); + } -+ adjustborders(c->mon); + } + } + + void +@@ -1706,9 +1730,11 @@ togglefloating(const Arg *arg) + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; +- if (selmon->sel->isfloating) +- resize(selmon->sel, selmon->sel->x, selmon->sel->y, +- selmon->sel->w, selmon->sel->h, 0); ++ if (selmon->sel->isfloating) { ++ selmon->sel->oldbw = selmon->sel->bw; ++ selmon->sel->bw = borderpx; ++ resizeclient(selmon->sel, selmon->wx, selmon->wy, selmon->ww - (2 * selmon->sel->bw), selmon->wh - (2 * selmon->sel->bw)); ++ } + arrange(selmon); + } - wc.border_width = c->bw; - XConfigureWindow(dpy, w, CWBorderWidth, &wc); -@@ -1933,7 +1977,8 @@ updatewindowtype(Client *c) { +@@ -2003,7 +2029,8 @@ updatewindowtype(Client *c) Atom state = getatomprop(c, netatom[NetWMState]); Atom wtype = getatomprop(c, netatom[NetWMWindowType]); -- if(state == netatom[NetWMFullscreen]) +- if (state == netatom[NetWMFullscreen]) + if(state == netatom[NetWMFullscreen] || -+ (WIDTH(c) == (c->mon->mx + c->mon->mw) && (HEIGHT(c) == (c->mon->my + c->mon->mh)))) - setfullscreen(c, True); - if(wtype == netatom[NetWMWindowTypeDialog]) - c->isfloating = True; ++ (WIDTH(c) >= (c->mon->mx + c->mon->mw) && (HEIGHT(c) >= (c->mon->my + c->mon->mh)))) + setfullscreen(c, 1); + if (wtype == netatom[NetWMWindowTypeDialog]) + c->isfloating = 1; diff --git a/dwm.suckless.org/patches/dwm-6.1-center.diff b/dwm.suckless.org/patches/dwm-6.1-center.diff @@ -0,0 +1,58 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..e0cdcf3 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -24,9 +24,9 @@ static const Rule rules[] = { + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ +- /* class instance title tags mask isfloating monitor */ +- { "Gimp", NULL, NULL, 0, 1, -1 }, +- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ /* class instance title tags mask iscentered isfloating monitor */ ++ { "Gimp", NULL, NULL, 0, 0, 1, -1 }, ++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 }, + }; + + /* layout(s) */ +diff --git a/dwm.c b/dwm.c +index 0362114..4aaaa60 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -92,7 +92,7 @@ struct Client { + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; +- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int isfixed, iscentered, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; +@@ -137,6 +137,7 @@ typedef struct { + const char *instance; + const char *title; + unsigned int tags; ++ int iscentered; + int isfloating; + int monitor; + } Rule; +@@ -296,6 +297,7 @@ applyrules(Client *c) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { ++ c->iscentered = r->iscentered; + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); +@@ -1063,6 +1065,11 @@ manage(Window w, XWindowAttributes *wa) + && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + c->bw = borderpx; + ++ if(c->iscentered) { ++ c->x = (c->mon->mw - WIDTH(c)) / 2; ++ c->y = (c->mon->mh - HEIGHT(c)) / 2; ++ } ++ + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); + XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix); diff --git a/dwm.suckless.org/patches/dwm-6.1-centeredmaster.diff b/dwm.suckless.org/patches/dwm-6.1-centeredmaster.diff @@ -1,58 +1,59 @@ diff --git a/dwm.c b/dwm.c -index 783fcdb..ab179d8 100644 +index 0362114..fa5ae4c 100644 --- a/dwm.c +++ b/dwm.c -@@ -215,6 +215,7 @@ static void tag(const Arg *arg); +@@ -209,6 +209,7 @@ static void spawn(const Arg *arg); + static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); - static void htile(Monitor *); +static void centeredmaster(Monitor *); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); -@@ -1748,6 +1749,45 @@ htile(Monitor *m) { +@@ -1690,6 +1691,46 @@ tile(Monitor *m) } void -+centeredmaster(Monitor *m) { ++centeredmaster(Monitor *m) ++{ + unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; + Client *c; + -+ // Count number of clients in the selected monitor ++ // Count number of clients in the selected monitor + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + -+ // initialize nmaster area ++ // initialize nmaster area + if(n > m->nmaster) { -+ // go mfact box in the center if more than nmaster clients ++ // go mfact box in the center if more than nmaster clients + mw = m->nmaster ? m->ww * m->mfact : 0; + mh = m->nmaster ? m->wh * m->mfact : 0; -+ mx = mxo = (m->ww - mw) / 2; -+ my = myo = (m->wh - mh) / 2; -+ } else { -+ // Go fullscreen if all clients are in the master area ++ mx = mxo = (m->ww - mw) / 2; ++ my = myo = (m->wh - mh) / 2; ++ } else { ++ // Go fullscreen if all clients are in the master area + mh = m->wh; -+ mw = m->ww; -+ mx = mxo = 0; -+ my = mxo = 0; -+ } ++ mw = m->ww; ++ mx = mxo = 0; ++ my = mxo = 0; ++ } + + for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { -+ // nmaster clients are stacked horizontally, in the center of the screen -+ w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); ++ // nmaster clients are stacked horizontally, in the center of the screen ++ w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), mh - (2*c->bw), False); + mx += WIDTH(c); + } else { -+ // Stack clients are stacked horizontally -+ w = (m->ww - tx) / (n - i); -+ resize(c, tx, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); ++ // Stack clients are stacked horizontally ++ w = (m->ww - tx) / (n - i); ++ resize(c, m->wx + tx, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); + tx += WIDTH(c); + } +} + +void - togglebar(const Arg *arg) { - selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; - updatebarpos(selmon); + togglebar(const Arg *arg) + { + selmon->showbar = !selmon->showbar; diff --git a/dwm.suckless.org/patches/dwm-6.1-combo.diff b/dwm.suckless.org/patches/dwm-6.1-combo.diff @@ -0,0 +1,75 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..40b7a99 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -234,6 +234,11 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + ++static void keyrelease(XEvent *e); ++static void combotag(const Arg *arg); ++static void comboview(const Arg *arg); ++ ++ + /* variables */ + static const char broken[] = "broken"; + static char stext[256]; +@@ -244,6 +249,7 @@ static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, ++ [ButtonRelease] = keyrelease, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, +@@ -251,6 +257,7 @@ static void (*handler[LASTEvent]) (XEvent *) = { + [EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, ++ [KeyRelease] = keyrelease, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, +@@ -274,6 +281,42 @@ static Window root; + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + + /* function implementations */ ++static int combo = 0; ++ ++void ++keyrelease(XEvent *e) { ++ combo = 0; ++} ++ ++void ++combotag(const Arg *arg) { ++ if(selmon->sel && arg->ui & TAGMASK) { ++ if (combo) { ++ selmon->sel->tags |= arg->ui & TAGMASK; ++ } else { ++ combo = 1; ++ selmon->sel->tags = arg->ui & TAGMASK; ++ } ++ focus(NULL); ++ arrange(selmon); ++ } ++} ++ ++void ++comboview(const Arg *arg) { ++ unsigned newtags = arg->ui & TAGMASK; ++ if (combo) { ++ selmon->tagset[selmon->seltags] |= newtags; ++ } else { ++ selmon->seltags ^= 1; /*toggle tagset*/ ++ combo = 1; ++ if (newtags) ++ selmon->tagset[selmon->seltags] = newtags; ++ } ++ focus(NULL); ++ arrange(selmon); ++} ++ + void + applyrules(Client *c) + { diff --git a/dwm.suckless.org/patches/dwm-6.1-dualstatus.diff b/dwm.suckless.org/patches/dwm-6.1-dualstatus.diff @@ -1,16 +1,16 @@ diff --git a/config.def.h b/config.def.h -index eaae8f3..05ca3cb 100644 +index 7054c06..b96107a 100644 --- a/config.def.h +++ b/config.def.h -@@ -17,6 +17,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ +@@ -15,6 +15,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 Bool extrabar = True; /* False means no extra bar */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++static const int extrabar = 1; /* 0 means no extra bar */ /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; -@@ -64,6 +65,7 @@ static Key keys[] = { +@@ -62,6 +63,7 @@ static Key keys[] = { { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, { MODKEY, XK_b, togglebar, {0} }, @@ -19,7 +19,7 @@ index eaae8f3..05ca3cb 100644 { MODKEY, XK_k, focusstack, {.i = -1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } }, diff --git a/dwm.c b/dwm.c -index 169adcb..0eae8b2 100644 +index 0362114..9b7cd74 100644 --- a/dwm.c +++ b/dwm.c @@ -141,6 +141,13 @@ typedef struct { @@ -28,14 +28,14 @@ index 169adcb..0eae8b2 100644 +typedef struct { + int y; -+ Bool show; ++ int show; + Window win; + char text[256]; +} Bar; + /* function declarations */ static void applyrules(Client *c); - static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); @@ -210,6 +217,7 @@ static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); @@ -52,24 +52,24 @@ index 169adcb..0eae8b2 100644 /* configuration, allows nested code to access above variables */ #include "config.h" -@@ -469,6 +478,8 @@ cleanup(void) { - while(m->stack) - unmanage(m->stack, False); +@@ -477,6 +486,8 @@ cleanup(void) + while (m->stack) + unmanage(m->stack, 0); XUngrabKey(dpy, AnyKey, AnyModifier, root); + XUnmapWindow(dpy, eb.win); + XDestroyWindow(dpy, eb.win); - while(mons) + while (mons) cleanupmon(mons); - drw_cur_free(drw, cursor[CurNormal]); -@@ -568,6 +579,7 @@ configurenotify(XEvent *e) { + for (i = 0; i < CurLast; i++) +@@ -578,6 +589,7 @@ configurenotify(XEvent *e) 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); + XMoveResizeWindow(dpy, eb.win, mons->wx, eb.y, mons->ww, bh); focus(NULL); arrange(NULL); } -@@ -738,6 +750,9 @@ drawbar(Monitor *m) { +@@ -751,6 +763,9 @@ drawbar(Monitor *m) } } drw_map(drw, m->barwin, 0, 0, m->ww, bh); @@ -79,19 +79,20 @@ index 169adcb..0eae8b2 100644 } void -@@ -1509,6 +1524,7 @@ setup(void) { +@@ -1558,6 +1573,7 @@ setup(void) root = RootWindow(dpy, screen); drw = drw_create(dpy, screen, root, sw, sh); drw_load_fonts(drw, fonts, LENGTH(fonts)); + eb.show = extrabar; if (!drw->fontcount) - die("No fonts could be loaded.\n"); + die("no fonts could be loaded.\n"); bh = drw->fonts[0]->h + 2; -@@ -1643,6 +1659,16 @@ togglebar(const Arg *arg) { +@@ -1699,6 +1715,17 @@ togglebar(const Arg *arg) } void -+toggleextrabar(const Arg *arg) { ++toggleextrabar(const Arg *arg) ++{ + if(selmon == mons) { + eb.show = !eb.show; + updatebarpos(selmon); @@ -101,26 +102,26 @@ index 169adcb..0eae8b2 100644 +} + +void - togglefloating(const Arg *arg) { - if(!selmon->sel) - return; -@@ -1747,6 +1773,13 @@ updatebars(void) { + togglefloating(const Arg *arg) + { + if (!selmon->sel) +@@ -1810,6 +1837,13 @@ updatebars(void) XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); XMapRaised(dpy, m->barwin); } + if(!eb.win) { + eb.win = XCreateWindow(dpy, root, mons->wx, eb.y, mons->ww, bh, 0, DefaultDepth(dpy, screen), -+ CopyFromParent, DefaultVisual(dpy, screen), -+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, eb.win, cursor[CurNormal]->cursor); + XMapRaised(dpy, eb.win); + } } void -@@ -1760,6 +1793,13 @@ updatebarpos(Monitor *m) { - } - else +@@ -1823,6 +1857,13 @@ updatebarpos(Monitor *m) + m->wy = m->topbar ? m->wy + bh : m->wy; + } else m->by = -bh; + if(m == mons && eb.show) { + m->wh -= bh; @@ -132,11 +133,11 @@ index 169adcb..0eae8b2 100644 } void -@@ -1932,8 +1972,21 @@ updatetitle(Client *c) { - +@@ -1992,8 +2033,21 @@ updatetitle(Client *c) void - updatestatus(void) { -- if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + updatestatus(void) + { +- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + char text[512]; + if(!gettextprop(root, XA_WM_NAME, text, sizeof(text))) { strcpy(stext, "dwm-"VERSION); diff --git a/dwm.suckless.org/patches/dwm-6.1-fancybar.diff b/dwm.suckless.org/patches/dwm-6.1-fancybar.diff @@ -0,0 +1,70 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..b74e787 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -704,13 +704,15 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, xx, w, dx; +- unsigned int i, occ = 0, urg = 0; ++ int x, xx, w, dx, tw, mw; ++ unsigned int i, occ = 0, urg = 0, n = 0, extra = 0; + Client *c; + + dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; + + for (c = m->clients; c; c = c->next) { ++ if (ISVISIBLE(c)) ++ n++; + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; +@@ -741,14 +743,40 @@ drawbar(Monitor *m) + 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 + 1, 1, dx, dx, m->sel->isfixed, m->sel->isfloating, 0); +- } else { +- drw_setscheme(drw, &scheme[SchemeNorm]); +- drw_rect(drw, x, 0, w, bh, 1, 0, 1); ++ if (n > 0) { ++ tw = m->sel->name ? TEXTW(m->sel->name) : 0; ++ mw = (tw >= w || n == 1) ? 0 : (w - tw) / (n - 1); ++ ++ i = 0; ++ for (c = m->clients; c; c = c->next) { ++ if (!ISVISIBLE(c) || c == m->sel) ++ continue; ++ tw = TEXTW(c->name); ++ if(tw < mw) ++ extra += (mw - tw); ++ else ++ i++; ++ } ++ if (i > 0) ++ mw += extra / i; ++ ++ for (c = m->clients; c; c = c->next) { ++ if (!ISVISIBLE(c)) ++ continue; ++ xx = x + w; ++ tw = TEXTW(c->name); ++ w = MIN(m->sel == c ? w : mw, tw); ++ ++ drw_setscheme(drw, m->sel == c ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, bh, c->name, 0); ++ drw_rect(drw, x + 1, 1, dx, dx, c->isfixed, c->isfloating, 0); ++ ++ x += w; ++ w = xx - x; ++ } + } ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ drw_rect(drw, x, 0, w, bh, 1, 0, 1); + } + drw_map(drw, m->barwin, 0, 0, m->ww, bh); + } diff --git a/dwm.suckless.org/patches/dwm-6.1-fancybarclickable.diff b/dwm.suckless.org/patches/dwm-6.1-fancybarclickable.diff @@ -6,7 +6,7 @@ index 875885b..05865bb 100644 /* click event mask button function argument */ { ClkLtSymbol, 0, Button1, setlayout, {0} }, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, -+ { ClkWinTitle, 0, Button1, focusonclick, {0} }, ++ { ClkWinTitle, 0, Button1, focusonclick, {0} }, { ClkWinTitle, 0, Button2, zoom, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, @@ -18,8 +18,8 @@ index f896170..cc2a4f2 100644 Monitor *next; Window barwin; const Layout *lt[2]; -+ int titlebarbegin; -+ int titlebarend; ++ int titlebarbegin; ++ int titlebarend; }; typedef struct { @@ -44,9 +44,9 @@ index f896170..cc2a4f2 100644 click = ClkStatusText; - else + else { -+ arg.ui = ev->x; ++ arg.ui = ev->x; click = ClkWinTitle; -+ } ++ } } else if((c = wintoclient(ev->window))) { focus(c); @@ -67,13 +67,13 @@ index f896170..cc2a4f2 100644 - unsigned int i, occ = 0, urg = 0; - Client *c; + int x, xx, w, ow, mw = 0, extra, tw, a = 0, s = 0; -+ char posbuf[10]; ++ char posbuf[10]; + unsigned int i, occ = 0, urg = 0, n = 0; + Client *c, *firstvis, *lastvis = NULL; for(c = m->clients; c; c = c->next) { -+ if(ISVISIBLE(c)) -+ n++; ++ if(ISVISIBLE(c)) ++ n++; occ |= c->tags; if(c->isurgent) urg |= c->tags; @@ -82,36 +82,35 @@ index f896170..cc2a4f2 100644 xx = x; if(m == selmon) { /* status is only drawn on selected monitor */ - w = TEXTW(stext); -+ if(m->lt[m->sellt]->arrange == monocle){ -+ x = xx; -+ for(c = nexttiled(m->clients), a = 0, s = 0; c; c = nexttiled(c->next), a++) { -+ if(c == m->stack) -+ s = a; -+ } -+ if(!s && a) -+ s = a; -+ snprintf(posbuf, LENGTH(posbuf), "[%d/%d]", s, a); -+ w = TEXTW(posbuf); -+ drw_text(drw, x, 0, w, bh, posbuf, 0); -+ xx = x + w; -+ } ++ if(m->lt[m->sellt]->arrange == monocle){ ++ x = xx; ++ for(c = nexttiled(m->clients), a = 0, s = 0; c; c = nexttiled(c->next), a++) { ++ if(c == m->stack) ++ s = a; ++ } ++ if(!s && a) ++ s = a; ++ snprintf(posbuf, LENGTH(posbuf), "[%d/%d]", s, a); ++ w = TEXTW(posbuf); ++ drw_text(drw, x, 0, w, bh, posbuf, 0); ++ xx = x + w; ++ } + -+ /* -+ char *buf = stext, *ptr = buf; -+ while (*ptr) { -+ for (i = 0; *ptr < 0; i++, ptr++); -+ w 2+= drw_font_getexts_width(drw->font, buf, i); -+ w += TEXTW(buf); -+ buf=++ptr; -+ }*/ -+ w = TEXTW(stext); ++ /* char *buf = stext, *ptr = buf; ++ while (*ptr) { ++ for (i = 0; *ptr < 0; i++, ptr++); ++ w 2+= drw_font_getexts_width(drw->font, buf, i); ++ w += TEXTW(buf); ++ buf=++ptr; ++ } */ ++ w = TEXTW(stext); + x = m->ww - w; if(x < xx) { x = xx; w = m->ww - xx; } -+ m->titlebarend=x; ++ m->titlebarend=x; drw_text(drw, x, 0, w, bh, stext, 0); } - else @@ -125,72 +124,72 @@ index f896170..cc2a4f2 100644 - drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, 0); - } - else { -+ m->titlebarbegin=x; -+ } -+ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); -+ firstvis = c; ++ m->titlebarbegin=x; ++ } ++ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); ++ firstvis = c; + -+ drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); -+ w = x - xx; -+ x = xx; ++ drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ w = x - xx; ++ x = xx; + -+ if(n > 0) { -+ mw = w / n; -+ extra = 0; -+ i = 0; ++ if(n > 0) { ++ mw = w / n; ++ extra = 0; ++ i = 0; + -+ while(c) { -+ lastvis = c; -+ tw = TEXTW(c->name); -+ if(tw < mw) extra += (mw - tw); else i++; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); -+ } ++ while(c) { ++ lastvis = c; ++ tw = TEXTW(c->name); ++ if(tw < mw) extra += (mw - tw); else i++; ++ for(c = c->next; c && !ISVISIBLE(c); c = c->next); ++ } + -+ if(i > 0) mw += extra / i; ++ if(i > 0) mw += extra / i; + -+ c = firstvis; -+ xx = x; -+ } -+ m->titlebarbegin=x; -+ while(w > bh) { -+ if(c) { -+ ow = w; -+ tw = TEXTW(c->name); -+ w = MIN(ow, tw); ++ c = firstvis; ++ xx = x; ++ } ++ m->titlebarbegin=x; ++ while(w > bh) { ++ if(c) { ++ ow = w; ++ tw = TEXTW(c->name); ++ w = MIN(ow, tw); + -+ if(w > mw) w = mw; -+ if(c == lastvis) w = ow; ++ if(w > mw) w = mw; ++ if(c == lastvis) w = ow; + -+ drw_text(drw, x, 0, w, bh, c->name, False); -+ if(c != firstvis) drawline(x, 0); -+ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, True); ++ drw_text(drw, x, 0, w, bh, c->name, False); ++ if(c != firstvis) drawline(x, 0); ++ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, True); + -+ x += w; -+ w = ow - w; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); ++ x += w; ++ w = ow - w; ++ for(c = c->next; c && !ISVISIBLE(c); c = c->next); + } else { drw_setscheme(drw, &scheme[SchemeNorm]); drw_text(drw, x, 0, w, bh, NULL, 0); -+ break; ++ break; } } + -+ if(m == selmon && m->sel && ISVISIBLE(m->sel)) { -+ drw_text(drw, x, 0, w, bh, m->sel->name, True); -+ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, True); -+ } ++ if(m == selmon && m->sel && ISVISIBLE(m->sel)) { ++ drw_text(drw, x, 0, w, bh, m->sel->name, True); ++ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, True); ++ } + drw_map(drw, m->barwin, 0, 0, m->ww, bh); } void +drawline(int x, int y) { -+ XGCValues gcv; ++ XGCValues gcv; + -+ gcv.foreground = drw->scheme->fg->rgb; ++ gcv.foreground = drw->scheme->fg->rgb; + -+ XChangeGC(dpy, drw->gc, GCForeground, &gcv); -+ XDrawLine(dpy, drw->drawable, drw->gc, x, y, x, y + (drw->font->ascent + drw->font->descent + 2)); ++ XChangeGC(dpy, drw->gc, GCForeground, &gcv); ++ XDrawLine(dpy, drw->drawable, drw->gc, x, y, x, y + (drw->font->ascent + drw->font->descent + 2)); +} + +void @@ -202,47 +201,47 @@ index f896170..cc2a4f2 100644 void +focusonclick(const Arg *arg) { -+ int x, w, mw = 0, tw, n = 0, i = 0, extra = 0; -+ Monitor *m = selmon; -+ Client *c, *firstvis; ++ int x, w, mw = 0, tw, n = 0, i = 0, extra = 0; ++ Monitor *m = selmon; ++ Client *c, *firstvis; + -+ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); -+ firstvis = c; ++ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); ++ firstvis = c; + -+ for(c = m->clients; c; c = c->next) -+ if (ISVISIBLE(c)) -+ n++; ++ for(c = m->clients; c; c = c->next) ++ if (ISVISIBLE(c)) ++ n++; + -+ if(n > 0) { -+ mw = (m->titlebarend - m->titlebarbegin) / n; -+ c = firstvis; -+ while(c) { -+ tw = TEXTW(c->name); -+ if(tw < mw) extra += (mw - tw); else i++; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); -+ } -+ if(i > 0) mw += extra / i; -+ } ++ if(n > 0) { ++ mw = (m->titlebarend - m->titlebarbegin) / n; ++ c = firstvis; ++ while(c) { ++ tw = TEXTW(c->name); ++ if(tw < mw) extra += (mw - tw); else i++; ++ for(c = c->next; c && !ISVISIBLE(c); c = c->next); ++ } ++ if(i > 0) mw += extra / i; ++ } + -+ x=m->titlebarbegin; ++ x=m->titlebarbegin; + -+ c = firstvis; -+ while(x < m->titlebarend) { -+ if(c) { -+ w=MIN(TEXTW(c->name), mw); -+ if (x < arg->i && x+w > arg->i) { -+ focus(c); -+ restack(selmon); -+ break; -+ } else { -+ x+=w; -+ } ++ c = firstvis; ++ while(x < m->titlebarend) { ++ if(c) { ++ w=MIN(TEXTW(c->name), mw); ++ if (x < arg->i && x+w > arg->i) { ++ focus(c); ++ restack(selmon); ++ break; ++ } else { ++ x+=w; ++ } + -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); -+ } else { -+ break; -+ } -+ } ++ for(c = c->next; c && !ISVISIBLE(c); c = c->next); ++ } else { ++ break; ++ } ++ } +} + +void @@ -255,7 +254,7 @@ index f896170..cc2a4f2 100644 updatetitle(c); - if(c == c->mon->sel) - drawbar(c->mon); -+ drawbar(c->mon); ++ drawbar(c->mon); } if(ev->atom == netatom[NetWMWindowType]) updatewindowtype(c); 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 @@ -1,10 +1,10 @@ diff --git a/dwm.c b/dwm.c -index ffc8864..0e5d3f1 100644 +index 0362114..0da6e27 100644 --- a/dwm.c +++ b/dwm.c -@@ -423,9 +423,15 @@ buttonpress(XEvent *e) { +@@ -430,9 +430,15 @@ buttonpress(XEvent *e) } - if(ev->window == selmon->barwin) { + if (ev->window == selmon->barwin) { i = x = 0; - do + unsigned int occ = 0; @@ -15,22 +15,22 @@ index ffc8864..0e5d3f1 100644 + 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)) { +- 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) { +@@ -717,11 +723,14 @@ drawbar(Monitor *m) } x = 0; - for(i = 0; i < LENGTH(tags); i++) { + 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, + drw_rect(drw, x + 1, 1, dx, dx, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - occ & 1 << i, urg & 1 << i); + 0, urg & 1 << i); x += w; diff --git a/dwm.suckless.org/patches/dwm-6.1-horizgrid.diff b/dwm.suckless.org/patches/dwm-6.1-horizgrid.diff @@ -0,0 +1,70 @@ +From 064e1d48631cd9b03f32b42d7be79677197ee42f Mon Sep 17 00:00:00 2001 +From: Marshall Mason <marshallmason3@gmail.com> +Date: Mon, 9 Nov 2015 12:38:28 -0800 +Subject: [PATCH] Added horizgrid function + +--- + config.def.h | 2 ++ + horizgrid.c | 32 ++++++++++++++++++++++++++++++++ + 2 files changed, 34 insertions(+) + create mode 100644 horizgrid.c + +diff --git a/config.def.h b/config.def.h +index eaae8f3..c2ad519 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -36,11 +36,13 @@ 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 */ + ++#include "horizgrid.c" + static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "###", horizgrid }, + }; + + /* key definitions */ +diff --git a/horizgrid.c b/horizgrid.c +new file mode 100644 +index 0000000..51ce0f8 +--- /dev/null ++++ b/horizgrid.c +@@ -0,0 +1,32 @@ ++void ++horizgrid(Monitor *m) { ++ Client *c; ++ unsigned int n, i; ++ int w = 0; ++ int ntop, nbottom = 0; ++ ++ /* Count windows */ ++ for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ ++ if(n == 0) ++ return; ++ else if(n == 1) { /* Just fill the whole screen */ ++ c = nexttiled(m->clients); ++ resize(c, m->wx, m->wy, m->ww - (2*c->bw), m->wh - (2*c->bw), False); ++ } else if(n == 2) { /* Split vertically */ ++ w = m->ww / 2; ++ c = nexttiled(m->clients); ++ resize(c, m->wx, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); ++ c = nexttiled(c->next); ++ resize(c, m->wx + w, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); ++ } else { ++ ntop = n / 2; ++ nbottom = n - ntop; ++ for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { ++ if(i < ntop) ++ resize(c, m->wx + i * m->ww / ntop, m->wy, m->ww / ntop - (2*c->bw), m->wh / 2 - (2*c->bw), False); ++ else ++ resize(c, m->wx + (i - ntop) * m->ww / nbottom, m->wy + m->wh / 2, m->ww / nbottom - (2*c->bw), m->wh / 2 - (2*c->bw), False); ++ } ++ } ++} +-- +2.1.4 + diff --git a/dwm.suckless.org/patches/dwm-6.1-make-the-borders-of-urgent-windows-a-different-color.diff b/dwm.suckless.org/patches/dwm-6.1-make-the-borders-of-urgent-windows-a-different-color.diff @@ -1,61 +0,0 @@ -From 8b7bc42822cd5924450bbfc9ed598f72254473ba Mon Sep 17 00:00:00 2001 -From: Alexander Huemer <alexander.huemer@xx.vu> -Date: Sat, 7 Mar 2015 21:45:48 +0100 -Subject: [PATCH] Make the borders of urgent windows a different color - ---- - config.def.h | 1 + - dwm.c | 10 ++++++++-- - 2 files changed, 9 insertions(+), 2 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 875885b..5276f02 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -8,6 +8,7 @@ static const char normfgcolor[] = "#bbbbbb"; - static const char selbordercolor[] = "#005577"; - static const char selbgcolor[] = "#005577"; - static const char selfgcolor[] = "#eeeeee"; -+static const char urgbordercolor[] = "#ff0000"; - 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 */ -diff --git a/dwm.c b/dwm.c -index c8fc7d7..0924ace 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -58,7 +58,7 @@ - - /* enums */ - enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ --enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ -+enum { SchemeNorm, SchemeSel, SchemeUrg, SchemeLast }; /* color schemes */ - enum { NetSupported, NetWMName, NetWMState, - NetWMFullscreen, NetActiveWindow, NetWMWindowType, - NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -@@ -1537,6 +1537,9 @@ 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); -+ scheme[SchemeUrg].border = drw_clr_create(drw, urgbordercolor); -+ scheme[SchemeUrg].bg = drw_clr_create(drw, selbgcolor); -+ scheme[SchemeUrg].fg = drw_clr_create(drw, selfgcolor); - /* init bars */ - updatebars(); - updatestatus(); -@@ -1982,8 +1985,11 @@ updatewmhints(Client *c) { - wmh->flags &= ~XUrgencyHint; - XSetWMHints(dpy, c->win, wmh); - } -- else -+ else { - c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; -+ if (c->isurgent) -+ XSetWindowBorder(dpy, c->win, scheme[SchemeUrg].border->rgb); -+ } - if(wmh->flags & InputHint) - c->neverfocus = !wmh->input; - else --- -2.1.4 - diff --git a/dwm.suckless.org/patches/dwm-6.1-mark.diff b/dwm.suckless.org/patches/dwm-6.1-mark.diff @@ -0,0 +1,231 @@ +diff -Naur dwm-6.1/config.def.h dwm-6.1-patched/config.def.h +--- dwm-6.1/config.def.h 2015-11-09 06:39:37.000000000 +0800 ++++ dwm-6.1-patched/config.def.h 2016-02-17 16:46:11.137603047 +0800 +@@ -11,6 +11,8 @@ + static const char selbordercolor[] = "#005577"; + static const char selbgcolor[] = "#005577"; + static const char selfgcolor[] = "#eeeeee"; ++static const char normmarkcolor[] = "#775500"; ++static const char selmarkcolor[] = "#775577"; + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ +@@ -68,7 +70,6 @@ + { 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]} }, +@@ -82,6 +83,9 @@ + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY, XK_Return, swapclient, {0} }, ++ { MODKEY, XK_o, swapfocus, {0} }, ++ { MODKEY, XK_semicolon, togglemark, {0} }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +diff -Naur dwm-6.1/drw.h dwm-6.1-patched/drw.h +--- dwm-6.1/drw.h 2015-11-09 06:39:37.000000000 +0800 ++++ dwm-6.1-patched/drw.h 2016-02-17 16:18:47.424219808 +0800 +@@ -23,6 +23,7 @@ + Clr *fg; + Clr *bg; + Clr *border; ++ Clr *mark; + } ClrScheme; + + typedef struct { +diff -Naur dwm-6.1/dwm.c dwm-6.1-patched/dwm.c +--- dwm-6.1/dwm.c 2015-11-09 06:39:37.000000000 +0800 ++++ dwm-6.1-patched/dwm.c 2016-02-17 16:41:55.737595294 +0800 +@@ -201,16 +201,20 @@ + static void setfocus(Client *c); + static void setfullscreen(Client *c, int fullscreen); + static void setlayout(const Arg *arg); ++static void stemark(const Arg *arg); + 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 swapclient(const Arg *arg); ++static void swapfocus(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 togglemark(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); +@@ -266,6 +270,7 @@ + static Drw *drw; + static Monitor *mons, *selmon; + static Window root; ++static Client *mark; + + /* configuration, allows nested code to access above variables */ + #include "config.h" +@@ -482,6 +487,7 @@ + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < SchemeLast; i++) { ++ drw_clr_free(scheme[i].mark); + drw_clr_free(scheme[i].border); + drw_clr_free(scheme[i].bg); + drw_clr_free(scheme[i].fg); +@@ -807,7 +813,12 @@ + detachstack(c); + attachstack(c); + grabbuttons(c, 1); +- XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); ++ if (c == mark) ++ XSetWindowBorder(dpy, c->win, ++ scheme[SchemeSel].mark->pix); ++ else ++ XSetWindowBorder(dpy, c->win, ++ scheme[SchemeSel].border->pix); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1018,6 +1029,8 @@ + { + if (!selmon->sel) + return; ++ if (mark == selmon->sel) ++ setmark(0); + if (!sendevent(selmon->sel, wmatom[WMDelete])) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); +@@ -1065,7 +1078,10 @@ + + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); +- XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix); ++ if (c == mark) ++ XSetWindowBorder(dpy, w, scheme[SchemeNorm].mark->pix); ++ else ++ XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); +@@ -1528,6 +1544,23 @@ + drawbar(selmon); + } + ++void ++setmark(Client *c) ++{ ++ if (c == mark) ++ return; ++ if (mark) { ++ XSetWindowBorder(dpy, mark->win, scheme[mark == selmon->sel ++ ? SchemeSel : SchemeNorm].border->pix); ++ mark = 0; ++ } ++ if (c) { ++ XSetWindowBorder(dpy, c->win, scheme[c == selmon->sel ++ ? SchemeSel : SchemeNorm].mark->pix); ++ mark = c; ++ } ++} ++ + /* arg > 1.0 will set mfact absolutly */ + void + setmfact(const Arg *arg) +@@ -1580,9 +1613,11 @@ + cursor[CurResize] = drw_cur_create(drw, XC_sizing); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ ++ scheme[SchemeNorm].mark = drw_clr_create(drw, normmarkcolor); + scheme[SchemeNorm].border = drw_clr_create(drw, normbordercolor); + scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor); + scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor); ++ scheme[SchemeSel].mark = drw_clr_create(drw, selmarkcolor); + scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); + scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); + scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); +@@ -1646,6 +1681,50 @@ + } + + void ++swapclient(const Arg *arg) ++{ ++ Client *s, *m, t; ++ ++ if (!mark) { ++ zoom(0); ++ return; ++ } ++ s = selmon->sel; ++ m = mark; ++ if (!s || m == s || !selmon->lt[selmon->sellt]->arrange) ++ return; ++ t = *s; ++ strcpy(s->name, m->name); ++ strcpy(m->name, t.name); ++ s->win = m->win; ++ m->win = t.win; ++ XMoveResizeWindow(dpy, s->win, s->x + 2 * sw, s->y, s->w, s->h); ++ arrange(s->mon); ++ XMapWindow(dpy, s->win); ++ XMoveResizeWindow(dpy, m->win, m->x + 2 * sw, m->y, m->w, m->h); ++ arrange(m->mon); ++ XMapWindow(dpy, m->win); ++ ++ selmon->sel = m; ++ mark = s; ++ focus(s); ++ setmark(m); ++} ++ ++void ++swapfocus(const Arg *arg) ++{ ++ Client *t; ++ ++ if (!selmon->sel || !mark || selmon->sel == mark) { ++ return; ++ } ++ t = mark; ++ setmark(selmon->sel); ++ focus(t); ++} ++ ++void + tag(const Arg *arg) + { + if (selmon->sel && arg->ui & TAGMASK) { +@@ -1713,6 +1792,15 @@ + } + + void ++togglemark(const Arg *arg) ++{ ++ if (!selmon->sel) { ++ return; ++ } ++ setmark(selmon->sel == mark ? 0 : selmon->sel); ++} ++ ++void + toggletag(const Arg *arg) + { + unsigned int newtags; +@@ -1745,7 +1833,10 @@ + if (!c) + return; + grabbuttons(c, 0); +- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); ++ if (c == mark) ++ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].mark->pix); ++ else ++ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); diff --git a/dwm.suckless.org/patches/dwm-6.1-pertag-tab-v2b.diff b/dwm.suckless.org/patches/dwm-6.1-pertag-tab-v2b.diff @@ -0,0 +1,841 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..f0b33c5 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,10 +15,21 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 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 +@@ -62,6 +73,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 } }, +@@ -109,5 +121,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..077d92b 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 0362114..887a839 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,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 { +@@ -111,25 +111,35 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ ++typedef struct Pertag Pertag; + 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]; + int showbar; ++ int showtab; + int topbar; ++ int 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 { +@@ -164,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 int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,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 *); +@@ -240,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 +285,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 */ ++ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -393,6 +418,8 @@ 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); +@@ -442,14 +469,33 @@ buttonpress(XEvent *e) + click = ClkStatusText; + else + click = ClkWinTitle; +- } else if ((c = wintoclient(ev->window))) { ++ } ++ 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); ++ 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 || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -469,23 +515,24 @@ cleanup(void) + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; +- size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) +- while (m->stack) +- unmanage(m->stack, 0); ++ while(m->stack) ++ unmanage(m->stack, False); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); +- for (i = 0; i < CurLast; i++) +- drw_cur_free(drw, cursor[i]); +- for (i = 0; i < SchemeLast; i++) { +- drw_clr_free(scheme[i].border); +- drw_clr_free(scheme[i].bg); +- drw_clr_free(scheme[i].fg); +- } ++ drw_cur_free(drw, cursor[CurNormal]); ++ drw_cur_free(drw, cursor[CurResize]); ++ drw_cur_free(drw, cursor[CurMove]); ++ drw_clr_free(scheme[SchemeNorm].border); ++ drw_clr_free(scheme[SchemeNorm].bg); ++ drw_clr_free(scheme[SchemeNorm].fg); ++ drw_clr_free(scheme[SchemeSel].border); ++ drw_clr_free(scheme[SchemeSel].bg); ++ drw_clr_free(scheme[SchemeSel].fg); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); +@@ -505,6 +552,8 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -526,6 +575,7 @@ clientmessage(XEvent *e) + { + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); ++ int i; + + if (!c) + return; +@@ -537,6 +587,8 @@ clientmessage(XEvent *e) + if (!ISVISIBLE(c)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; ++ for(i=0; !(c->tags & 1 << i); i++); ++ view(&(Arg){.ui = 1 << i}); + } + pop(c); + } +@@ -565,6 +617,7 @@ void + configurenotify(XEvent *e) + { + Monitor *m; ++ Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + +@@ -576,8 +629,14 @@ 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){ ++ for (c = m->clients; c; c = c->next) ++ if (c->isfullscreen) ++ resizeclient(c, m->mx, m->my, m->mw, m->mh); + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -640,16 +699,41 @@ Monitor * + createmon(void) + { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; +- m->lt[0] = &layouts[0]; ++ m->toptab = toptab; ++ m->ntabs = 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] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ ++ /* swap focus and zoomswap*/ ++ m->pertag->prevzooms[i] = NULL; ++ } + return m; + } + +@@ -763,6 +847,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, "", 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; +@@ -787,8 +969,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 +@@ -806,7 +990,7 @@ focus(Client *c) + clearurgent(c); + detachstack(c); + attachstack(c); +- grabbuttons(c, 1); ++ grabbuttons(c, True); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); + setfocus(c); + } else { +@@ -815,6 +999,7 @@ focus(Client *c) + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + /* there are some broken focus acquiring clients */ +@@ -868,6 +1053,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) + { +@@ -981,7 +1179,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 +1337,7 @@ motionnotify(XEvent *e) + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { +- unfocus(selmon->sel, 1); ++ unfocus(selmon->sel, True); + selmon = m; + focus(NULL); + } +@@ -1159,11 +1357,13 @@ movemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; ++ if(c->isfullscreen) /* no support moving fullscreen windows by mouse */ ++ return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, +- None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) ++ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; +@@ -1250,12 +1450,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); +@@ -1317,11 +1519,13 @@ resizemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; ++ if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */ ++ return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, +- None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) ++ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + return; + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + do { +@@ -1369,6 +1573,7 @@ restack(Monitor *m) + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1477,11 +1682,11 @@ sendevent(Client *c, Atom proto) + void + setfocus(Client *c) + { +- if (!c->neverfocus) { ++ if(!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], +- XA_WINDOW, 32, PropModeReplace, +- (unsigned char *) &(c->win), 1); ++ XA_WINDOW, 32, PropModeReplace, ++ (unsigned char *) &(c->win), 1); + } + sendevent(c, wmatom[WMTakeFocus]); + } +@@ -1517,10 +1722,13 @@ setfullscreen(Client *c, int 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; ++ 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->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); +@@ -1539,7 +1747,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); + } + +@@ -1559,8 +1767,9 @@ setup(void) + drw = drw_create(dpy, screen, root, sw, sh); + drw_load_fonts(drw, fonts, LENGTH(fonts)); + if (!drw->fontcount) +- die("no fonts could be loaded.\n"); ++ die("No fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1632,10 +1841,10 @@ sigchld(int unused) + void + spawn(const Arg *arg) + { +- if (arg->v == dmenucmd) ++ if(arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; +- if (fork() == 0) { +- if (dpy) ++ if(fork() == 0) { ++ if(dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); +@@ -1692,18 +1901,29 @@ 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) ++ if(!selmon->sel) + return; +- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ ++ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) +@@ -1731,9 +1951,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); + } +@@ -1744,7 +1984,7 @@ unfocus(Client *c, int setfocus) + { + if (!c) + return; +- grabbuttons(c, 0); ++ grabbuttons(c, False); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1809,20 +2049,44 @@ 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 +@@ -2004,9 +2268,9 @@ updatewindowtype(Client *c) + Atom wtype = getatomprop(c, netatom[NetWMWindowType]); + + if (state == netatom[NetWMFullscreen]) +- setfullscreen(c, 1); ++ setfullscreen(c, True); + if (wtype == netatom[NetWMWindowTypeDialog]) +- c->isfloating = 1; ++ c->isfloating = True; + } + + void +@@ -2031,11 +2295,33 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { +- if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) ++ 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); + } +@@ -2063,7 +2349,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-pertag.diff b/dwm.suckless.org/patches/dwm-6.1-pertag.diff @@ -1,15 +1,8 @@ -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. - -Contributors: -- Carlos Pita, thanks for debugging NetActiveWindow issues and sending a patch - -Index: dwm/dwm.c -=================================================================== ---- dwm/dwm.c.orig 2014-02-09 15:24:18.232117136 +0100 -+++ dwm/dwm.c 2014-02-09 15:24:18.224117135 +0100 -@@ -110,6 +110,7 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..9ba4ec5 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -111,6 +111,7 @@ typedef struct { void (*arrange)(Monitor *); } Layout; @@ -17,7 +10,7 @@ Index: dwm/dwm.c struct Monitor { char ltsymbol[16]; float mfact; -@@ -129,6 +130,7 @@ +@@ -130,6 +131,7 @@ struct Monitor { Monitor *next; Window barwin; const Layout *lt[2]; @@ -25,7 +18,7 @@ Index: dwm/dwm.c }; typedef struct { -@@ -270,6 +272,16 @@ +@@ -270,6 +272,16 @@ static Window root; /* configuration, allows nested code to access above variables */ #include "config.h" @@ -42,16 +35,16 @@ Index: dwm/dwm.c /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; -@@ -518,6 +530,7 @@ - clientmessage(XEvent *e) { +@@ -526,6 +538,7 @@ clientmessage(XEvent *e) + { XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); + int i; - if(!c) + if (!c) return; -@@ -530,6 +543,8 @@ - if(!ISVISIBLE(c)) { +@@ -537,6 +550,8 @@ clientmessage(XEvent *e) + if (!ISVISIBLE(c)) { c->mon->seltags ^= 1; c->mon->tagset[c->mon->seltags] = c->tags; + for(i=0; !(c->tags & 1 << i); i++); @@ -59,19 +52,19 @@ Index: dwm/dwm.c } pop(c); } -@@ -631,6 +646,7 @@ - Monitor * - createmon(void) { +@@ -640,6 +655,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)); -@@ -642,6 +658,27 @@ + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; +@@ -650,6 +666,27 @@ 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)))) ++ 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++) { @@ -95,63 +88,63 @@ Index: dwm/dwm.c return m; } -@@ -958,7 +995,7 @@ - +@@ -981,7 +1018,7 @@ grabkeys(void) void - incnmaster(const Arg *arg) { + 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); } -@@ -1462,10 +1499,13 @@ - +@@ -1517,10 +1554,13 @@ setfullscreen(Client *c, int fullscreen) void - setlayout(const Arg *arg) { -- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + 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]) { ++ 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) + 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) + if (selmon->sel) arrange(selmon); -@@ -1483,7 +1523,7 @@ +@@ -1539,7 +1579,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) + if (f < 0.1 || f > 0.9) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } -@@ -1627,7 +1667,7 @@ - +@@ -1692,7 +1732,7 @@ tile(Monitor *m) void - togglebar(const Arg *arg) { + 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); -@@ -1663,9 +1703,29 @@ - void - toggleview(const Arg *arg) { +@@ -1731,9 +1771,29 @@ void + toggleview(const Arg *arg) + { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; - if(newtagset) { -+ if(newtagset == ~0) { + 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))) { ++ 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; @@ -169,21 +162,21 @@ Index: dwm/dwm.c focus(NULL); arrange(selmon); } -@@ -1960,11 +2020,33 @@ - +@@ -2031,11 +2091,33 @@ updatewmhints(Client *c) void - view(const Arg *arg) { + view(const Arg *arg) + { + int i; + unsigned int tmptag; + - if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ -- if(arg->ui & TAGMASK) -+ if(arg->ui & TAGMASK) { +- 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) ++ if (arg->ui == ~0) + selmon->pertag->curtag = 0; + else { + for (i=0; !(arg->ui & 1 << i); i++) ; diff --git a/dwm.suckless.org/patches/dwm-6.1-pertag_without_bar.diff b/dwm.suckless.org/patches/dwm-6.1-pertag_without_bar.diff @@ -0,0 +1,161 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..e44bb24 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -111,6 +111,7 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -130,6 +131,7 @@ struct Monitor { + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -270,6 +272,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]; }; + +@@ -640,6 +650,7 @@ Monitor * + createmon(void) + { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; +@@ -650,6 +661,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; + } + +@@ -981,7 +1007,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); + } + +@@ -1517,10 +1543,13 @@ setfullscreen(Client *c, int 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); +@@ -1539,7 +1568,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); + } + +@@ -1731,9 +1760,27 @@ 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); + } +@@ -2031,11 +2078,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.1-push_no_master.diff b/dwm.suckless.org/patches/dwm-6.1-push_no_master.diff @@ -0,0 +1,70 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..d61d736 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -186,7 +186,10 @@ static void motionnotify(XEvent *e); + static void movemouse(const Arg *arg); + static Client *nexttiled(Client *c); + static void pop(Client *); ++static Client *prevtiled(Client *c); + static void propertynotify(XEvent *e); ++static void pushdown(const Arg *arg); ++static void pushup(const Arg *arg); + static void quit(const Arg *arg); + static Monitor *recttomon(int x, int y, int w, int h); + static void resize(Client *c, int x, int y, int w, int h, int interact); +@@ -1225,6 +1228,16 @@ pop(Client *c) + arrange(c->mon); + } + ++Client * ++prevtiled(Client *c) { ++ Client *p, *r; ++ ++ for(p = selmon->clients, r = NULL; p && p != c; p = p->next) ++ if(!p->isfloating && ISVISIBLE(p)) ++ r = p; ++ return r; ++} ++ + void + propertynotify(XEvent *e) + { +@@ -1263,6 +1276,37 @@ propertynotify(XEvent *e) + } + + void ++pushdown(const Arg *arg) { ++ Client *sel = selmon->sel, *c; ++ ++ if(!sel || sel->isfloating || sel == nexttiled(selmon->clients)) ++ return; ++ if((c = nexttiled(sel->next))) { ++ detach(sel); ++ sel->next = c->next; ++ c->next = sel; ++ } ++ focus(sel); ++ arrange(selmon); ++} ++ ++void ++pushup(const Arg *arg) { ++ Client *sel = selmon->sel, *c; ++ ++ if(!sel || sel->isfloating) ++ return; ++ if((c = prevtiled(sel)) && c != nexttiled(selmon->clients)) { ++ detach(sel); ++ sel->next = c; ++ for(c = selmon->clients; c->next != sel->next; c = c->next); ++ c->next = sel; ++ } ++ focus(sel); ++ arrange(selmon); ++} ++ ++void + quit(const Arg *arg) + { + running = 0; diff --git a/dwm.suckless.org/patches/dwm-6.1-resizecorners.diff b/dwm.suckless.org/patches/dwm-6.1-resizecorners.diff @@ -0,0 +1,68 @@ +diff --git a/dwm.c b/dwm.c +index ff7e096..b6ce27c 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -1313,9 +1313,14 @@ void + resizemouse(const Arg *arg) + { + int ocx, ocy, nw, nh; ++ int ocx2, ocy2, nx, ny; + Client *c; + Monitor *m; + XEvent ev; ++ int horizcorner, vertcorner; ++ int di; ++ unsigned int dui; ++ Window dummy; + Time lasttime = 0; + + if (!(c = selmon->sel)) +@@ -1325,10 +1330,19 @@ resizemouse(const Arg *arg) + restack(selmon); + ocx = c->x; + ocy = c->y; ++ ocx2 = c->x + c->w; ++ ocy2 = c->y + c->h; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + return; +- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); ++ if (!XQueryPointer (dpy, c->win, &dummy, &dummy, &di, &di, &nx, &ny, &dui)) ++ return; ++ horizcorner = nx < c->w / 2; ++ vertcorner = ny < c->h / 2; ++ XWarpPointer (dpy, None, c->win, 0, 0, 0, 0, ++ horizcorner ? (-c->bw) : (c->w + c->bw - 1), ++ vertcorner ? (-c->bw) : (c->h + c->bw - 1)); ++ + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { +@@ -1344,6 +1358,11 @@ resizemouse(const Arg *arg) + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); ++ nx = horizcorner ? ev.xmotion.x : c->x; ++ ny = vertcorner ? ev.xmotion.y : c->y; ++ nw = MAX(horizcorner ? (ocx2 - nx) : (ev.xmotion.x - ocx - 2 * c->bw + 1), 1); ++ nh = MAX(vertcorner ? (ocy2 - ny) : (ev.xmotion.y - ocy - 2 * c->bw + 1), 1); ++ + if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww + && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) + { +@@ -1352,11 +1371,13 @@ resizemouse(const Arg *arg) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) +- resize(c, c->x, c->y, nw, nh, 1); ++ resize(c, nx, ny, nw, nh, 1); + break; + } + } while (ev.type != ButtonRelease); +- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); ++ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, ++ horizcorner ? (-c->bw) : (c->w + c->bw - 1), ++ vertcorner ? (-c->bw) : (c->h + c->bw - 1)); + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { diff --git a/dwm.suckless.org/patches/dwm-6.1-single_window_no_border.diff b/dwm.suckless.org/patches/dwm-6.1-single_window_no_border.diff @@ -3,25 +3,23 @@ URL: http://dwm.suckless.org/patches/noborder This patch removes the border when there is just one window visible in tiled or monocle layout. -Index: dwm/dwm.c -=================================================================== ---- dwm/dwm.c.orig 2014-02-09 15:24:19.404117168 +0100 -+++ dwm/dwm.c 2014-02-09 15:24:19.396117168 +0100 -@@ -1089,7 +1089,7 @@ - +--- dwm/dwm.c.orig 2015-11-11 19:14:39.771079356 -0800 ++++ dwm/dwm.c 2015-11-11 19:14:42.821079144 -0800 +@@ -1117,7 +1117,7 @@ maprequest(XEvent *e) void - monocle(Monitor *m) { + monocle(Monitor *m) + { - unsigned int n = 0; + unsigned int n = 0, r = 0; Client *c; - for(c = m->clients; c; c = c->next) -@@ -1097,8 +1097,17 @@ + for (c = m->clients; c; c = c->next) +@@ -1125,8 +1125,17 @@ monocle(Monitor *m) n++; - if(n > 0) /* override layout symbol */ + if (n > 0) /* override layout symbol */ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); -- for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) -- resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False); +- for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) +- resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); + for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) { + /* remove border when in monocle layout */ + if(c->bw) { @@ -29,31 +27,31 @@ Index: dwm/dwm.c + c->bw = 0; + r = 1; + } -+ resize(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw), False); ++ resize(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw), False); + if(r) -+ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw)); ++ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw)); + } } void -@@ -1601,7 +1610,7 @@ - +@@ -1666,7 +1675,7 @@ tagmon(const Arg *arg) void - tile(Monitor *m) { + tile(Monitor *m) + { - unsigned int i, n, h, mw, my, ty; + unsigned int i, n, h, mw, my, ty, r; Client *c; - for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); -@@ -1612,17 +1621,36 @@ + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); +@@ -1677,16 +1686,35 @@ tile(Monitor *m) mw = m->nmaster ? m->ww * m->mfact : 0; else mw = m->ww; -- for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) -+ for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++, r = 0) { +- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if(n == 1) { + if (c->bw) { -+ /* remove border when only one window is on the current tag */ ++ /* remove border when only one window is on the cu rrent tag */ + c->oldbw = c->bw; + c->bw = 0; + r = 1; @@ -65,16 +63,15 @@ Index: dwm/dwm.c + c->oldbw = 0; + r = 1; + } - if(i < m->nmaster) { + if (i < m->nmaster) { h = (m->wh - my) / (MIN(n, m->nmaster) - i); - resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); + resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); + if(r) + resizeclient(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw)); my += HEIGHT(c); - } - else { + } else { h = (m->wh - ty) / (n - i); - resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False); + resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); + if(r) + resizeclient(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw)); ty += HEIGHT(c); @@ -83,19 +80,19 @@ Index: dwm/dwm.c } void -@@ -1640,9 +1668,15 @@ - if(selmon->sel->isfullscreen) /* no support for fullscreen windows */ +@@ -1706,9 +1734,15 @@ togglefloating(const Arg *arg) + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ return; selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; -- if(selmon->sel->isfloating) -+ if(selmon->sel->isfloating) { +- if (selmon->sel->isfloating) ++ if (selmon->sel->isfloating) { + /* restore border when moving window into floating mode */ + if(!selmon->sel->bw && selmon->sel->oldbw) { + selmon->sel->bw = selmon->sel->oldbw; + selmon->sel->oldbw = 0; + } resize(selmon->sel, selmon->sel->x, selmon->sel->y, - selmon->sel->w, selmon->sel->h, False); + selmon->sel->w, selmon->sel->h, 0); + } arrange(selmon); } diff --git a/dwm.suckless.org/patches/dwm-6.1-statuscolors.diff b/dwm.suckless.org/patches/dwm-6.1-statuscolors.diff @@ -1,100 +1,90 @@ -Only in dwm: config.def.h -diff -up dwm/drw.c dwm_git_colors/drw.c ---- dwm/drw.c 2015-03-24 10:00:33.865796838 -0700 -+++ dwm_git_colors/drw.c 2015-03-24 09:56:59.542647284 -0700 -@@ -202,13 +202,38 @@ drw_setscheme(Drw *drw, ClrScheme *schem - drw->scheme = scheme; +diff -up dwm/drw.c dwm-statuscolors/drw.c +--- dwm/drw.c 2015-11-08 15:39:37.000000000 -0700 ++++ dwm-statuscolors/drw.c 2015-11-28 15:42:28.534399525 -0700 +@@ -206,6 +206,68 @@ drw_setscheme(Drw *drw, ClrScheme *schem + drw->scheme = scheme; } +int -+drw_colored_text(Drw *drw, ClrScheme *scheme, int numcolors, int x, int y, unsigned int w, unsigned int h, char *text) { -+ if(!drw || !drw->fontcount || !drw->scheme) -+ return 0; ++drw_get_width(Drw *drw, int numcolors, const char *text) ++{ ++ int i; ++ Fnt *curfont = drw->fonts[0]; ++ int w = drw_text(drw, 0, 0, 0, 0, text, 0) + curfont->h; ++ ++ for (i = 0; i < strlen(text); i++) { ++ if (text[i] > 0 && text[i] <= numcolors) { ++ /* we found a color code ++ * drw_text counted it as a normal character and added one character's width ++ * we aren't going to render this character, so we remove one character's width */ ++ w -= curfont->xfont->max_advance_width; ++ ++ if (i == 0 || i + 1 == strlen(text)) { ++ /* we're on the first or the last character of the string ++ * drw_text already added one character's height (divided by 2) as padding to the beginning and end ++ * we don't want to double this padding, so we skip this character */ ++ continue; ++ } ++ ++ if (text[i - 1] > 0 && text[i - 1] <= numcolors) { ++ /* the previous character was also a color code ++ * we already added padding in the previous iteration ++ * we don't want to double this padding, so we skip this character */ ++ continue; ++ } ++ ++ /* we are somewhere in the middle of the string and the color has changed ++ * we want to add one character's height (divided by 2) as padding to the end of the previous colored text ++ * and to the beginning of the new colored text */ ++ w += curfont->h; ++ } ++ } ++ ++ return w; ++} + -+ char *buf = text, *ptr = buf, c =1; ++void ++drw_colored_text(Drw *drw, ClrScheme *scheme, int numcolors, int x, int y, unsigned int w, unsigned int h, char *text) ++{ ++ if (!drw || !drw->fontcount || !drw->scheme) ++ return; ++ ++ char *buf = text, *ptr = buf, c = 1; + int i; + -+ while(*ptr) { -+ for(i = 0; *ptr < 0 || *ptr > numcolors; i++, ptr++); -+ if(!*ptr) ++ while (*ptr) { ++ for (i = 0; *ptr < 0 || *ptr > numcolors; i++, ptr++); ++ if (!*ptr) + break; + c = *ptr; + *ptr = 0; -+ if(i) { -+ x = drw_text(drw, x, y, w, h, buf, 0); -+ } ++ if (i) ++ x = drw_text(drw, x, y, w, h, buf, 0) + drw->fonts[0]->h; + *ptr = c; + drw_setscheme(drw, &scheme[c-1]); + buf = ++ptr; + } + drw_text(drw, x, y, w, h, buf, 0); -+ return x; +} + void --drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) { -+drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty) { - int dx; - - if(!drw || !drw->fontcount || !drw->scheme) - return; -- XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix); -+ XSetForeground(drw->dpy, drw->gc, drw->scheme->fg->pix); - dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; - if(filled) - XFillRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx+1, dx+1); -@@ -217,7 +242,7 @@ drw_rect(Drw *drw, int x, int y, unsigne - } - - int --drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert) { -+drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int pad) { - char buf[1024]; - int tx, ty, th; - Extnts tex; -@@ -242,7 +267,7 @@ drw_text(Drw *drw, int x, int y, unsigne - if (!drw || !drw->scheme) { - return 0; - } else if (render) { -- XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->fg->pix : drw->scheme->bg->pix); -+ XSetForeground(drw->dpy, drw->gc, drw->scheme->bg->pix); - XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); - } - -@@ -294,10 +319,10 @@ drw_text(Drw *drw, int x, int y, unsigne - for(i = len; i && i > len - 3; buf[--i] = '.'); - - if (render) { -- th = curfont->ascent + curfont->descent; -- ty = y + (h / 2) - (th / 2) + curfont->ascent; -+ th = pad ? (curfont->ascent + curfont->descent) : 0; -+ ty = y + ((h + curfont->ascent - curfont->descent) / 2); - tx = x + (h / 2); -- XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); -+ XftDrawStringUtf8(d, &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); - } - - x += tex.w; -diff -up dwm/drw.h dwm_git_colors/drw.h ---- dwm/drw.h 2015-03-24 10:00:33.865796838 -0700 -+++ dwm_git_colors/drw.h 2015-03-24 09:22:03.216317586 -0700 -@@ -67,8 +67,9 @@ void drw_setfont(Drw *drw, Fnt *font); - void drw_setscheme(Drw *drw, ClrScheme *scheme); + drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) + { +diff -up dwm/drw.h dwm-statuscolors/drw.h +--- dwm/drw.h 2015-11-08 15:39:37.000000000 -0700 ++++ dwm-statuscolors/drw.h 2015-11-28 15:39:44.427726312 -0700 +@@ -67,6 +67,8 @@ void drw_setfont(Drw *, Fnt *); + void drw_setscheme(Drw *, ClrScheme *); /* Drawing functions */ --void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert); --int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert); -+int drw_colored_text(Drw *drw, ClrScheme *scheme, int numcolors, int x, int y, unsigned int w, unsigned int h, char *text); -+void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty); -+int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int pad); ++int drw_get_width(Drw *, int, const char *); ++void drw_colored_text(Drw *, ClrScheme *, int, int, int, unsigned int, unsigned int, char *); + void drw_rect(Drw *, int, int, unsigned int, unsigned int, int, int, int); + int drw_text(Drw *, int, int, unsigned int, unsigned int, const char *, int); - /* Map functions */ - void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); -Binary files dwm/drw.o and dwm_git_colors/drw.o differ -Binary files dwm/dwm and dwm_git_colors/dwm differ -diff -up dwm/dwm.c dwm_git_colors/dwm.c ---- dwm/dwm.c 2015-03-24 10:02:59.752217939 -0700 -+++ dwm_git_colors/dwm.c 2015-03-24 09:23:22.826334134 -0700 +diff -up dwm/dwm.c dwm-statuscolors/dwm.c +--- dwm/dwm.c 2015-11-08 15:39:37.000000000 -0700 ++++ dwm-statuscolors/dwm.c 2015-11-28 15:45:32.134406853 -0700 @@ -51,6 +51,7 @@ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) @@ -103,26 +93,26 @@ diff -up dwm/dwm.c dwm_git_colors/dwm.c #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw) -@@ -261,7 +263,7 @@ static void (*handler[LASTEvent]) (XEven +@@ -261,7 +262,7 @@ static void (*handler[LASTEvent]) (XEven static Atom wmatom[WMLast], netatom[NetLast]; - static Bool running = True; + static int running = 1; static Cur *cursor[CurLast]; -static ClrScheme scheme[SchemeLast]; +static ClrScheme scheme[MAXCOLORS]; static Display *dpy; static Drw *drw; static Monitor *mons, *selmon; -@@ -703,14 +716,14 @@ drawbar(Monitor *m) { +@@ -718,35 +719,35 @@ drawbar(Monitor *m) x = 0; - for(i = 0; i < LENGTH(tags); i++) { + for (i = 0; i < LENGTH(tags); i++) { 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_setscheme(drw, &scheme[(m->tagset[m->seltags] & 1 << i) ? 1 : (urg & 1 << i ? 2:0)]); -+ drw_text(drw, x, 0, w, bh, tags[i], 1); - drw_rect(drw, x, 0, w, bh, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, ++ drw_setscheme(drw, &scheme[(m->tagset[m->seltags] & 1 << i) ? 1 : (urg & 1 << i ? 2 : 0)]); ++ drw_text(drw, x, 0, w, bh, tags[i], 0); + drw_rect(drw, x + 1, 1, dx, dx, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - occ & 1 << i, urg & 1 << i); -+ occ & 1 << i); ++ occ & 1 << i, 0); x += w; } w = blw = TEXTW(m->ltsymbol); @@ -131,41 +121,41 @@ diff -up dwm/dwm.c dwm_git_colors/dwm.c drw_text(drw, x, 0, w, bh, m->ltsymbol, 0); x += w; xx = x; -@@ -721,19 +734,19 @@ drawbar(Monitor *m) { + if (m == selmon) { /* status is only drawn on selected monitor */ +- w = TEXTW(stext); ++ w = drw_get_width(drw, NUMCOLORS, stext); + x = m->ww - w; + if (x < xx) { x = xx; w = m->ww - xx; } - drw_text(drw, x, 0, w, bh, stext, 0); + drw_colored_text(drw, scheme, NUMCOLORS, x, 0, w, bh, stext); - } - else + } else x = m->ww; - if((w = x - xx) > bh) { + if ((w = x - xx) > bh) { x = xx; - if(m->sel) { + 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); + drw_setscheme(drw, &scheme[m == selmon ? 1 : 0]); -+ drw_text(drw, x, 0, w, bh, m->sel->name, 1); -+ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating); - } - else { + drw_text(drw, x, 0, w, bh, m->sel->name, 0); + drw_rect(drw, x + 1, 1, dx, dx, m->sel->isfixed, m->sel->isfloating, 0); + } else { - drw_setscheme(drw, &scheme[SchemeNorm]); + drw_setscheme(drw, &scheme[0]); - drw_text(drw, x, 0, w, bh, NULL, 0); + drw_rect(drw, x, 0, w, bh, 1, 0, 1); } } -@@ -791,7 +804,7 @@ focus(Client *c) { +@@ -807,7 +808,7 @@ focus(Client *c) detachstack(c); attachstack(c); - grabbuttons(c, True); + grabbuttons(c, 1); - XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); + XSetWindowBorder(dpy, c->win, scheme[1].border->pix); setfocus(c); - } - else { -@@ -1039,7 +1052,7 @@ manage(Window w, XWindowAttributes *wa) + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1065,7 +1066,7 @@ manage(Window w, XWindowAttributes *wa) wc.border_width = c->bw; XConfigureWindow(dpy, w, CWBorderWidth, &wc); @@ -174,7 +164,7 @@ diff -up dwm/dwm.c dwm_git_colors/dwm.c configure(c); /* propagates border_width, if size doesn't change */ updatewindowtype(c); updatesizehints(c); -@@ -1531,12 +1544,12 @@ setup(void) { +@@ -1580,12 +1581,12 @@ setup(void) cursor[CurResize] = drw_cur_create(drw, XC_sizing); cursor[CurMove] = drw_cur_create(drw, XC_fleur); /* init appearance */ @@ -193,14 +183,12 @@ diff -up dwm/dwm.c dwm_git_colors/dwm.c /* init bars */ updatebars(); updatestatus(); -@@ -1685,7 +1698,7 @@ unfocus(Client *c, Bool setfocus) { - if(!c) +@@ -1745,7 +1746,7 @@ unfocus(Client *c, int setfocus) + if (!c) return; - grabbuttons(c, False); + grabbuttons(c, 0); - XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + XSetWindowBorder(dpy, c->win, scheme[0].border->pix); - if(setfocus) { + if (setfocus) { XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XDeleteProperty(dpy, root, netatom[NetActiveWindow]); -Binary files dwm/dwm.o and dwm_git_colors/dwm.o differ -Common subdirectories: dwm/.git and dwm_git_colors/.git diff --git a/dwm.suckless.org/patches/dwm-6.1-swallowing.diff b/dwm.suckless.org/patches/dwm-6.1-swallowing.diff @@ -0,0 +1,377 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..d1140ff 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -24,9 +24,10 @@ static const Rule rules[] = { + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ +- /* class instance title tags mask isfloating monitor */ +- { "Gimp", NULL, NULL, 0, 1, -1 }, +- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ /* class instance title tags mask isfloating isterminal noswallow monitor */ ++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, ++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, -1 }, ++ { "st-", NULL, NULL, 0, 0, 1, 1, -1 }, + }; + + /* layout(s) */ +diff --git a/dwm.c b/dwm.c +index ff7e096..b50436a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -40,6 +40,10 @@ + #include <X11/extensions/Xinerama.h> + #endif /* XINERAMA */ + #include <X11/Xft/Xft.h> ++#ifdef SWALLOWING ++#include <X11/Xlib-xcb.h> ++#include <xcb/res.h> ++#endif + + #include "drw.h" + #include "util.h" +@@ -92,9 +96,11 @@ struct Client { + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; +- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; ++ pid_t pid; + Client *next; + Client *snext; ++ Client *swallowing; + Monitor *mon; + Window win; + }; +@@ -138,6 +144,8 @@ typedef struct { + const char *title; + unsigned int tags; + int isfloating; ++ int isterminal; ++ int noswallow; + int monitor; + } Rule; + +@@ -170,12 +178,14 @@ static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static pid_t getparentprocess(pid_t p); + static int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); + static void incnmaster(const Arg *arg); ++static int isdescprocess(pid_t p, pid_t c); + static void keypress(XEvent *e); + static void killclient(const Arg *arg); + static void manage(Window w, XWindowAttributes *wa); +@@ -206,8 +216,10 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static Client *swallowingclient(Window w); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); ++static Client *termforwin(const Client *c); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); +@@ -227,6 +239,7 @@ static void updatewindowtype(Client *c); + static void updatetitle(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); ++static pid_t winpid(Window w); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); +@@ -267,6 +280,10 @@ static Drw *drw; + static Monitor *mons, *selmon; + static Window root; + ++#ifdef SWALLOWING ++static xcb_connection_t *xcon; ++#endif /* SWALLOWING */ ++ + /* configuration, allows nested code to access above variables */ + #include "config.h" + +@@ -296,6 +313,7 @@ applyrules(Client *c) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { ++ c->isterminal = r->isterminal; + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); +@@ -413,6 +431,46 @@ attachstack(Client *c) + } + + void ++swallow(Client *p, Client *c) ++{ ++ if (c->noswallow || c->isterminal) ++ return; ++ ++ detach(c); ++ detachstack(c); ++ ++ setclientstate(c, WithdrawnState); ++ XUnmapWindow(dpy, p->win); ++ ++ p->swallowing = c; ++ c->mon = p->mon; ++ ++ Window w = p->win; ++ p->win = c->win; ++ c->win = w; ++ updatetitle(p); ++ arrange(p->mon); ++ configure(p); ++ updateclientlist(); ++} ++ ++void ++unswallow(Client *c) ++{ ++ c->win = c->swallowing->win; ++ ++ free(c->swallowing); ++ c->swallowing = NULL; ++ ++ updatetitle(c); ++ arrange(c->mon); ++ XMapWindow(dpy, c->win); ++ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); ++ configure(c); ++ setclientstate(c, NormalState); ++} ++ ++void + buttonpress(XEvent *e) + { + unsigned int i, x, click; +@@ -475,7 +533,7 @@ cleanup(void) + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) +- unmanage(m->stack, 0); ++ unmanage(m->stack, 0); // XXX - unmanage swallowing windows too + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); +@@ -666,6 +724,9 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ ++ else if ((c = swallowingclient(ev->window))) ++ unmanage(c->swallowing, 1); + } + + void +@@ -1037,12 +1098,13 @@ killclient(const Arg *arg) + void + manage(Window w, XWindowAttributes *wa) + { +- Client *c, *t = NULL; ++ Client *c, *t, *term = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; ++ c->pid = winpid(w); + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; +@@ -1050,7 +1112,9 @@ manage(Window w, XWindowAttributes *wa) + } else { + c->mon = selmon; + applyrules(c); ++ term = termforwin(c); + } ++ + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; +@@ -1092,6 +1156,8 @@ manage(Window w, XWindowAttributes *wa) + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); ++ if (term) ++ swallow(term, c); + focus(NULL); + } + +@@ -1763,6 +1829,20 @@ unmanage(Client *c, int destroyed) + Monitor *m = c->mon; + XWindowChanges wc; + ++ if (c->swallowing) { ++ unswallow(c); ++ return; ++ } ++ ++ Client *s = swallowingclient(c->win); ++ if (s) { ++ free(s->swallowing); ++ s->swallowing = NULL; ++ arrange(m); ++ focus(NULL); ++ return; ++ } ++ + /* The server grab construct avoids race conditions. */ + detach(c); + detachstack(c); +@@ -1778,9 +1858,12 @@ unmanage(Client *c, int destroyed) + XUngrabServer(dpy); + } + free(c); +- focus(NULL); +- updateclientlist(); +- arrange(m); ++ ++ if (!s) { ++ arrange(m); ++ focus(NULL); ++ updateclientlist(); ++ } + } + + void +@@ -2045,16 +2128,118 @@ view(const Arg *arg) + arrange(selmon); + } + ++pid_t ++winpid(Window w) ++{ ++ pid_t result = 0; ++ ++#ifdef SWALLOWING ++ xcb_res_client_id_spec_t spec = {0}; ++ spec.client = w; ++ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; ++ ++ xcb_generic_error_t *e = NULL; ++ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); ++ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); ++ ++ if (!r) ++ return (pid_t)0; ++ ++ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); ++ for (; i.rem; xcb_res_client_id_value_next(&i)) { ++ spec = i.data->spec; ++ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { ++ uint32_t *t = xcb_res_client_id_value_value(i.data); ++ result = *t; ++ break; ++ } ++ } ++ ++ free(r); ++#endif /* SWALLOWING */ ++ ++ if (result == (pid_t)-1) ++ result = 0; ++ return result; ++} ++ ++pid_t ++getparentprocess(pid_t p) ++{ ++ unsigned int v = 0; ++ ++#ifdef __linux__ ++ FILE *f; ++ char buf[256]; ++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); ++ ++ if (!(f = fopen(buf, "r"))) ++ return 0; ++ ++ fscanf(f, "%*u %*s %*c %u", &v); ++ fclose(f); ++#endif /* __linux__ */ ++ ++ return (pid_t)v; ++} ++ ++int ++isdescprocess(pid_t p, pid_t c) ++{ ++ while (p != c && c != 0) ++ c = getparentprocess(c); ++ ++ return (int)c; ++} ++ ++Client * ++termforwin(const Client *w) ++{ ++ Client *c; ++ Monitor *m; ++ ++ if (!w->pid || w->isterminal) ++ return NULL; ++ ++ for (m = mons; m; m = m->next) { ++ for (c = m->clients; c; c = c->next) { ++ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) ++ return c; ++ } ++ } ++ ++ return NULL; ++} ++ ++Client * ++swallowingclient(Window w) ++{ ++ Client *c; ++ Monitor *m; ++ ++ for (m = mons; m; m = m->next) { ++ for (c = m->clients; c; c = c->next) { ++ if (c->swallowing && c->swallowing->win == w) ++ return c; ++ } ++ } ++ ++ return NULL; ++} ++ + Client * + wintoclient(Window w) + { + Client *c; + Monitor *m; + +- for (m = mons; m; m = m->next) +- for (c = m->clients; c; c = c->next) ++ for (m = mons; m; m = m->next) { ++ for (c = m->clients; c; c = c->next) { + if (c->win == w) + return c; ++ } ++ } ++ + return NULL; + } + +@@ -2136,6 +2321,10 @@ main(int argc, char *argv[]) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display\n"); ++#ifdef SWALLOWING ++ if (!(xcon = XGetXCBConnection(dpy))) ++ die("dwm: cannot get xcb connection\n"); ++#endif + checkotherwm(); + setup(); + scan(); diff --git a/dwm.suckless.org/patches/dwm-6.1-systray.diff b/dwm.suckless.org/patches/dwm-6.1-systray.diff @@ -1,33 +1,25 @@ -Author: Jan Christoph Ebersbach <jceb@e-jc.de>, inspired by http://code.google.com/p/dwm-plus -URL: http://dwm.suckless.org/patches/systray -Implements a system tray for dwm. - -Contributors: -- Carlos Pita, thanks for investigating multi monitor issues and sending in a - patch - -Index: dwm/config.def.h -=================================================================== ---- dwm/config.def.h.orig -+++ dwm/config.def.h -@@ -10,6 +10,10 @@ static const char selbgcolor[] = "# +diff --git a/config.def.h b/config.def.h +index 7054c06..8393a58 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,10 @@ static const char selbgcolor[] = "#005577"; static const char selfgcolor[] = "#eeeeee"; static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +static const unsigned int systrayspacing = 2; /* systray spacing */ -+static const Bool systraypinningfailfirst = True; /* True: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ -+static const Bool showsystray = True; /* False means no systray */ - static const Bool showbar = True; /* False means no bar */ - static const Bool topbar = True; /* False means bottom bar */ ++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, 0: display systray on the last monitor*/ ++static const int showsystray = 1; /* 0 means no systray */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ -Index: dwm/dwm.c -=================================================================== ---- dwm/dwm.c.orig -+++ dwm/dwm.c -@@ -56,12 +56,30 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..e574573 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -57,12 +57,30 @@ #define TAGMASK ((1 << LENGTH(tags)) - 1) - #define TEXTW(X) (drw_font_getexts_width(drw->font, X, strlen(X)) + drw->font->h) + #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 @@ -59,7 +51,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 @@ typedef struct { +@@ -141,6 +159,12 @@ typedef struct { int monitor; } Rule; @@ -71,24 +63,24 @@ 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 @@ static void focus(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +@@ -170,8 +194,10 @@ static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); +static Atom getatomprop(Client *c, Atom prop); - static Bool getrootptr(int *x, int *y); + static int getrootptr(int *x, int *y); static long getstate(Window w); +static unsigned int getsystraywidth(); - static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); - static void grabbuttons(Client *c, Bool focused); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); static void grabkeys(void); -@@ -188,13 +214,16 @@ static void pop(Client *); +@@ -189,13 +215,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); +static void removesystrayicon(Client *i); - static void resize(Client *c, int x, int y, int w, int h, Bool interact); + static void resize(Client *c, int x, int y, int w, int h, int interact); +static void resizebarwin(Monitor *m); static void resizeclient(Client *c, int x, int y, int w, int h); static void resizemouse(const Arg *arg); @@ -96,12 +88,12 @@ Index: dwm/dwm.c static void restack(Monitor *m); static void run(void); static void scan(void); --static Bool sendevent(Client *c, Atom proto); -+static Bool sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); +-static int sendevent(Client *c, Atom proto); ++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); -@@ -205,6 +234,7 @@ static void setup(void); +@@ -206,6 +235,7 @@ static void setup(void); static void showhide(Client *c); static void sigchld(int unused); static void spawn(const Arg *arg); @@ -109,7 +101,7 @@ Index: dwm/dwm.c static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); -@@ -222,18 +252,24 @@ static void updateclientlist(void); +@@ -223,18 +253,24 @@ static void updateclientlist(void); static void updatenumlockmask(void); static void updatesizehints(Client *c); static void updatestatus(void); @@ -134,7 +126,7 @@ Index: dwm/dwm.c static const char broken[] = "broken"; static char stext[256]; static int screen; -@@ -255,9 +291,10 @@ static void (*handler[LASTEvent]) (XEven +@@ -256,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { [MapRequest] = maprequest, [MotionNotify] = motionnotify, [PropertyNotify] = propertynotify, @@ -143,34 +135,34 @@ Index: dwm/dwm.c }; -static Atom wmatom[WMLast], netatom[NetLast]; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; - static Bool running = True; + static int running = 1; static Cur *cursor[CurLast]; static ClrScheme scheme[SchemeLast]; -@@ -471,6 +508,11 @@ cleanup(void) { +@@ -479,6 +516,11 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); - while(mons) + while (mons) cleanupmon(mons); -+ if(showsystray) { ++ if (showsystray) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + free(systray); + } - drw_cur_free(drw, cursor[CurNormal]); - drw_cur_free(drw, cursor[CurResize]); - drw_cur_free(drw, cursor[CurMove]); -@@ -516,9 +558,49 @@ clearurgent(Client *c) { - + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < SchemeLast; i++) { +@@ -524,9 +566,50 @@ clearurgent(Client *c) void - clientmessage(XEvent *e) { + clientmessage(XEvent *e) + { + XWindowAttributes wa; + XSetWindowAttributes swa; XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); -+ if(showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { ++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { + /* add systray icons */ -+ if(cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { -+ if(!(c = (Client *)calloc(1, sizeof(Client)))) ++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { ++ if (!(c = (Client *)calloc(1, sizeof(Client)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Client)); + c->win = cme->data.l[2]; + c->mon = selmon; @@ -191,7 +183,7 @@ Index: dwm/dwm.c + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + XReparentWindow(dpy, c->win, systray->win, 0, 0); + /* use parents background color */ -+ swa.background_pixel = scheme[SchemeNorm].bg->rgb; ++ swa.background_pixel = scheme[SchemeNorm].bg->pix; + XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + /* FIXME not sure if I have to send these events, too */ @@ -205,23 +197,24 @@ Index: dwm/dwm.c + } + return; + } - if(!c) ++ + if (!c) return; - if(cme->message_type == netatom[NetWMState]) { -@@ -568,7 +650,7 @@ configurenotify(XEvent *e) { + if (cme->message_type == netatom[NetWMState]) { +@@ -577,7 +660,7 @@ configurenotify(XEvent *e) drw_resize(drw, sw, bh); 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); + resizebarwin(m); focus(NULL); arrange(NULL); } -@@ -652,6 +734,11 @@ destroynotify(XEvent *e) { +@@ -661,6 +744,11 @@ destroynotify(XEvent *e) - if((c = wintoclient(ev->window))) - unmanage(c, True); -+ else if((c = wintosystrayicon(ev->window))) { + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); @@ -229,65 +222,65 @@ Index: dwm/dwm.c } void -@@ -696,6 +783,7 @@ drawbar(Monitor *m) { - unsigned int i, occ = 0, urg = 0; - Client *c; +@@ -710,6 +798,7 @@ drawbar(Monitor *m) + + dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; + resizebarwin(m); - for(c = m->clients; c; c = c->next) { + for (c = m->clients; c; c = c->next) { occ |= c->tags; - if(c->isurgent) -@@ -718,6 +806,9 @@ drawbar(Monitor *m) { - if(m == selmon) { /* status is only drawn on selected monitor */ + if (c->isurgent) +@@ -732,6 +821,9 @@ drawbar(Monitor *m) + if (m == selmon) { /* status is only drawn on selected monitor */ w = TEXTW(stext); x = m->ww - w; -+ if(showsystray && m == systraytomon(m)) { ++ if (showsystray && m == systraytomon(m)) { + x -= getsystraywidth(); + } - if(x < xx) { + if (x < xx) { x = xx; w = m->ww - xx; -@@ -747,6 +838,7 @@ drawbars(void) { +@@ -760,6 +852,7 @@ drawbars(void) - for(m = mons; m; m = m->next) + for (m = mons; m; m = m->next) drawbar(m); + updatesystray(); } void -@@ -773,8 +865,11 @@ expose(XEvent *e) { +@@ -787,8 +880,11 @@ 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))) { +- if (ev->count == 0 && (m = wintomon(ev->window))) ++ if (ev->count == 0 && (m = wintomon(ev->window))) { drawbar(m); -+ if(m == selmon) ++ if (m == selmon) + updatesystray(); + } } void -@@ -857,10 +952,17 @@ getatomprop(Client *c, Atom prop) { +@@ -875,10 +971,17 @@ getatomprop(Client *c, Atom prop) unsigned long dl; unsigned char *p = NULL; Atom da, atom = None; + /* FIXME getatomprop should return the number of items and a pointer to + * the stored data instead of this workaround */ + Atom req = XA_ATOM; -+ if(prop == xatom[XembedInfo]) ++ if (prop == xatom[XembedInfo]) + req = xatom[XembedInfo]; -- if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, -+ if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, +- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, ++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, &da, &di, &dl, &dl, &p) == Success && p) { atom = *(Atom *)p; -+ if(da == xatom[XembedInfo] && dl == 2) ++ if (da == xatom[XembedInfo] && dl == 2) + atom = ((Atom *)p)[1]; XFree(p); } return atom; -@@ -892,6 +994,15 @@ getstate(Window w) { +@@ -912,6 +1015,15 @@ getstate(Window w) return result; } @@ -295,42 +288,42 @@ Index: dwm/dwm.c +getsystraywidth() { + unsigned int w = 0; + Client *i; -+ if(showsystray) -+ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; ++ if (showsystray) ++ for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next); + return w ? w + systrayspacing : 1; +} + - Bool - gettextprop(Window w, Atom atom, char *text, unsigned int size) { - char **list = NULL; -@@ -992,7 +1103,7 @@ void - killclient(const Arg *arg) { - if(!selmon->sel) + int + gettextprop(Window w, Atom atom, char *text, unsigned int size) + { +@@ -1018,7 +1130,7 @@ killclient(const Arg *arg) + { + if (!selmon->sel) return; -- if(!sendevent(selmon->sel, wmatom[WMDelete])) { -+ if(!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { +- if (!sendevent(selmon->sel, wmatom[WMDelete])) { ++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { XGrabServer(dpy); XSetErrorHandler(xerrordummy); XSetCloseDownMode(dpy, DestroyAll); -@@ -1078,6 +1189,12 @@ void - maprequest(XEvent *e) { +@@ -1105,6 +1217,12 @@ maprequest(XEvent *e) + { static XWindowAttributes wa; XMapRequestEvent *ev = &e->xmaprequest; + Client *i; -+ if((i = wintosystrayicon(ev->window))) { ++ if ((i = wintosystrayicon(ev->window))) { + sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); + resizebarwin(selmon); + updatesystray(); + } - if(!XGetWindowAttributes(dpy, ev->window, &wa)) + if (!XGetWindowAttributes(dpy, ev->window, &wa)) return; -@@ -1194,6 +1311,16 @@ propertynotify(XEvent *e) { +@@ -1232,6 +1350,16 @@ propertynotify(XEvent *e) Window trans; XPropertyEvent *ev = &e->xproperty; -+ if((c = wintosystrayicon(ev->window))) { -+ if(ev->atom == XA_WM_NORMAL_HINTS) { ++ if ((c = wintosystrayicon(ev->window))) { ++ if (ev->atom == XA_WM_NORMAL_HINTS) { + updatesizehints(c); + updatesystrayicongeom(c, c->w, c->h); + } @@ -339,44 +332,45 @@ Index: dwm/dwm.c + resizebarwin(selmon); + updatesystray(); + } - if((ev->window == root) && (ev->atom == XA_WM_NAME)) + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) updatestatus(); - else if(ev->state == PropertyDelete) -@@ -1243,12 +1370,33 @@ recttomon(int x, int y, int w, int h) { + else if (ev->state == PropertyDelete) +@@ -1283,6 +1411,19 @@ recttomon(int x, int y, int w, int h) } void +removesystrayicon(Client *i) { + Client **ii; + -+ if(!showsystray || !i) ++ if (!showsystray || !i) + return; -+ for(ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); -+ if(ii) ++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); ++ if (ii) + *ii = i->next; + free(i); +} + + +void - resize(Client *c, int x, int y, int w, int h, Bool interact) { - if(applysizehints(c, &x, &y, &w, &h, interact)) - resizeclient(c, x, y, w, h); + resize(Client *c, int x, int y, int w, int h, int interact) + { + if (applysizehints(c, &x, &y, &w, &h, interact)) +@@ -1290,6 +1431,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) } void +resizebarwin(Monitor *m) { + unsigned int w = m->ww; -+ if(showsystray && m == systraytomon(m)) ++ if (showsystray && m == systraytomon(m)) + w -= getsystraywidth(); + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); +} + +void - resizeclient(Client *c, int x, int y, int w, int h) { + resizeclient(Client *c, int x, int y, int w, int h) + { XWindowChanges wc; - -@@ -1315,6 +1463,18 @@ resizemouse(const Arg *arg) { +@@ -1362,6 +1511,18 @@ resizemouse(const Arg *arg) } void @@ -384,7 +378,7 @@ Index: dwm/dwm.c + XResizeRequestEvent *ev = &e->xresizerequest; + Client *i; + -+ if((i = wintosystrayicon(ev->window))) { ++ if ((i = wintosystrayicon(ev->window))) { + updatesystrayicongeom(i, ev->width, ev->height); + resizebarwin(selmon); + updatesystray(); @@ -392,28 +386,29 @@ Index: dwm/dwm.c +} + +void - restack(Monitor *m) { + restack(Monitor *m) + { Client *c; - XEvent ev; -@@ -1398,25 +1558,35 @@ setclientstate(Client *c, long state) { +@@ -1450,26 +1611,36 @@ setclientstate(Client *c, long state) } - Bool --sendevent(Client *c, Atom proto) { -+sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) { + int +-sendevent(Client *c, Atom proto) ++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) + { int n; - Atom *protocols; + Atom *protocols, mt; - Bool exists = False; + int exists = 0; XEvent ev; -- if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { -- while(!exists && n--) +- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { +- while (!exists && n--) - exists = protocols[n] == proto; - XFree(protocols); -+ if(proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { ++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { + mt = wmatom[WMProtocols]; -+ if(XGetWMProtocols(dpy, w, &protocols, &n)) { ++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { + while(!exists && n--) + exists = protocols[n] == proto; + XFree(protocols); @@ -423,7 +418,7 @@ Index: dwm/dwm.c + exists = True; + mt = proto; } - if(exists) { + if (exists) { ev.type = ClientMessage; - ev.xclient.window = c->win; - ev.xclient.message_type = wmatom[WMProtocols]; @@ -442,16 +437,16 @@ Index: dwm/dwm.c } return exists; } -@@ -1429,7 +1599,7 @@ setfocus(Client *c) { - XA_WINDOW, 32, PropModeReplace, - (unsigned char *) &(c->win), 1); +@@ -1483,7 +1654,7 @@ setfocus(Client *c) + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); } - sendevent(c, wmatom[WMTakeFocus]); + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); } void -@@ -1511,12 +1681,18 @@ setup(void) { +@@ -1569,12 +1740,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); @@ -470,7 +465,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 +1704,8 @@ setup(void) { +@@ -1586,6 +1763,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); @@ -479,7 +474,7 @@ Index: dwm/dwm.c /* init bars */ updatebars(); updatestatus(); -@@ -1583,6 +1761,22 @@ spawn(const Arg *arg) { +@@ -1645,6 +1824,22 @@ spawn(const Arg *arg) } } @@ -487,34 +482,34 @@ Index: dwm/dwm.c +systraytomon(Monitor *m) { + Monitor *t; + int i, n; -+ if(!systraypinning) { -+ if(!m) ++ if (!systraypinning) { ++ if (!m) + return selmon; + return m == selmon ? m : NULL; + } -+ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; -+ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; -+ if(systraypinningfailfirst && n < systraypinning) ++ for (n = 1, t = mons; t && t->next; n++, t = t->next); ++ for (i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next); ++ if (systraypinningfailfirst && n < systraypinning) + return mons; + return t; +} + void - tag(const Arg *arg) { - if(selmon->sel && arg->ui & TAGMASK) { -@@ -1629,7 +1823,18 @@ void - togglebar(const Arg *arg) { + tag(const Arg *arg) + { +@@ -1694,7 +1889,18 @@ togglebar(const Arg *arg) + { selmon->showbar = !selmon->showbar; updatebarpos(selmon); - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + resizebarwin(selmon); -+ if(showsystray) { ++ if (showsystray) { + XWindowChanges wc; -+ if(!selmon->showbar) ++ if (!selmon->showbar) + wc.y = -bh; -+ else if(selmon->showbar) { ++ else if (selmon->showbar) { + wc.y = 0; -+ if(!selmon->topbar) ++ if (!selmon->topbar) + wc.y = selmon->mh - bh; + } + XConfigureWindow(dpy, systray->win, CWY, &wc); @@ -522,11 +517,11 @@ Index: dwm/dwm.c arrange(selmon); } -@@ -1719,11 +1924,18 @@ unmapnotify(XEvent *e) { +@@ -1790,11 +1996,17 @@ unmapnotify(XEvent *e) else - unmanage(c, False); + unmanage(c, 0); } -+ else if((c = wintosystrayicon(ev->window))) { ++ else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); @@ -534,47 +529,46 @@ Index: dwm/dwm.c } void - updatebars(void) { + updatebars(void) + { + unsigned int w; Monitor *m; -+ XSetWindowAttributes wa = { .override_redirect = True, - .background_pixmap = ParentRelative, -@@ -1732,10 +1944,15 @@ updatebars(void) { - for(m = mons; m; m = m->next) { +@@ -1804,10 +2016,15 @@ updatebars(void) + for (m = mons; m; m = m->next) { if (m->barwin) continue; - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), + w = m->ww; -+ if(showsystray && m == systraytomon(m)) ++ if (showsystray && m == systraytomon(m)) + w -= getsystraywidth(); + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); -+ if(showsystray && m == systraytomon(m)) ++ if (showsystray && m == systraytomon(m)) + XMapRaised(dpy, systray->win); XMapRaised(dpy, m->barwin); } } -@@ -1929,6 +2146,117 @@ updatestatus(void) { +@@ -1998,6 +2215,117 @@ updatestatus(void) } void +updatesystrayicongeom(Client *i, int w, int h) { -+ if(i) { ++ if (i) { + i->h = bh; -+ if(w == h) ++ if (w == h) + i->w = bh; -+ else if(h == bh) ++ else if (h == bh) + i->w = w; + else + i->w = (int) ((float)bh * ((float)w / (float)h)); + applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); + /* force icons into the systray dimenons if they don't want to */ -+ if(i->h > bh) { -+ if(i->w == i->h) ++ if (i->h > bh) { ++ if (i->w == i->h) + i->w = bh; + else + i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); @@ -588,17 +582,17 @@ Index: dwm/dwm.c + long flags; + int code = 0; + -+ if(!showsystray || !i || ev->atom != xatom[XembedInfo] || ++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || + !(flags = getatomprop(i, xatom[XembedInfo]))) + return; + -+ if(flags & XEMBED_MAPPED && !i->tags) { ++ if (flags & XEMBED_MAPPED && !i->tags) { + i->tags = 1; + code = XEMBED_WINDOW_ACTIVATE; + XMapRaised(dpy, i->win); + setclientstate(i, NormalState); + } -+ else if(!(flags & XEMBED_MAPPED) && i->tags) { ++ else if (!(flags & XEMBED_MAPPED) && i->tags) { + i->tags = 0; + code = XEMBED_WINDOW_DEACTIVATE; + XUnmapWindow(dpy, i->win); @@ -619,23 +613,23 @@ Index: dwm/dwm.c + unsigned int x = m->mx + m->mw; + unsigned int w = 1; + -+ if(!showsystray) ++ if (!showsystray) + return; -+ if(!systray) { ++ if (!systray) { + /* init systray */ -+ if(!(systray = (Systray *)calloc(1, sizeof(Systray)))) ++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); -+ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel].bg->rgb); ++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel].bg->pix); + wa.event_mask = ButtonPressMask | ExposureMask; + wa.override_redirect = True; -+ wa.background_pixel = scheme[SchemeNorm].bg->rgb; ++ wa.background_pixel = scheme[SchemeNorm].bg->pix; + XSelectInput(dpy, systray->win, SubstructureNotifyMask); + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&systrayorientation, 1); + XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); + XMapRaised(dpy, systray->win); + XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); -+ if(XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { ++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { + sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); + XSync(dpy, False); + } @@ -646,16 +640,16 @@ Index: dwm/dwm.c + return; + } + } -+ for(w = 0, i = systray->icons; i; i = i->next) { ++ for (w = 0, i = systray->icons; i; i = i->next) { + /* make sure the background color stays the same */ -+ wa.background_pixel = scheme[SchemeNorm].bg->rgb; ++ wa.background_pixel = scheme[SchemeNorm].bg->pix; + XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); + XMapRaised(dpy, i->win); + w += systrayspacing; + i->x = w; + XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); + w += i->w; -+ if(i->mon != m) ++ if (i->mon != m) + i->mon = m; + } + w = w ? w + systrayspacing : 1; @@ -667,16 +661,16 @@ Index: dwm/dwm.c + XMapWindow(dpy, systray->win); + XMapSubwindows(dpy, systray->win); + /* redraw background */ -+ XSetForeground(dpy, drw->gc, scheme[SchemeNorm].bg->rgb); ++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm].bg->pix); + XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); + XSync(dpy, False); +} + +void - updatewindowtype(Client *c) { + updatewindowtype(Client *c) + { Atom state = getatomprop(c, netatom[NetWMState]); - Atom wtype = getatomprop(c, netatom[NetWMWindowType]); -@@ -1997,6 +2325,16 @@ wintomon(Window w) { +@@ -2070,6 +2398,16 @@ wintomon(Window w) return selmon; } @@ -684,9 +678,9 @@ Index: dwm/dwm.c +wintosystrayicon(Window w) { + Client *i = NULL; + -+ if(!showsystray || !w) ++ if (!showsystray || !w) + return i; -+ for(i = systray->icons; i && i->win != w; i = i->next) ; ++ for (i = systray->icons; i && i->win != w; i = i->next); + return i; +} + diff --git a/dwm.suckless.org/patches/dwm-6.1-tab-v2b.diff b/dwm.suckless.org/patches/dwm-6.1-tab-v2b.diff @@ -0,0 +1,511 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..e784231 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,6 +15,12 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 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 int toptab = False; /* False means bottom tab bar */ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +@@ -62,6 +68,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 } }, +@@ -109,5 +116,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..9ff827c 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, this 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 more 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 0362114..ff06772 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,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 { +@@ -111,24 +111,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]; + int showbar; ++ int showtab; + int topbar; ++ int toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; + }; + +@@ -164,12 +172,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 int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,6 +217,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 *); +@@ -240,6 +252,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 *) = { +@@ -391,8 +404,9 @@ arrange(Monitor *m) + } + + void +-arrangemon(Monitor *m) +-{ ++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); +@@ -442,14 +456,33 @@ buttonpress(XEvent *e) + click = ClkStatusText; + else + click = ClkWinTitle; +- } else if ((c = wintoclient(ev->window))) { ++ } ++ 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 +@@ -505,6 +538,8 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -565,6 +600,7 @@ void + configurenotify(XEvent *e) + { + Monitor *m; ++ Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + +@@ -576,8 +612,12 @@ configurenotify(XEvent *e) + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for (m = mons; m; m = m->next) ++ for(m = mons; m; m = m->next){ ++ for (c = m->clients; c; c = c->next) ++ if (c->isfullscreen) ++ resizeclient(c, m->mx, m->my, m->mw, m->mh); + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -646,7 +686,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); +@@ -763,6 +806,105 @@ 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, "", 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; +@@ -787,8 +929,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 +@@ -815,6 +959,7 @@ focus(Client *c) + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + /* there are some broken focus acquiring clients */ +@@ -868,6 +1013,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) + { +@@ -1250,12 +1408,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); +@@ -1369,6 +1529,7 @@ restack(Monitor *m) + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1561,6 +1722,8 @@ setup(void) + if (!drw->fontcount) + die("no fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; ++ + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1699,6 +1862,17 @@ 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) +@@ -1809,20 +1983,44 @@ 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 +@@ -2063,7 +2261,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-urg-border.diff b/dwm.suckless.org/patches/dwm-6.1-urg-border.diff @@ -0,0 +1,61 @@ +From 8b7bc42822cd5924450bbfc9ed598f72254473ba Mon Sep 17 00:00:00 2001 +From: Alexander Huemer <alexander.huemer@xx.vu> +Date: Sat, 7 Mar 2015 21:45:48 +0100 +Subject: [PATCH] Make the borders of urgent windows a different color + +--- + config.def.h | 1 + + dwm.c | 10 ++++++++-- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 875885b..5276f02 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -8,6 +8,7 @@ static const char normfgcolor[] = "#bbbbbb"; + static const char selbordercolor[] = "#005577"; + static const char selbgcolor[] = "#005577"; + static const char selfgcolor[] = "#eeeeee"; ++static const char urgbordercolor[] = "#ff0000"; + 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 */ +diff --git a/dwm.c b/dwm.c +index c8fc7d7..0924ace 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -58,7 +58,7 @@ + + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +-enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ ++enum { SchemeNorm, SchemeSel, SchemeUrg, SchemeLast }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +@@ -1537,6 +1537,9 @@ 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); ++ scheme[SchemeUrg].border = drw_clr_create(drw, urgbordercolor); ++ scheme[SchemeUrg].bg = drw_clr_create(drw, selbgcolor); ++ scheme[SchemeUrg].fg = drw_clr_create(drw, selfgcolor); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1982,8 +1985,11 @@ updatewmhints(Client *c) { + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + } +- else ++ else { + c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; ++ if (c->isurgent) ++ XSetWindowBorder(dpy, c->win, scheme[SchemeUrg].border->pix); ++ } + if(wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else +-- +2.1.4 + diff --git a/dwm.suckless.org/patches/dwm-6.1-uselessgap.diff b/dwm.suckless.org/patches/dwm-6.1-uselessgap.diff @@ -1,15 +1,7 @@ -commit 6d7963f16af5ce9e14deab86efb3a68a5c420268 -Author: jeromenerf <jerome.andrieux@gmail.com> -Date: Sat Aug 15 18:35:11 2015 +0200 - - Useless gap for 6.1 - -diff --git a/dwm.c b/dwm.c -index c9fdd49..783fcdb 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -53,8 +53,8 @@ - #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) +--- dwm/dwm.c.orig 2015-11-22 13:26:16.664650238 -0700 ++++ dwm/dwm.c 2015-11-22 13:25:57.407984351 -0700 +@@ -52,8 +52,8 @@ + #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) -#define WIDTH(X) ((X)->w + 2 * (X)->bw) @@ -19,13 +11,13 @@ index c9fdd49..783fcdb 100644 #define TAGMASK ((1 << LENGTH(tags)) - 1) #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) -@@ -1316,12 +1317,34 @@ resize(Client *c, int x, int y, int w, int h, Bool interact) { - void - resizeclient(Client *c, int x, int y, int w, int h) { +@@ -1293,12 +1293,36 @@ void + resizeclient(Client *c, int x, int y, int w, int h) + { XWindowChanges wc; -+ unsigned int n; -+ unsigned int gapoffset; -+ unsigned int gapincr; ++ unsigned int n; ++ unsigned int gapoffset; ++ unsigned int gapincr; + Client *nbc; - c->oldx = c->x; c->x = wc.x = x; @@ -33,28 +25,30 @@ index c9fdd49..783fcdb 100644 - c->oldw = c->w; c->w = wc.width = w; - c->oldh = c->h; c->h = wc.height = h; wc.border_width = c->bw; -+ -+ // Get number of clients for the selected monitor -+ for(n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); -+ // Do nothing if layout is floating -+ if(c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { -+ gapincr = gapoffset = 0 ; -+ } else { -+ // Remove border and gap if layout is monocle or only one client ++ ++ /* Get number of clients for the selected monitor */ ++ for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); ++ ++ /* Do nothing if layout is floating */ ++ if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { ++ gapincr = gapoffset = 0; ++ } else { ++ /* Remove border and gap if layout is monocle or only one client */ + if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) { -+ gapoffset = 0; -+ gapincr = -2 * borderpx ; -+ wc.border_width = 0; -+ } else { -+ gapoffset = gappx ; -+ gapincr = 2 * gappx ; -+ } ++ gapoffset = 0; ++ gapincr = -2 * borderpx; ++ wc.border_width = 0; ++ } else { ++ gapoffset = gappx; ++ gapincr = 2 * gappx; ++ } + } + -+ c->oldx = c->x; c->x = wc.x = x + gapoffset ; -+ c->oldy = c->y; c->y = wc.y = y + gapoffset ; -+ c->oldw = c->w; c->w = wc.width = w - gapincr ; -+ c->oldh = c->h; c->h = wc.height = h - gapincr ; ++ c->oldx = c->x; c->x = wc.x = x + gapoffset; ++ c->oldy = c->y; c->y = wc.y = y + gapoffset; ++ c->oldw = c->w; c->w = wc.width = w - gapincr; ++ c->oldh = c->h; c->h = wc.height = h - gapincr; ++ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); configure(c); XSync(dpy, False); diff --git a/dwm.suckless.org/patches/dwm-6.1-warp.diff b/dwm.suckless.org/patches/dwm-6.1-warp.diff @@ -0,0 +1,57 @@ +diff -ruN dwm-6.1-orig/dwm.c dwm-6.1/dwm.c +--- dwm-6.1-orig/dwm.c 2015-11-08 16:39:37.000000000 -0600 ++++ dwm-6.1/dwm.c 2015-12-14 19:17:19.656091228 -0600 +@@ -227,6 +227,7 @@ + static void updatetitle(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); ++static void warp(const Client *c); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); +@@ -840,6 +841,7 @@ + in gedit and anjuta */ + selmon = m; + focus(NULL); ++ warp(selmon->sel); + } + + void +@@ -1384,6 +1386,8 @@ + } + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); ++ if (m == selmon && (m->tagset[m->seltags] & m->sel->tags)) ++ warp(m->sel); + } + + void +@@ -2040,6 +2044,28 @@ + arrange(selmon); + } + ++void ++warp(const Client *c) ++{ ++ int x, y; ++ ++ if (!c) { ++ XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->wx + selmon->ww/2, selmon->wy + selmon->wh/2); ++ return; ++ } ++ ++ if (!getrootptr(&x, &y) || ++ (x > c->x - c->bw && ++ y > c->y - c->bw && ++ x < c->x + c->w + c->bw*2 && ++ y < c->y + c->h + c->bw*2) || ++ (y > c->mon->by && y < c->mon->by + bh) || ++ (c->mon->topbar && !y)) ++ return; ++ ++ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); ++} ++ + Client * + wintoclient(Window w) + { diff --git a/dwm.suckless.org/patches/dwm-10e232f9ace7-attachabove.diff b/dwm.suckless.org/patches/dwm-git-20120406-attachabove.diff diff --git a/dwm.suckless.org/patches/dwm-10e232f9ace7-pertag.diff b/dwm.suckless.org/patches/dwm-git-20120406-pertag.diff diff --git a/dwm.suckless.org/patches/dwm-c794a9f5ae5e-systray.diff b/dwm.suckless.org/patches/dwm-git-20130119-systray.diff diff --git a/dwm.suckless.org/patches/dwm-git-20160103-systray.diff b/dwm.suckless.org/patches/dwm-git-20160103-systray.diff @@ -0,0 +1,689 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..8393a58 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,10 @@ static const char selbgcolor[] = "#005577"; + static const char selfgcolor[] = "#eeeeee"; + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ ++static const unsigned int systrayspacing = 2; /* systray spacing */ ++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, 0: display systray on the last monitor*/ ++static const int showsystray = 1; /* 0 means no systray */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + +diff --git a/dwm.c b/dwm.c +index ff7e096..cf0b3a9 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -57,12 +57,30 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) + ++#define SYSTEM_TRAY_REQUEST_DOCK 0 ++#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 ++ ++/* XEMBED messages */ ++#define XEMBED_EMBEDDED_NOTIFY 0 ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_FOCUS_IN 4 ++#define XEMBED_MODALITY_ON 10 ++ ++#define XEMBED_MAPPED (1 << 0) ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_WINDOW_DEACTIVATE 2 ++ ++#define VERSION_MAJOR 0 ++#define VERSION_MINOR 0 ++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR ++ + /* 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 { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, ++ NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, NetWMWindowType, ++ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ + enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +@@ -141,6 +159,12 @@ typedef struct { + int monitor; + } Rule; + ++typedef struct Systray Systray; ++struct Systray { ++ Window win; ++ Client *icons; ++}; ++ + /* function declarations */ + static void applyrules(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +@@ -170,8 +194,10 @@ static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static unsigned int getsystraywidth(); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); +@@ -189,13 +215,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); ++static void removesystrayicon(Client *i); + static void resize(Client *c, int x, int y, int w, int h, int interact); ++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); +-static int sendevent(Client *c, Atom proto); ++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); + static void sendmon(Client *c, Monitor *m); + static void setclientstate(Client *c, long state); + static void setfocus(Client *c); +@@ -206,6 +235,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static Monitor *systraytomon(Monitor *m); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -223,18 +253,24 @@ static void updateclientlist(void); + static void updatenumlockmask(void); + static void updatesizehints(Client *c); + static void updatestatus(void); ++static void updatesystray(void); ++static void updatesystrayicongeom(Client *i, int w, int h); ++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); + static void updatewindowtype(Client *c); + static void updatetitle(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); ++static Client *wintosystrayicon(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 Systray *systray = NULL; ++static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; + static const char broken[] = "broken"; + static char stext[256]; + static int screen; +@@ -256,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, ++ [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify + }; +-static Atom wmatom[WMLast], netatom[NetLast]; ++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; + static int running = 1; + static Cur *cursor[CurLast]; + static ClrScheme scheme[SchemeLast]; +@@ -479,6 +516,11 @@ cleanup(void) + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); ++ if (showsystray) { ++ XUnmapWindow(dpy, systray->win); ++ XDestroyWindow(dpy, systray->win); ++ free(systray); ++ } + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < SchemeLast; i++) { +@@ -524,9 +566,50 @@ clearurgent(Client *c) + void + clientmessage(XEvent *e) + { ++ XWindowAttributes wa; ++ XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + ++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { ++ /* add systray icons */ ++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { ++ if (!(c = (Client *)calloc(1, sizeof(Client)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); ++ c->win = cme->data.l[2]; ++ c->mon = selmon; ++ c->next = systray->icons; ++ systray->icons = c; ++ XGetWindowAttributes(dpy, c->win, &wa); ++ c->x = c->oldx = c->y = c->oldy = 0; ++ c->w = c->oldw = wa.width; ++ c->h = c->oldh = wa.height; ++ c->oldbw = wa.border_width; ++ c->bw = 0; ++ c->isfloating = True; ++ /* reuse tags field as mapped status */ ++ c->tags = 1; ++ updatesizehints(c); ++ updatesystrayicongeom(c, wa.width, wa.height); ++ XAddToSaveSet(dpy, c->win); ++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); ++ XReparentWindow(dpy, c->win, systray->win, 0, 0); ++ /* use parents background color */ ++ swa.background_pixel = scheme[SchemeNorm].bg->pix; ++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ /* FIXME not sure if I have to send these events, too */ ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ XSync(dpy, False); ++ resizebarwin(selmon); ++ updatesystray(); ++ setclientstate(c, NormalState); ++ } ++ return; ++ } ++ + if (!c) + return; + if (cme->message_type == netatom[NetWMState]) { +@@ -581,7 +664,7 @@ configurenotify(XEvent *e) + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); +- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ resizebarwin(m); + } + focus(NULL); + arrange(NULL); +@@ -666,6 +749,11 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void +@@ -715,6 +803,7 @@ drawbar(Monitor *m) + + dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; + ++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) +@@ -737,6 +826,9 @@ drawbar(Monitor *m) + 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; +@@ -765,6 +857,7 @@ drawbars(void) + + for (m = mons; m; m = m->next) + drawbar(m); ++ updatesystray(); + } + + void +@@ -792,8 +885,11 @@ 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); ++ if (m == selmon) ++ updatesystray(); ++ } + } + + void +@@ -880,10 +976,17 @@ getatomprop(Client *c, Atom prop) + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; ++ /* FIXME getatomprop should return the number of items and a pointer to ++ * the stored data instead of this workaround */ ++ Atom req = XA_ATOM; ++ if (prop == xatom[XembedInfo]) ++ req = xatom[XembedInfo]; + +- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, ++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; ++ if (da == xatom[XembedInfo] && dl == 2) ++ atom = ((Atom *)p)[1]; + XFree(p); + } + return atom; +@@ -917,6 +1020,15 @@ getstate(Window w) + return result; + } + ++unsigned int ++getsystraywidth() { ++ unsigned int w = 0; ++ Client *i; ++ if (showsystray) ++ for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next); ++ return w ? w + systrayspacing : 1; ++} ++ + int + gettextprop(Window w, Atom atom, char *text, unsigned int size) + { +@@ -1023,7 +1135,7 @@ killclient(const Arg *arg) + { + if (!selmon->sel) + return; +- if (!sendevent(selmon->sel, wmatom[WMDelete])) { ++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); +@@ -1110,6 +1222,12 @@ maprequest(XEvent *e) + { + static XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; ++ Client *i; ++ if ((i = wintosystrayicon(ev->window))) { ++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + + if (!XGetWindowAttributes(dpy, ev->window, &wa)) + return; +@@ -1237,6 +1355,16 @@ propertynotify(XEvent *e) + Window trans; + XPropertyEvent *ev = &e->xproperty; + ++ if ((c = wintosystrayicon(ev->window))) { ++ if (ev->atom == XA_WM_NORMAL_HINTS) { ++ updatesizehints(c); ++ updatesystrayicongeom(c, c->w, c->h); ++ } ++ else ++ updatesystrayiconstate(c, ev); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) + updatestatus(); + else if (ev->state == PropertyDelete) +@@ -1288,6 +1416,19 @@ recttomon(int x, int y, int w, int h) + } + + void ++removesystrayicon(Client *i) { ++ Client **ii; ++ ++ if (!showsystray || !i) ++ return; ++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); ++ if (ii) ++ *ii = i->next; ++ free(i); ++} ++ ++ ++void + resize(Client *c, int x, int y, int w, int h, int interact) + { + if (applysizehints(c, &x, &y, &w, &h, interact)) +@@ -1295,6 +1436,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) + } + + void ++resizebarwin(Monitor *m) { ++ unsigned int w = m->ww; ++ if (showsystray && m == systraytomon(m)) ++ w -= getsystraywidth(); ++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); ++} ++ ++void + resizeclient(Client *c, int x, int y, int w, int h) + { + XWindowChanges wc; +@@ -1367,6 +1516,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; +@@ -1455,26 +1616,36 @@ setclientstate(Client *c, long state) + } + + int +-sendevent(Client *c, Atom proto) ++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) + { + int n; +- Atom *protocols; ++ Atom *protocols, mt; + int exists = 0; + XEvent ev; + +- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { +- while (!exists && n--) +- exists = protocols[n] == proto; +- XFree(protocols); ++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { ++ mt = wmatom[WMProtocols]; ++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { ++ while(!exists && n--) ++ exists = protocols[n] == proto; ++ XFree(protocols); ++ } ++ } ++ else { ++ exists = True; ++ mt = proto; + } + if (exists) { + ev.type = ClientMessage; +- ev.xclient.window = c->win; +- ev.xclient.message_type = wmatom[WMProtocols]; ++ ev.xclient.window = w; ++ ev.xclient.message_type = mt; + ev.xclient.format = 32; +- ev.xclient.data.l[0] = proto; +- ev.xclient.data.l[1] = CurrentTime; +- XSendEvent(dpy, c->win, False, NoEventMask, &ev); ++ ev.xclient.data.l[0] = d0; ++ ev.xclient.data.l[1] = d1; ++ ev.xclient.data.l[2] = d2; ++ ev.xclient.data.l[3] = d3; ++ ev.xclient.data.l[4] = d4; ++ XSendEvent(dpy, w, False, mask, &ev); + } + return exists; + } +@@ -1488,7 +1659,7 @@ setfocus(Client *c) + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } +- sendevent(c, wmatom[WMTakeFocus]); ++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); + } + + void +@@ -1574,12 +1745,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); ++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); ++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); ++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); + netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); + netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); + netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); ++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); ++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); ++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); +@@ -1591,6 +1768,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); ++ /* init system tray */ ++ updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1650,6 +1829,22 @@ spawn(const Arg *arg) + } + } + ++Monitor * ++systraytomon(Monitor *m) { ++ Monitor *t; ++ int i, n; ++ if (!systraypinning) { ++ if (!m) ++ return selmon; ++ return m == selmon ? m : NULL; ++ } ++ for (n = 1, t = mons; t && t->next; n++, t = t->next); ++ for (i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next); ++ if (systraypinningfailfirst && n < systraypinning) ++ return mons; ++ return t; ++} ++ + void + tag(const Arg *arg) + { +@@ -1699,7 +1894,18 @@ togglebar(const Arg *arg) + { + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); +- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); ++ resizebarwin(selmon); ++ if (showsystray) { ++ XWindowChanges wc; ++ if (!selmon->showbar) ++ wc.y = -bh; ++ else if (selmon->showbar) { ++ wc.y = 0; ++ if (!selmon->topbar) ++ wc.y = selmon->mh - bh; ++ } ++ XConfigureWindow(dpy, systray->win, CWY, &wc); ++ } + arrange(selmon); + } + +@@ -1795,11 +2001,17 @@ unmapnotify(XEvent *e) + else + unmanage(c, 0); + } ++ else if ((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void + updatebars(void) + { ++ unsigned int w; + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, +@@ -1809,10 +2021,15 @@ updatebars(void) + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; +- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), ++ w = m->ww; ++ if (showsystray && m == systraytomon(m)) ++ w -= getsystraywidth(); ++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); ++ if (showsystray && m == systraytomon(m)) ++ XMapRaised(dpy, systray->win); + XMapRaised(dpy, m->barwin); + } + } +@@ -2003,6 +2220,117 @@ updatestatus(void) + } + + void ++updatesystrayicongeom(Client *i, int w, int h) { ++ if (i) { ++ i->h = bh; ++ if (w == h) ++ i->w = bh; ++ else if (h == bh) ++ i->w = w; ++ else ++ i->w = (int) ((float)bh * ((float)w / (float)h)); ++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); ++ /* force icons into the systray dimenons if they don't want to */ ++ if (i->h > bh) { ++ if (i->w == i->h) ++ i->w = bh; ++ else ++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); ++ i->h = bh; ++ } ++ } ++} ++ ++void ++updatesystrayiconstate(Client *i, XPropertyEvent *ev) { ++ long flags; ++ int code = 0; ++ ++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || ++ !(flags = getatomprop(i, xatom[XembedInfo]))) ++ return; ++ ++ if (flags & XEMBED_MAPPED && !i->tags) { ++ i->tags = 1; ++ code = XEMBED_WINDOW_ACTIVATE; ++ XMapRaised(dpy, i->win); ++ setclientstate(i, NormalState); ++ } ++ else if (!(flags & XEMBED_MAPPED) && i->tags) { ++ i->tags = 0; ++ code = XEMBED_WINDOW_DEACTIVATE; ++ XUnmapWindow(dpy, i->win); ++ setclientstate(i, WithdrawnState); ++ } ++ else ++ return; ++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, ++ systray->win, XEMBED_EMBEDDED_VERSION); ++} ++ ++void ++updatesystray(void) { ++ XSetWindowAttributes wa; ++ XWindowChanges wc; ++ Client *i; ++ Monitor *m = systraytomon(NULL); ++ unsigned int x = m->mx + m->mw; ++ unsigned int w = 1; ++ ++ if (!showsystray) ++ return; ++ if (!systray) { ++ /* init systray */ ++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); ++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel].bg->pix); ++ wa.event_mask = ButtonPressMask | ExposureMask; ++ wa.override_redirect = True; ++ wa.background_pixel = scheme[SchemeNorm].bg->pix; ++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); ++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, ++ PropModeReplace, (unsigned char *)&systrayorientation, 1); ++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); ++ XMapRaised(dpy, systray->win); ++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); ++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { ++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); ++ XSync(dpy, False); ++ } ++ else { ++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); ++ free(systray); ++ systray = NULL; ++ return; ++ } ++ } ++ for (w = 0, i = systray->icons; i; i = i->next) { ++ /* make sure the background color stays the same */ ++ wa.background_pixel = scheme[SchemeNorm].bg->pix; ++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); ++ XMapRaised(dpy, i->win); ++ w += systrayspacing; ++ 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); ++ XMapWindow(dpy, systray->win); ++ XMapSubwindows(dpy, systray->win); ++ /* redraw background */ ++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm].bg->pix); ++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); ++ XSync(dpy, False); ++} ++ ++void + updatewindowtype(Client *c) + { + Atom state = getatomprop(c, netatom[NetWMState]); +@@ -2075,6 +2403,16 @@ wintomon(Window w) + return selmon; + } + ++Client * ++wintosystrayicon(Window w) { ++ Client *i = NULL; ++ ++ if (!showsystray || !w) ++ return i; ++ for (i = systray->icons; i && i->win != w; i = i->next); ++ return i; ++} ++ + /* There's no way to check accesses to destroyed windows, thus those cases are + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs + * default error handler, which may call exit. */ diff --git a/dwm.suckless.org/patches/dwm-master_2015-12-19_3465be-pertag-tab-v2b.diff b/dwm.suckless.org/patches/dwm-master_2015-12-19_3465be-pertag-tab-v2b.diff @@ -0,0 +1,844 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..f0b33c5 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,10 +15,21 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 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 +@@ -62,6 +73,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 } }, +@@ -109,5 +121,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..077d92b 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 ff7e096..830d2c2 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,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 { +@@ -111,25 +111,35 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ ++typedef struct Pertag Pertag; + 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]; + int showbar; ++ int showtab; + int topbar; ++ int 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 { +@@ -164,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 int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,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 *); +@@ -240,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 +285,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 */ ++ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -393,6 +418,8 @@ 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); +@@ -442,14 +469,33 @@ buttonpress(XEvent *e) + click = ClkStatusText; + else + click = ClkWinTitle; +- } else if ((c = wintoclient(ev->window))) { ++ } ++ 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); ++ 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 || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -469,23 +515,24 @@ cleanup(void) + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; +- size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) +- while (m->stack) +- unmanage(m->stack, 0); ++ while(m->stack) ++ unmanage(m->stack, False); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); +- for (i = 0; i < CurLast; i++) +- drw_cur_free(drw, cursor[i]); +- for (i = 0; i < SchemeLast; i++) { +- drw_clr_free(scheme[i].border); +- drw_clr_free(scheme[i].bg); +- drw_clr_free(scheme[i].fg); +- } ++ drw_cur_free(drw, cursor[CurNormal]); ++ drw_cur_free(drw, cursor[CurResize]); ++ drw_cur_free(drw, cursor[CurMove]); ++ drw_clr_free(scheme[SchemeNorm].border); ++ drw_clr_free(scheme[SchemeNorm].bg); ++ drw_clr_free(scheme[SchemeNorm].fg); ++ drw_clr_free(scheme[SchemeSel].border); ++ drw_clr_free(scheme[SchemeSel].bg); ++ drw_clr_free(scheme[SchemeSel].fg); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); +@@ -505,6 +552,8 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -526,6 +575,7 @@ clientmessage(XEvent *e) + { + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); ++ int i; + + if (!c) + return; +@@ -537,6 +587,8 @@ clientmessage(XEvent *e) + if (!ISVISIBLE(c)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; ++ for(i=0; !(c->tags & 1 << i); i++); ++ view(&(Arg){.ui = 1 << i}); + } + pop(c); + } +@@ -565,11 +617,10 @@ void + configurenotify(XEvent *e) + { + Monitor *m; +- Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + +- /* TODO: updategeom handling sucks, needs to be simplified */ ++ // TODO: updategeom handling sucks, needs to be simplified + if (ev->window == root) { + dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; +@@ -577,10 +628,9 @@ configurenotify(XEvent *e) + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for (m = mons; m; m = m->next) { +- for (c = m->clients; c; c = c->next) +- if (c->isfullscreen) +- resizeclient(c, m->mx, m->my, m->mw, m->mh); ++ //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); +@@ -645,16 +695,41 @@ Monitor * + createmon(void) + { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; +- m->lt[0] = &layouts[0]; ++ m->toptab = toptab; ++ m->ntabs = 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] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ ++ /* swap focus and zoomswap*/ ++ m->pertag->prevzooms[i] = NULL; ++ } + return m; + } + +@@ -768,6 +843,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, "", 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; +@@ -792,8 +965,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 +@@ -811,7 +986,7 @@ focus(Client *c) + clearurgent(c); + detachstack(c); + attachstack(c); +- grabbuttons(c, 1); ++ grabbuttons(c, True); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); + setfocus(c); + } else { +@@ -820,6 +995,7 @@ focus(Client *c) + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + /* there are some broken focus acquiring clients */ +@@ -873,6 +1049,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) + { +@@ -986,7 +1175,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); + } + +@@ -1144,7 +1333,7 @@ motionnotify(XEvent *e) + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { +- unfocus(selmon->sel, 1); ++ unfocus(selmon->sel, True); + selmon = m; + focus(NULL); + } +@@ -1164,11 +1353,13 @@ movemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; ++ if(c->isfullscreen) /* no support moving fullscreen windows by mouse */ ++ return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, +- None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) ++ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; +@@ -1255,12 +1446,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); +@@ -1322,11 +1515,13 @@ resizemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; ++ if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */ ++ return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, +- None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) ++ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + return; + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + do { +@@ -1374,6 +1569,7 @@ restack(Monitor *m) + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1482,11 +1678,11 @@ sendevent(Client *c, Atom proto) + void + setfocus(Client *c) + { +- if (!c->neverfocus) { ++ if(!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], +- XA_WINDOW, 32, PropModeReplace, +- (unsigned char *) &(c->win), 1); ++ XA_WINDOW, 32, PropModeReplace, ++ (unsigned char *) &(c->win), 1); + } + sendevent(c, wmatom[WMTakeFocus]); + } +@@ -1522,10 +1718,13 @@ setfullscreen(Client *c, int 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; ++ 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->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); +@@ -1544,7 +1743,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); + } + +@@ -1564,8 +1763,9 @@ setup(void) + drw = drw_create(dpy, screen, root, sw, sh); + drw_load_fonts(drw, fonts, LENGTH(fonts)); + if (!drw->fontcount) +- die("no fonts could be loaded.\n"); ++ die("No fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1637,10 +1837,10 @@ sigchld(int unused) + void + spawn(const Arg *arg) + { +- if (arg->v == dmenucmd) ++ if(arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; +- if (fork() == 0) { +- if (dpy) ++ if(fork() == 0) { ++ if(dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); +@@ -1697,18 +1897,29 @@ 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) ++ if(!selmon->sel) + return; +- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ ++ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) +@@ -1736,9 +1947,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); + } +@@ -1749,7 +1980,7 @@ unfocus(Client *c, int setfocus) + { + if (!c) + return; +- grabbuttons(c, 0); ++ grabbuttons(c, False); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1814,20 +2045,44 @@ 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 +@@ -2009,9 +2264,9 @@ updatewindowtype(Client *c) + Atom wtype = getatomprop(c, netatom[NetWMWindowType]); + + if (state == netatom[NetWMFullscreen]) +- setfullscreen(c, 1); ++ setfullscreen(c, True); + if (wtype == netatom[NetWMWindowTypeDialog]) +- c->isfloating = 1; ++ c->isfloating = True; + } + + void +@@ -2036,11 +2291,33 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { +- if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) ++ 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); + } +@@ -2068,7 +2345,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_2015-12-19_3465be-tab-v2b.diff b/dwm.suckless.org/patches/dwm-master_2015-12-19_3465be-tab-v2b.diff @@ -0,0 +1,500 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..e784231 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,6 +15,12 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 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 int toptab = False; /* False means bottom tab bar */ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +@@ -62,6 +68,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 } }, +@@ -109,5 +116,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..9ff827c 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, this 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 more 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 ff7e096..fb285ec 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,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 { +@@ -111,24 +111,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]; + int showbar; ++ int showtab; + int topbar; ++ int toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; + }; + +@@ -164,12 +172,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 int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,6 +217,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 *); +@@ -240,6 +252,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 *) = { +@@ -391,8 +404,9 @@ arrange(Monitor *m) + } + + void +-arrangemon(Monitor *m) +-{ ++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); +@@ -442,14 +456,33 @@ buttonpress(XEvent *e) + click = ClkStatusText; + else + click = ClkWinTitle; +- } else if ((c = wintoclient(ev->window))) { ++ } ++ 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 +@@ -505,6 +538,8 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -577,7 +612,9 @@ 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){ + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); +@@ -651,7 +688,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); +@@ -768,6 +808,105 @@ 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, "", 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; +@@ -792,8 +931,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 +@@ -820,6 +961,7 @@ focus(Client *c) + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + /* there are some broken focus acquiring clients */ +@@ -873,6 +1015,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) + { +@@ -1255,12 +1410,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); +@@ -1374,6 +1531,7 @@ restack(Monitor *m) + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1566,6 +1724,8 @@ setup(void) + if (!drw->fontcount) + die("no fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; ++ + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1704,6 +1864,17 @@ 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) +@@ -1814,20 +1985,44 @@ 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 +@@ -2068,7 +2263,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/exresize.md b/dwm.suckless.org/patches/exresize.md @@ -16,7 +16,7 @@ description. Download -------- - * [dwm-r1606-exresize.dif](dwm-r1606-exresize.diff) (20121117) + * [dwm-r1606-exresize.diff](dwm-r1606-exresize.diff) (20121117) Authors ------- diff --git a/dwm.suckless.org/patches/fancybar-c794a9f5ae5e.patch b/dwm.suckless.org/patches/fancybar-c794a9f5ae5e.patch @@ -1,124 +0,0 @@ ---- dwm.c.orig 2012-09-30 16:19:00.251353990 -0400 -+++ dwm.c 2012-09-30 16:18:06.436026937 -0400 -@@ -179,6 +179,7 @@ - static Monitor *dirtomon(int dir); - static void drawbar(Monitor *m); - static void drawbars(void); -+static void drawline(unsigned long col[ColLast]); - 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 enternotify(XEvent *e); -@@ -721,12 +722,15 @@ - - void - drawbar(Monitor *m) { -- int x; -- unsigned int i, occ = 0, urg = 0; -+ int x, ow, mw = 0, extra, tw; -+ unsigned int i, n = 0, occ = 0, urg = 0; - unsigned long *col; -- Client *c; -+ Client *c, *firstvis, *lastvis = NULL; -+ DC seldc; - - for(c = m->clients; c; c = c->next) { -+ if(ISVISIBLE(c)) -+ n++; - occ |= c->tags; - if(c->isurgent) - urg |= c->tags; -@@ -755,16 +759,61 @@ - } - 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); -- drawsquare(m->sel->isfixed, m->sel->isfloating, False, col); -+ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); -+ firstvis = c; -+ -+ col = m == selmon ? dc.sel : dc.norm; -+ dc.w = dc.x - x; -+ dc.x = x; -+ -+ if(n > 0) { -+ mw = dc.w / n; -+ extra = 0; -+ seldc = dc; -+ i = 0; -+ -+ while(c) { -+ lastvis = c; -+ tw = TEXTW(c->name); -+ if(tw < mw) extra += (mw - tw); else i++; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); - } -- else -+ -+ if(i > 0) mw += extra / i; -+ -+ c = firstvis; -+ x = dc.x; -+ } -+ -+ while(dc.w > bh) { -+ if(c) { -+ ow = dc.w; -+ tw = TEXTW(c->name); -+ dc.w = MIN(ow, tw); -+ -+ if(dc.w > mw) dc.w = mw; -+ if(m->sel ==c) seldc = dc; -+ if(c == lastvis) dc.w = ow; -+ -+ drawtext(c->name, col, False); -+ if(c != firstvis) drawline(col); -+ drawsquare(c->isfixed, c->isfloating, False, col); -+ -+ dc.x += dc.w; -+ dc.w = ow - dc.w; -+ for(c = c->next; c&& !ISVISIBLE(c); c = c->next); -+ } else { - drawtext(NULL, dc.norm, False); -+ break; -+ } - } -+ -+ if(m == selmon && m->sel && ISVISIBLE(m->sel)) { -+ dc = seldc; -+ drawtext(m->sel->name, col, True); -+ drawsquare(m->sel->isfixed, m->sel->isfloating, True, col); -+ } -+ - XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0); - XSync(dpy, False); - } -@@ -778,6 +827,15 @@ - } - - void -+drawline(unsigned long col[ColLast]) { -+ XGCValues gcv; -+ -+ gcv.foreground = col[ColFG]; -+ XChangeGC(dpy, dc.gc, GCForeground, &gcv); -+ XDrawLine(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.x, dc.y + (dc.font.ascent + dc.font.descent + 2)); -+} -+ -+void - drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { - int x; - -@@ -1327,8 +1385,7 @@ - } - if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { - updatetitle(c); -- if(c == c->mon->sel) -- drawbar(c->mon); -+ drawbar(c->mon); - } - if(ev->atom == netatom[NetWMWindowType]) - updatewindowtype(c); diff --git a/dwm.suckless.org/patches/fancybar-r1496.diff b/dwm.suckless.org/patches/fancybar-r1496.diff @@ -1,126 +0,0 @@ -diff -r de4a2998e1f5 dwm.c ---- a/dwm.c Tue Sep 22 09:53:11 2009 +0100 -+++ b/dwm.c Tue Sep 22 12:32:15 2009 +0200 -@@ -171,6 +171,7 @@ - static Monitor *dirtomon(int dir); - static void drawbar(Monitor *m); - static void drawbars(void); -+static void drawvline(unsigned long col[ColLast]); - 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 enternotify(XEvent *e); -@@ -668,12 +669,15 @@ - - void - drawbar(Monitor *m) { -- int x; -- unsigned int i, occ = 0, urg = 0; -+ int x, ow, mw = 0, extra, tw; -+ unsigned int i, n = 0, occ = 0, urg = 0; - unsigned long *col; -- Client *c; -+ Client *c, *firstvis, *lastvis = NULL; -+ DC seldc; - - for(c = m->clients; c; c = c->next) { -+ if(ISVISIBLE(c)) -+ n++; - occ |= c->tags; - if(c->isurgent) - urg |= c->tags; -@@ -702,16 +706,62 @@ - } - 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); -- drawsquare(m->sel->isfixed, m->sel->isfloating, False, col); -+ -+ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); -+ firstvis = c; -+ -+ col = m == selmon ? dc.sel : dc.norm; -+ dc.w = dc.x - x; -+ dc.x = x; -+ -+ if(n > 0) { -+ mw = dc.w / n; -+ extra = 0; -+ seldc = dc; -+ i = 0; -+ -+ while(c) { -+ lastvis = c; -+ tw = TEXTW(c->name); -+ if(tw < mw) extra += (mw - tw); else i++; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); - } -- else -+ -+ if(i > 0) mw += extra / i; -+ -+ c = firstvis; -+ x = dc.x; -+ } -+ -+ while(dc.w > bh) { -+ if(c) { -+ ow = dc.w; -+ tw = TEXTW(c->name); -+ dc.w = MIN(ow, tw); -+ -+ if(dc.w > mw) dc.w = mw; -+ if(m->sel == c) seldc = dc; -+ if(c == lastvis) dc.w = ow; -+ -+ drawtext(c->name, col, False); -+ if(c != firstvis) drawvline(col); -+ drawsquare(c->isfixed, c->isfloating, False, col); -+ -+ dc.x += dc.w; -+ dc.w = ow - dc.w; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); -+ } else { - drawtext(NULL, dc.norm, False); -+ break; -+ } - } -+ -+ if(m == selmon && m->sel && ISVISIBLE(m->sel)) { -+ dc = seldc; -+ drawtext(m->sel->name, col, True); -+ drawsquare(m->sel->isfixed, m->sel->isfloating, True, col); -+ } -+ - XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0); - XSync(dpy, False); - } -@@ -725,6 +775,15 @@ - } - - void -+drawvline(unsigned long col[ColLast]) { -+ XGCValues gcv; -+ -+ gcv.foreground = col[ColFG]; -+ XChangeGC(dpy, dc.gc, GCForeground, &gcv); -+ XDrawLine(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.x, dc.y + (dc.font.ascent + dc.font.descent + 2)); -+} -+ -+void - drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { - int x; - XGCValues gcv; -@@ -1274,8 +1333,7 @@ - } - if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { - updatetitle(c); -- if(c == c->mon->sel) -- drawbar(c->mon); -+ drawbar(c->mon); - } - } - } diff --git a/dwm.suckless.org/patches/fancybar.md b/dwm.suckless.org/patches/fancybar.md @@ -6,16 +6,14 @@ This patch provides a status bar that shows the titles of all visible windows (as opposed to showing just the selected one). When the titles don't completely fit, they're cropped. The title of the selected window is inverted. -[![Fancybar, no cropping][1]][2] [![Fancybar with cropping][3]][4] +[![Fancybar][1]][1] *Fancybar in action* ## Download * [fancybar-5.6.1.diff](historical/fancybar-5.6.1.diff) (dwm 5.6.1) (20090824) - * [fancybar-r1496.diff](fancybar-r1496.diff) (dwm 5.7) (20090922) - * [fancybar-c794a9f5ae5e.patch](fancybar-c794a9f5ae5e.patch) (20120708) - * [dwm-35db6d8-fancybar.diff](dwm-35db6d8-fancybar.diff) (20150105) + * [dwm-6.1-fancybar.diff](dwm-6.1-fancybar.diff) (20151109) ## Author @@ -24,7 +22,4 @@ fit, they're cropped. The title of the selected window is inverted. This patch was inspired by the decorated tabbed layout of Xmonad. -[1]: http://port70.net/~kzed/dwm-5.6.1/dwm-5.6.1-fancybar-1.png.jpg -[2]: http://port70.net/~kzed/dwm-5.6.1/dwm-5.6.1-fancybar-1.png -[3]: http://port70.net/~kzed/dwm-5.6.1/dwm-5.6.1-fancybar-2.png.jpg -[4]: http://port70.net/~kzed/dwm-5.6.1/dwm-5.6.1-fancybar-2.png +[1]: http://s27.postimg.org/nvlkivn03/2015_10_14_132203_727x15_scrot.png diff --git a/dwm.suckless.org/patches/fancybarclickable.md b/dwm.suckless.org/patches/fancybarclickable.md @@ -8,14 +8,17 @@ minus the [statuscolors](statuscolors). It uses the dwm bar to show you the titles of all the windows in the current tag and lets you select windows by selecting their title in the dwm bar. +[![Fancybarclickable][1]][1] + Download -------- * [dwm-6.1-fancybarclickable.diff](dwm-6.1-fancybarclickable.diff) Authors ------- - -* Stefan Mark wrote fancycoloredbarclickable. -* Mate Nagy wrote fancybar. +* Stefan Mark wrote [fancycoloredbarclickable](fancycoloredbarclickable.md). +* Mate Nagy wrote [fancybar](fancybar.md). * An anonymous Canadian updated the fancybar patch and added the - selectby-click-on-title function from fancycoloredbarclickable to it. + `selectby-click-on-title` function from fancycoloredbarclickable to it. + +[1]: http://s4.postimg.org/ql2f934wd/fancybar.png diff --git a/dwm.suckless.org/patches/fibonacci.md b/dwm.suckless.org/patches/fibonacci.md @@ -18,10 +18,6 @@ arrangement can be seen below. +-----------+-----+-----+ +-----------+-----+-----+ spiral dwindle -[![dwm in spiral layout.][1]][2] - -*Links2, sic, xterm & xclock in spiral layout.* - ## Usage 1. Download the patch and apply according to the [general instructions](.). @@ -50,6 +46,4 @@ Joe Thornber's spiral tiling for [Xmonad][3] formed the inspiration for this patch. Thanks to Jan Christoph Ebersbach for updating this patch for versions 4.5 to 4.9. -[1]: http://schot.a-eskwadraat.nl/images/dwm-spiral_small.png -[2]: http://schot.a-eskwadraat.nl/images/dwm-spiral.png -[3]: http://www.xmonad.org +[1]: http://www.xmonad.org diff --git a/dwm.suckless.org/patches/flextile.md b/dwm.suckless.org/patches/flextile.md @@ -8,7 +8,7 @@ This patch replaces the `tile` layout with a more flexible version. The features * left/right/top/bottom n-master, right/left/bottom/top/no stack/deck (deck is like `monocle` in the stack area) * per-tag configuration -It therefor provides i. a. the following additional possibilities: +It therefore provides the following additional possibilities: * `tile` for left-handed people * compare multiple files with one other each at a time without switching between views diff --git a/dwm.suckless.org/patches/focusonclick.md b/dwm.suckless.org/patches/focusonclick.md @@ -7,8 +7,8 @@ ## Download * [dwm-6.0-focusonclick.diff](dwm-6.0-focusonclick.diff) (2012-11-24) - * [dwm-r1508-focusonclick.diff](dwm-r1508-focusonclick.diff) (dwm r1508) (20100321) - * [dwm-5.8.2-focusonclick.diff](dwm-5.8.2-focusonclick.diff) (dwm 2010604) + * [dwm-git-20100321-focusonclick.diff](historical/dwm-git-20100321-focusonclick.diff) + * [dwm-5.8.2-focusonclick.diff](historical/dwm-5.8.2-focusonclick.diff) (dwm 2010604) ## Author diff --git a/dwm.suckless.org/patches/hide_vacant_tags.md b/dwm.suckless.org/patches/hide_vacant_tags.md @@ -18,9 +18,10 @@ filled/empty rectangles. Download -------- -* [dwm-6.1-hide_vacant_tags.diff](dwm-6.1-hide_vacant_tags.diff) (1169b) (20140607) +* [dwm-6.1-hide_vacant_tags.diff](dwm-6.1-hide_vacant_tags.diff) - 2016-01-22 Author ------ * [OndÅ™ej Grover](mailto:ondrej.grover@gmail.com) +* Matthew Boswell - mordervomubel+suckless at lockmail dot us (mechanical update for dwm 6.1 release) diff --git a/dwm.suckless.org/patches/dwm-5.6.1-attachabove.diff b/dwm.suckless.org/patches/historical/dwm-5.6.1-attachabove.diff diff --git a/dwm.suckless.org/patches/dwm-5.6.1-attachaside.diff b/dwm.suckless.org/patches/historical/dwm-5.6.1-attachaside.diff diff --git a/dwm.suckless.org/patches/dwm-5.7.2-attachaside.diff b/dwm.suckless.org/patches/historical/dwm-5.7.2-attachaside.diff diff --git a/dwm.suckless.org/patches/dwm-5.8.2-focusonclick.diff b/dwm.suckless.org/patches/historical/dwm-5.8.2-focusonclick.diff diff --git a/dwm.suckless.org/patches/dwm-5.8.2-pertag.diff b/dwm.suckless.org/patches/historical/dwm-5.8.2-pertag.diff diff --git a/dwm.suckless.org/patches/dwm-5.8.2-pertag_without_bar.diff b/dwm.suckless.org/patches/historical/dwm-5.8.2-pertag_without_bar.diff diff --git a/dwm.suckless.org/patches/historical/dwm-6.0-xft.diff b/dwm.suckless.org/patches/historical/dwm-6.0-xft.diff @@ -0,0 +1,259 @@ +diff --git a/config.def.h b/config.def.h +index 77ff358..a355bf0 100644 +--- a/config.def.h ++++ 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[] = "monospace-9"; + static const char normbordercolor[] = "#444444"; + static const char normbgcolor[] = "#222222"; + static const char normfgcolor[] = "#bbbbbb"; +diff --git a/config.mk b/config.mk +index 484554a..a09be79 100644 +--- a/config.mk ++++ 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} -I/usr/include/freetype2 ++LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} -lfontconfig -lXft + + # flags + CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +diff --git a/dwm.c b/dwm.c +index 1d78655..9587e77 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -39,6 +39,7 @@ + #ifdef XINERAMA + #include <X11/extensions/Xinerama.h> + #endif /* XINERAMA */ ++#include <X11/Xft/Xft.h> + + /* macros */ + #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +@@ -99,16 +100,15 @@ struct Client { + + typedef struct { + int x, y, w, h; +- unsigned long norm[ColLast]; +- unsigned long sel[ColLast]; ++ XftColor norm[ColLast]; ++ XftColor sel[ColLast]; + Drawable drawable; + GC gc; + struct { + int ascent; + int descent; + int height; +- XFontSet set; +- XFontStruct *xfont; ++ XftFont *xfont; + } font; + } DC; /* draw context */ + +@@ -178,15 +178,15 @@ static void die(const char *errstr, ...); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(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 drawsquare(Bool filled, Bool empty, Bool invert, XftColor col[ColLast]); ++static void drawtext(const char *text, XftColor col[ColLast], Bool invert); + 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 unsigned long getcolor(const char *colstr); ++static XftColor getcolor(const char *colstr); + static Bool getrootptr(int *x, int *y); + static long getstate(Window w); + static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -485,10 +485,6 @@ cleanup(void) { + for(m = mons; m; m = m->next) + while(m->stack) + unmanage(m->stack, False); +- if(dc.font.set) +- XFreeFontSet(dpy, dc.font.set); +- else +- XFreeFont(dpy, dc.font.xfont); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + XFreePixmap(dpy, dc.drawable); + XFreeGC(dpy, dc.gc); +@@ -719,7 +715,7 @@ void + drawbar(Monitor *m) { + int x; + unsigned int i, occ = 0, urg = 0; +- unsigned long *col; ++ XftColor *col; + Client *c; + + for(c = m->clients; c; c = c->next) { +@@ -774,10 +770,10 @@ drawbars(void) { + } + + void +-drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { ++drawsquare(Bool filled, Bool empty, Bool invert, XftColor col[ColLast]) { + int x; + +- XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); ++ XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG].pixel); + x = (dc.font.ascent + dc.font.descent + 2) / 4; + if(filled) + XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1); +@@ -786,11 +782,12 @@ drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { + } + + void +-drawtext(const char *text, unsigned long col[ColLast], Bool invert) { ++drawtext(const char *text, XftColor col[ColLast], Bool invert) { + char buf[256]; + int i, x, y, h, len, olen; ++ XftDraw *d; + +- XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); ++ XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG].pixel); + XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); + if(!text) + return; +@@ -805,11 +802,11 @@ drawtext(const char *text, unsigned long col[ColLast], Bool invert) { + memcpy(buf, text, len); + if(len < olen) + 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); +- else +- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); ++ ++ d = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy, screen), DefaultColormap(dpy,screen)); ++ ++ XftDrawStringUtf8(d, &col[invert ? ColBG : ColFG], dc.font.xfont, x, y, (XftChar8 *) buf, len); ++ XftDrawDestroy(d); + } + + void +@@ -855,7 +852,7 @@ focus(Client *c) { + detachstack(c); + attachstack(c); + grabbuttons(c, True); +- XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); ++ XSetWindowBorder(dpy, c->win, dc.sel[ColBorder].pixel); + setfocus(c); + } + else +@@ -926,14 +923,14 @@ getatomprop(Client *c, Atom prop) { + return atom; + } + +-unsigned long ++XftColor + getcolor(const char *colstr) { +- Colormap cmap = DefaultColormap(dpy, screen); +- XColor color; ++ XftColor color; + +- if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) ++ if(!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), colstr, &color)) + die("error, cannot allocate color '%s'\n", colstr); +- return color.pixel; ++ ++ return color; + } + + Bool +@@ -1034,35 +1031,13 @@ incnmaster(const Arg *arg) { + + void + initfont(const char *fontstr) { +- char *def, **missing; +- int n; + +- dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); +- if(missing) { +- while(n--) +- fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); +- XFreeStringList(missing); +- } +- if(dc.font.set) { +- XFontStruct **xfonts; +- char **font_names; +- +- dc.font.ascent = dc.font.descent = 0; +- XExtentsOfFontSet(dc.font.set); +- n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); +- while(n--) { +- dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); +- dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent); +- xfonts++; +- } +- } +- else { +- if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) +- && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) +- die("error, cannot load font: '%s'\n", fontstr); +- dc.font.ascent = dc.font.xfont->ascent; +- dc.font.descent = dc.font.xfont->descent; +- } ++ if(!(dc.font.xfont = XftFontOpenName(dpy,screen,fontstr)) ++ && !(dc.font.xfont = XftFontOpenName(dpy,screen,"fixed"))) ++ die("error, cannot load font: '%s'\n", fontstr); ++ ++ dc.font.ascent = dc.font.xfont->ascent; ++ dc.font.descent = dc.font.xfont->descent; + dc.font.height = dc.font.ascent + dc.font.descent; + } + +@@ -1144,7 +1119,7 @@ manage(Window w, XWindowAttributes *wa) { + + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); +- XSetWindowBorder(dpy, w, dc.norm[ColBorder]); ++ XSetWindowBorder(dpy, w, dc.norm[ColBorder].pixel); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); +@@ -1621,8 +1596,6 @@ setup(void) { + dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); + dc.gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); +- if(!dc.font.set) +- XSetFont(dpy, dc.gc, dc.font.xfont->fid); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1692,13 +1665,9 @@ tagmon(const Arg *arg) { + + int + textnw(const char *text, unsigned int len) { +- XRectangle r; +- +- if(dc.font.set) { +- XmbTextExtents(dc.font.set, text, len, NULL, &r); +- return r.width; +- } +- return XTextWidth(dc.font.xfont, text, len); ++ XGlyphInfo ext; ++ XftTextExtentsUtf8(dpy, dc.font.xfont, (XftChar8 *) text, len, &ext); ++ return ext.xOff; + } + + void +@@ -1776,7 +1745,7 @@ unfocus(Client *c, Bool setfocus) { + if(!c) + return; + grabbuttons(c, False); +- XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]); ++ XSetWindowBorder(dpy, c->win, dc.norm[ColBorder].pixel); + if(setfocus) + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + } diff --git a/dwm.suckless.org/patches/dwm-6.1-xft-with-fallback-font.diff b/dwm.suckless.org/patches/historical/dwm-6.1-xft-with-fallback-font.diff diff --git a/dwm.suckless.org/patches/dwm-cdec978-center.diff b/dwm.suckless.org/patches/historical/dwm-cdec978-center.diff diff --git a/dwm.suckless.org/patches/dwm-r1508-focusonclick.diff b/dwm.suckless.org/patches/historical/dwm-git-20100321-focusonclick.diff diff --git a/dwm.suckless.org/patches/historical/dwm-master_2015-10-20_7e1182c-pertag-tab-v2b.diff b/dwm.suckless.org/patches/historical/dwm-master_2015-10-20_7e1182c-pertag-tab-v2b.diff @@ -0,0 +1,692 @@ +diff --git a/config.def.h b/config.def.h +index 3fde3cf..ef6d4d3 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,10 +15,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 +@@ -32,7 +44,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 */ +@@ -62,6 +74,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 } }, +@@ -109,5 +122,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..077d92b 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 96b43f7..c0aab5d 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,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 { +@@ -111,25 +111,35 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ ++typedef struct Pertag Pertag; + 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 { +@@ -164,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); +@@ -206,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 *); +@@ -240,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 +285,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 */ ++ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */ ++}; ++ + /* 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 +@@ -497,6 +543,8 @@ cleanupmon(Monitor *mon) { + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -516,6 +564,7 @@ void + clientmessage(XEvent *e) { + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); ++ int i; + + if(!c) + return; +@@ -528,6 +577,8 @@ clientmessage(XEvent *e) { + if(!ISVISIBLE(c)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; ++ for(i=0; !(c->tags & 1 << i); i++); ++ view(&(Arg){.ui = 1 << i}); + } + pop(c); + } +@@ -565,8 +616,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); + } +@@ -629,16 +683,41 @@ configurerequest(XEvent *e) { + Monitor * + createmon(void) { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; +- m->lt[0] = &layouts[0]; ++ m->toptab = toptab; ++ m->ntabs = 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] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ ++ /* swap focus and zoomswap*/ ++ m->pertag->prevzooms[i] = NULL; ++ } + return m; + } + +@@ -749,6 +828,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; +@@ -772,8 +949,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 +@@ -800,6 +979,7 @@ focus(Client *c) { + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + void +@@ -850,6 +1030,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; +@@ -957,7 +1150,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); + } + +@@ -1215,12 +1408,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); +@@ -1328,6 +1523,7 @@ restack(Monitor *m) { + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if(!m->sel) + return; + if(m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1469,10 +1665,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); +@@ -1490,7 +1689,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); + } + +@@ -1511,6 +1710,8 @@ setup(void) { + if (!drw->fontcount) + die("no fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; ++ + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1635,13 +1836,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; +@@ -1671,9 +1882,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); + } +@@ -1745,20 +1976,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 +@@ -1967,11 +2221,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); + } +@@ -1997,7 +2273,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/historical/dwm-master_2015-10-20_7e1182c-tab-v2b.diff b/dwm.suckless.org/patches/historical/dwm-master_2015-10-20_7e1182c-tab-v2b.diff @@ -0,0 +1,506 @@ +diff --git a/config.def.h b/config.def.h +index 3fde3cf..6a7ad0f 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,6 +15,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" }; +@@ -32,7 +39,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 */ +@@ -62,6 +69,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 } }, +@@ -109,5 +117,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..f736591 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 96b43f7..585dd7b 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,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 { +@@ -111,24 +111,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]; + }; + +@@ -164,12 +172,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); +@@ -206,6 +217,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 *); +@@ -240,6 +252,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 +@@ -497,6 +531,8 @@ cleanupmon(Monitor *mon) { + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -565,8 +601,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); + } +@@ -635,7 +674,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); +@@ -749,6 +791,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; +@@ -772,8 +912,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 +@@ -800,6 +942,7 @@ focus(Client *c) { + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + void +@@ -850,6 +993,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; +@@ -1215,12 +1371,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); +@@ -1328,6 +1486,7 @@ restack(Monitor *m) { + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if(!m->sel) + return; + if(m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1511,6 +1670,8 @@ setup(void) { + if (!drw->fontcount) + die("no fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; ++ + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1642,6 +1803,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; +@@ -1745,20 +1916,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 +@@ -1997,7 +2191,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/historical/dwm-r1525-warp.diff b/dwm.suckless.org/patches/historical/dwm-r1525-warp.diff @@ -1,99 +0,0 @@ -diff -r c361034c5a1c dwm.c ---- a/dwm.c Sat Sep 11 19:00:18 2010 +0000 -+++ b/dwm.c Sat Sep 11 21:47:56 2010 +0200 -@@ -236,6 +236,7 @@ - static void updatetitle(Client *c); - static void updatewmhints(Client *c); - static void view(const Arg *arg); -+static void warp(const Client *c); - static Client *wintoclient(Window w); - static Monitor *wintomon(Window w); - static int xerror(Display *dpy, XErrorEvent *ee); -@@ -274,6 +275,7 @@ - static DC dc; - static Monitor *mons = NULL, *selmon = NULL; - static Window root; -+static Bool warpmouse = True; - - /* configuration, allows nested code to access above variables */ - #include "config.h" -@@ -452,10 +454,12 @@ - focus(c); - click = ClkClientWin; - } -+ warpmouse = False; - 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); -+ warpmouse = True; - } - - void -@@ -854,6 +858,7 @@ - unfocus(selmon->sel, True); - selmon = m; - focus(NULL); -+ warp(selmon->sel); - } - - void -@@ -879,6 +884,7 @@ - if(c) { - focus(c); - restack(selmon); -+ warp(c); - } - } - -@@ -1150,6 +1156,7 @@ - XMapWindow(dpy, c->win); - setclientstate(c, NormalState); - arrange(c->mon); -+ warp(c); - } - - void -@@ -1609,6 +1616,7 @@ - if(selmon->sel && arg->ui & TAGMASK) { - selmon->sel->tags = arg->ui & TAGMASK; - arrange(selmon); -+ warp(selmon->sel); - } - } - -@@ -1689,6 +1697,7 @@ - if(newtags) { - selmon->sel->tags = newtags; - arrange(selmon); -+ warp(selmon->sel); - } - } - -@@ -1962,6 +1971,26 @@ - arrange(selmon); - } - -+void -+warp(const Client *c) { -+ Window dummy; -+ int x, y, di; -+ unsigned int dui; -+ -+ if(!c || !warpmouse) -+ return; -+ XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui); -+ if(x > c->x && y > c->y && x < c->y + c->w && y < c->y + c->h) -+ return; -+ XSelectInput(dpy, root, SubstructureRedirectMask -+ & EnterWindowMask); -+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, -+ c->w / 2, c->h / 2); -+ XSelectInput(dpy, root, SubstructureRedirectMask | SubstructureNotifyMask -+ | EnterWindowMask | LeaveWindowMask | StructureNotifyMask); -+} -+ -+ - Client * - wintoclient(Window w) { - Client *c; diff --git a/dwm.suckless.org/patches/dwm-r1578-pertag.diff b/dwm.suckless.org/patches/historical/dwm-r1578-pertag.diff diff --git a/dwm.suckless.org/patches/historical/push-5.3.c b/dwm.suckless.org/patches/historical/push-5.3.c @@ -1,56 +0,0 @@ -static Client * -prevtiled(Client *c) { - Client *p, *r; - - for (p = clients, r = NULL; p && p != c; p = p->next) - if (!p->isfloating && ISVISIBLE(p)) - r = p; - return r; -} - -static void -pushup(const Arg *arg) { - Client *c; - - if (!sel || sel->isfloating) - return; - if ((c = prevtiled(sel))) { - /* attach before c */ - detach(sel); - sel->next = c; - if (clients == c) - clients = sel; - else { - for (c = clients; c->next != sel->next; c = c->next); - c->next = sel; - } - } else { - /* move to the end */ - for (c = sel; c->next; c = c->next); - detach(sel); - sel->next = NULL; - c->next = sel; - } - focus(sel); - arrange(); -} - -static void -pushdown(const Arg *arg) { - Client *c; - - if (!sel || sel->isfloating) - return; - if ((c = nexttiled(sel->next))) { - /* attach after c */ - detach(sel); - sel->next = c->next; - c->next = sel; - } else { - /* move to the front */ - detach(sel); - attach(sel); - } - focus(sel); - arrange(); -} diff --git a/dwm.suckless.org/patches/historical/push-5.6.c b/dwm.suckless.org/patches/historical/push-5.6.c @@ -1,58 +0,0 @@ -static Client * -prevtiled(Client *c) { - Client *p, *r; - - for(p = selmon->clients, r = NULL; p && p != c; p = p->next) - if(!p->isfloating && ISVISIBLE(p)) - r = p; - return r; -} - -static void -pushup(const Arg *arg) { - Client *sel = selmon->sel; - Client *c; - - if(!sel || sel->isfloating) - return; - if((c = prevtiled(sel))) { - /* attach before c */ - detach(sel); - sel->next = c; - if(selmon->clients == c) - selmon->clients = sel; - else { - for(c = selmon->clients; c->next != sel->next; c = c->next); - c->next = sel; - } - } else { - /* move to the end */ - for(c = sel; c->next; c = c->next); - detach(sel); - sel->next = NULL; - c->next = sel; - } - focus(sel); - arrange(); -} - -static void -pushdown(const Arg *arg) { - Client *sel = selmon->sel; - Client *c; - - if(!sel || sel->isfloating) - return; - if((c = nexttiled(sel->next))) { - /* attach after c */ - detach(sel); - sel->next = c->next; - c->next = sel; - } else { - /* move to the front */ - detach(sel); - attach(sel); - } - focus(sel); - arrange(); -} diff --git a/dwm.suckless.org/patches/historical/xft.md b/dwm.suckless.org/patches/historical/xft.md @@ -0,0 +1,44 @@ +xft +=== + +Description +----------- + +The `xft` patch patch implements Xft. This allows users to utilize the UTF8 +character set. Look at the patch below which is more advance. + +The `xft-with-fallback-font` patch adds Xft and fallback-font support to dwm. +This patch was built on top of the [Xft patch written by +Quentin](http://lists.suckless.org/dev/1311/18279.html). With fallback font +support, multiple fonts can now be specified in config.h which are used to +render characters not present in the first font. If none of the user-specified +fonts contains a given character, this patch attempts to automatically fallback +to whatever suitable font it can find on the host system. +**NOTE: This is enabled by default when you are using the latest dwm-git.** + +With this patch, the "font" variable in config.h is superseded by the "fonts" +variable which is a priority-ordered list of fonts that should be used to +render text. Here's an example "fonts" definition: + + static const char *fonts[] = { + "Sans:size=10.5", + "VL Gothic:size=10.5", + "WenQuanYi Micro Hei:size=10.5", + }; + +At least one font must be specified, and a maximum of `DRW_FONT_CACHE_SIZE` +fonts can be used. + + +Download +-------- +* [dwm-6.0-xft.diff](historical/dwm-6.0-xft.diff) (6.6k) (16 May 2012) + * memory leak fixed and improved implementation. + * include config.def.h and config.mk changes. + +* [dwm-6.1-xft-with-fallback-font.diff](historical/dwm-git-20150228-xft-with-fallback-font.diff) (20k) + +Author +------ +* Lee Fallat (lf94)<ircsurfer33@gmail.com> +* [Eric Pruitt](https://github.com/ericpruitt/) diff --git a/dwm.suckless.org/patches/horizgrid.md b/dwm.suckless.org/patches/horizgrid.md @@ -0,0 +1,37 @@ +horizontal grid +=============== + +Description +----------- +This patch is a variant of [gapless_grid](gapless_grid). It arranges windows in a grid pattern in which every window is roughly the same size, adjusted such that there are no gaps. However, this layout arranges the windows in a horizontal grid, rather than a vertical grid. + +Horizontal Grid Layout +---------------------- + + horizgrid (###) + +--------+--------+ + | | | + | | | + +-----+--+--+-----+ + | | | | + | | | | + +-----+-----+-----+ + + gapless_grid + +--------+--------+ + | | | + | +--------+ + +--------+ | + | +--------+ + | | | + +--------+--------+ + +Download +-------- + + * [dwm-6.1-horizgrid.diff](dwm-6.1-horizgrid.diff) (20160108) + +Authors +------- + + * Marshall Mason - `<marshallmason2@gmail.com>` diff --git a/dwm.suckless.org/patches/index.md b/dwm.suckless.org/patches/index.md @@ -1,6 +1,18 @@ Patches ======= +There are two types of patches: The ones that fit to your personal taste and +the ones you think should be included in mainline dwm. + +For patches that should be included in mainline dwm see the +[community](//suckless.org/community) page and the hackers@ mailing list. + + +You can use the following instructions to generate and apply patches posted on +this wiki. On how to upload patches which fit your personal taste and you want +to show the community, see the [wiki](//suckless.org/wiki) page on how to edit +the pages you see here. + diff generation --------------- For git users: @@ -15,10 +27,9 @@ For tarballs: where `X.Y` is a dwm tag name or version number. - patch application ----------------- -For git users: +For git users, use `-3` to fix the conflict easily: cd dwm-directory git apply path/to/patch.diff diff --git a/dwm.suckless.org/patches/keycode.md b/dwm.suckless.org/patches/keycode.md @@ -1,12 +1,14 @@ Keycode ======== With this patch, handling key input is done with keycodes instead of keysyms. -This way, input is keyboard layout independant (adapt config.h to your keyboard using for exemple xev). +This way, input is keyboard layout independant (adapt config.h to your keyboard +using for exemple xev). Download -------- * [dwm-6.0-keycode.diff](dwm-6.0-keycode.diff) +* [dwm-20151110-5ed9c48-keycode.patch](dwm-20151110-5ed9c48-keycode.patch) Author ------ -* Quentin Rameau <quinq@quinq.eu.org> +* Quentin Rameau <quinq@fifth.space> diff --git a/dwm.suckless.org/patches/mark.md b/dwm.suckless.org/patches/mark.md @@ -0,0 +1,38 @@ + +Mark +==== + +Description +----------- + +This patch provides an mechanism to easily jump between any clients, or to swap any clients through shortcuts by introcuding mark. The mark is global, and only one mark is allowed at the same time. The marked client is distinguished from other clients by having a different border color. +This patch adds 3 functions and 2 variables: +* functions: + togglemark - mark/unmark current focused client. + swapclient - swap focused client with marked client, falls back to + zoom() if the mark is not being set. + swapfocus - swap focus with mark. +* variables: + normmarkcolor - border color for marked client. + selmarkcolor - border color for current focused client that is + also being marked. +And example of key mappings for this patch: + { MODKEY, XK_semicolon,togglemark, {0} }, + { MODKEY, XK_o, swapfocus, {0} }, + { MODKEY, XK_Return, swapclient, {0} }, +/*togglemark twice to remove the mark, emulates the behaviour of zoom()*/ + { MODKEY, XK_Return, togglemark, {0} }, + { MODKEY, XK_Return, togglemark, {0} }, + { MODKEY, XK_u, swapclient, {0} }, +/*swapclient and swapfocus at the same time, it's useful in some cases*/ + { MODKEY, XK_i, swapclient, {0} }, + { MODKEY, XK_i, swapfocus, {0} }, + +Download +-------- + +* [dwm-6.1-mark.diff](dwm-6.1-mark.diff) (7161b) (20160220) + +Author +------ +* phi <crispyforg@163.com> diff --git a/dwm.suckless.org/patches/movestack.md b/dwm.suckless.org/patches/movestack.md @@ -23,8 +23,8 @@ movestack(-1) will swap the client with the current focus with the previous clie ## Download - * [dwm-5.6.1-movestack.diff][1] (2.4k) (20090911) * [dwm-5.8.2-movestack.diff](movestack-5.8.2.diff) (2.6k) (20101102) + * [dwm-5.6.1-movestack.diff][1] (2.4k) (20090911) ## Author diff --git a/dwm.suckless.org/patches/noborder.md b/dwm.suckless.org/patches/noborder.md @@ -13,7 +13,7 @@ Download Patches against different versions of dwm are available at [dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). - * [dwm-6.1-single_window_no_border.diff](dwm-6.1-single_window_no_border.diff) (3025b) (20140209) + * [dwm-6.1-single_window_no_border.diff](dwm-6.1-single_window_no_border.diff) (3047b) (20151111) * [dwm-10e232f9ace7-statusallmons.diff](dwm-10e232f9ace7-statusallmons.diff) (982b) (20120406) * [dwm-6.0-single_window_no_border.diff](dwm-6.0-single_window_no_border.diff) (2865b) (20120406) diff --git a/dwm.suckless.org/patches/pertag.md b/dwm.suckless.org/patches/pertag.md @@ -11,12 +11,10 @@ Download Patches against different versions of dwm are available at [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.1-pertag.diff](dwm-6.1-pertag.diff) (6.4K) (20151109) + * [dwm-git-20120406-pertag.diff](dwm-git-20120406-pertag.diff) (5955b) * [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] * [dwm-5.8.2-pertag.diff][7] * [dwm-5.7.2-pertag.diff][6] * [dwm-pertag-5.6.1.diff][5] @@ -24,6 +22,11 @@ Patches against different versions of dwm are available at * [dwm-5.2-pertag.diff][3] * [dwm-5.1-pertag.diff][2] + * Using pertag but with the same barpos + * [dwm-6.1-pertag_without_bar.diff](dwm-6.1-pertag_without_bar.diff) (5.2K) (20151109) + * [dwm-6.0-pertag_without_bar.diff](dwm-6.0-pertag_without_bar.diff) (5578b) (20140530) + * [dwm-5.8.2-pertag\_without\_bar.diff][8] + Authors ------- * Jan Christoph Ebersbach - <jceb@e-jc.de> @@ -32,6 +35,7 @@ Authors * Updated by Sidney Amani - `<seed at uffs dot org>` * Updated by William Light - `<wrl at illest dot net>` * Updated by termac - `<terror.macbeth.I at gmail dot com>` + * Updated by Ivan Tham - `pickfire at riseup dot net` [1]: historical/taglayouts [2]: http://v4hn.de/patches/dwm-5.1-pertag.diff @@ -39,6 +43,6 @@ Authors [4]: historical/dwm-5.4-pertag.diff [5]: historical/dwm-pertag-5.6.1.diff [6]: historical/dwm-5.7.2-pertag.diff -[7]: dwm-5.8.2-pertag.diff -[8]: dwm-5.8.2-pertag_without_bar.diff -[9]: dwm-r1578-pertag.diff +[7]: historical/dwm-5.8.2-pertag.diff +[8]: historical/dwm-5.8.2-pertag_without_bar.diff +[9]: historical/dwm-r1578-pertag.diff diff --git a/dwm.suckless.org/patches/push.c b/dwm.suckless.org/patches/push.c @@ -1,58 +0,0 @@ -static Client * -prevtiled(Client *c) { - Client *p, *r; - - for(p = selmon->clients, r = NULL; p && p != c; p = p->next) - if(!p->isfloating && ISVISIBLE(p)) - r = p; - return r; -} - -static void -pushup(const Arg *arg) { - Client *sel = selmon->sel; - Client *c; - - if(!sel || sel->isfloating) - return; - if((c = prevtiled(sel))) { - /* attach before c */ - detach(sel); - sel->next = c; - if(selmon->clients == c) - selmon->clients = sel; - else { - for(c = selmon->clients; c->next != sel->next; c = c->next); - c->next = sel; - } - } else { - /* move to the end */ - for(c = sel; c->next; c = c->next); - detach(sel); - sel->next = NULL; - c->next = sel; - } - focus(sel); - arrange(selmon); -} - -static void -pushdown(const Arg *arg) { - Client *sel = selmon->sel; - Client *c; - - if(!sel || sel->isfloating) - return; - if((c = nexttiled(sel->next))) { - /* attach after c */ - detach(sel); - sel->next = c->next; - c->next = sel; - } else { - /* move to the front */ - detach(sel); - attach(sel); - } - focus(sel); - arrange(selmon); -} diff --git a/dwm.suckless.org/patches/push.md b/dwm.suckless.org/patches/push.md @@ -8,8 +8,8 @@ static Key keys[] = { ... - { MODKEY|ControlMask, XK_j, pushdown, {0} }, - { MODKEY|ControlMask, XK_k, pushup, {0} }, + { MODKEY|ControlMask, XK_j, pushdown, {0} }, + { MODKEY|ControlMask, XK_k, pushup, {0} }, `push_no_master` is the same as the regular `push` patch, but it does not push up nor push down into the master area. We have zoom() for that. @@ -17,13 +17,10 @@ Patches against different versions of dwm are available at [dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). - * [dwm-6.1-push.diff](dwm-6.1-push.diff) (1402b) (20140209) - * [dwm-10e232f9ace7-push.diff](dwm-10e232f9ace7-push.diff) (1332b) (20120406) - * [dwm-6.0-push.diff](dwm-6.0-push.diff) (1332b) (20120406) + * [dwm-6.0-push.diff](dwm-6.0-push.diff) (1332b) - 2012/4/6 * [dwm-6.0-push_no_master.diff](dwm-6.0-push_no_master.diff) - * [push.c](push.c) (dwm 5.7.1) (20090927) - * [push-5.6.c](historical/push-5.6.c) (1K) (20090709) - * [push-5.3.c](historical/push-5.3.c) (1K) (20090124) + * [dwm-6.1-push.diff](dwm-6.1-push.diff) (1402b) - 2014/2/9 + * [dwm-6.1-push_no_master.diff](dwm-6.1-push_no_master.diff) - 2015/11/21 ## Note This patch seems to be equivalent to the [movestack](movestack) patch. diff --git a/dwm.suckless.org/patches/resizecorners.md b/dwm.suckless.org/patches/resizecorners.md @@ -6,8 +6,10 @@ By default, windows only from the bottom right corner. With this Patch, the mous ## Download + * [dwm-6.1-resizecorners.diff](dwm-6.1-resizecorners.diff) (17.02.2016) * [dwm-6.0-resizecorners.diff](dwm-6.0-resizecorners.diff) (12.05.2015) ## Author * dusty - <dusty@teknik.io> + * Klemens Nanni <[kl3@posteo.org](mailto:kl3@posteo.org)> (6.1 version) diff --git a/dwm.suckless.org/patches/statuscolors.md b/dwm.suckless.org/patches/statuscolors.md @@ -19,7 +19,7 @@ Add code to your status script to output the raw characters '\x03' to switch to The following definition in 'config.h': #define NUMCOLORS 4 - static const char colors[NUMCOLORS][ColLast][8] = { + static const char colors[NUMCOLORS][MAXCOLORS][8] = { // border foreground background { "#000033", "#dddddd", "#000033" }, // normal { "#000088", "#ffffff", "#000088" }, // selected diff --git a/dwm.suckless.org/patches/swallow.md b/dwm.suckless.org/patches/swallow.md @@ -0,0 +1,34 @@ +# terminals swallow windows + +## Description + +This patch adds "window swallowing" to dwm, a la `rio` from Plan 9. + +Windows that are marked with the `isterminal` flag (settable using rules in `config.h`) will swallow a window opened by any descendant processes. +For example, if you open a terminal and then in that terminal type `xclock`, the `xclock` window takes the place of that terminal window. +Closing the `xclock` window restores the terminal window in the current position. + +This patch is useful for users who tend to do most or all of their work from the command line, but sometimes need to use a graphical program. +This patch avoids cluttering the desktop with unused terminals. + +(`dmenu` could be used, but if you are deep in a directory hierarchy and want to, say, view a PDF, cutting and pasting the path to `dmenu` takes longer than just running `mupdf`.) + +## Download +Please see [deadpixi-dwm](https://github.com/deadpixi/deadpixi-dwm) for the development site. + +Patches are also available here: + + * [dwm-6.1-swallowing.diff](dwm-6.1-swallowing.diff) (9319b) - 2016/1/27 + +## Note +The window swallowing functionality requires `dwm` to walk the process tree, which is an inherently OS-specific task. +Only Linux is supported at this time. +Please contact the author (jking@deadpixi.com) if you would like to help expand the list of supported operating systems. + +Also please note that building with this patch requires `libxcb`, `Xlib-libxcb`, and `xcb-res`. +This is due to the use of the latest revision of the X Resource Extension, which is unsupported in vanilla Xlib. + +Only terminals created by local processes can swallow windows, and only windows created by local processes can be swallowed. + +## Author + * Rob King <jking@deadpixi.com> diff --git a/dwm.suckless.org/patches/systray.md b/dwm.suckless.org/patches/systray.md @@ -11,12 +11,13 @@ Download Patches against different versions of dwm are available at [dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). - * [dwm-14343e69cc59-systray.diff](dwm-14343e69cc59-systray.diff) () (20150808) - * [dwm-6.1-systray.diff](dwm-6.1-systray.diff) (21630b) (20140209) - * [dwm-c794a9f5ae5e-systray.diff](dwm-c794a9f5ae5e-systray.diff) (19946b) (20130119) + * [dwm-git-20160103-systray.diff](dwm-git-20160103-systray.diff) (3465bed) + * [dwm-6.1-systray.diff](dwm-6.1-systray.diff) (22K) (20151109) + * [dwm-git-20130119-systray.diff](dwm-git-20130119-systray.diff]) (19946b) * [dwm-6.0-systray.diff](dwm-6.0-systray.diff) (19788b) (20130119) Author ------ * Jan Christoph Ebersbach <jceb@e-jc.de> * Eon S. Jeon <esjeon@hyunmu.am> (14343e69cc59) + * David Phillips (5ed9c48 (6.1), and 20160103) diff --git a/dwm.suckless.org/patches/tab.md b/dwm.suckless.org/patches/tab.md @@ -134,6 +134,7 @@ Download Old versions + * [dwm-master\_2015-10-20\_7e1182c-tab-v2b.diff](historical/dwm-master\_2015-10-20\_7e1182c-tab-v2b.diff), [dwm-master\_2015-10-20\_7e1182c-pertag-tab-v2b.diff](historical/dwm-master\_2015-10-20\_7e1182c-pertag-tab-v2b.diff) * [dwm-master\_2015-03-05\_14343e-tab-v2b.diff](historical/dwm-master\_2015-03-05\_14343e-tab-v2b.diff), [dwm-master\_2015-03-05\_14343e-pertag-tab-v2b.diff](historical/dwm-master\_2015-03-05\_14343e-pertag-tab-v2b.diff) * [dwm-6.0-tab-v2b.diff](historical/dwm-6.0-tab-v2b.diff), [dwm-6.0-pertag-tab-v2b.diff](historical/dwm-6.0-pertag-tab-v2b.diff) * [dwm-master\_2013-08-27\_cdec978-tab-v2a.diff](historical/dwm-master_2013-08-27_cdec978-tab-v2a.diff), [dwm-master\_2013-08-27\_cdec978-pertag-tab-v2a.diff](historical/dwm-master_2013-08-27_cdec978-pertag-tab-v2a.diff) diff --git a/dwm.suckless.org/patches/urgentborder.md b/dwm.suckless.org/patches/urgentborder.md @@ -8,8 +8,8 @@ Use config.h item "urgbordercolor" to change it. ## Download - * [dwm-6.1-make-the-borders-of-urgent-windows-a-different-color.diff](dwm-6.1-make-the-borders-of-urgent-windows-a-different-color.diff) (2.2K) (20150307) - + * [dwm-6.1-urg-border.diff](dwm-6.1-urg-border.diff) (2.2K) (20150307) + ## Author * Alexander Huemer - alexander dot huemer dot xx dot vu (Based on former work by Ray Kohler - ataraxia937 gmail com) diff --git a/dwm.suckless.org/patches/warp.md b/dwm.suckless.org/patches/warp.md @@ -4,19 +4,20 @@ warp Description ----------- -This patch warps the mouse cursor each time another window gets focused to the -middle of the window. +This patch warps the mouse cursor to the center of the currently focused window +or screen when the mouse cursor is (a) on a different screen or (b) on top of a +different window. Download -------- -* [dwm-5.9-warp.diff](dwm-5.9-warp.diff) (1.3k) (20111028) -* [dwm-r1525-warp.diff](historical/dwm-r1525-warp.diff) (2.3k) (20100911) - In the patch for r1525, there is a problem with this caused by `XSelectInput`, causing the - statusbar to freeze. Interestingly, the [stdin](stdin) patch works around this. +* [dwm-5.9-warp.diff](dwm-5.9-warp.diff) (20111028) +* [dwm-6.1-warp.diff](dwm-6.1-warp.diff) (20151215) Author ------ * Evan Gates (emg) <evan.gates@gmail.com> * Enno Boland (Gottox) +* Jochen Sprickerhof +* Winston Weinert (winny) <winston@ml1.net> diff --git a/dwm.suckless.org/patches/xft-with-fallback-fonts.md b/dwm.suckless.org/patches/xft-with-fallback-fonts.md @@ -1,36 +0,0 @@ -Xft With Fallback-Font Support -============================== - -Description ------------ - -Adds Xft and fallback-font support to dwm. This patch was built on top of the -[Xft patch written by Quentin](http://lists.suckless.org/dev/1311/18279.html). -With fallback font support, multiple fonts can now be specified in config.h -which are used to render characters not present in the first font. If none of -the user-specified fonts contains a given character, this patch attempts to -automatically fallback to whatever suitable font it can find on the host -system. - -With this patch, the "font" variable in config.h is superseded by the "fonts" -variable which is a priority-ordered list of fonts that should be used to -render text. Here's an example "fonts" definition: - - static const char *fonts[] = { - "Sans:size=10.5", - "VL Gothic:size=10.5", - "WenQuanYi Micro Hei:size=10.5", - }; - -At least one font must be specified, and a maximum of `DRW_FONT_CACHE_SIZE` -fonts can be used. - -Download --------- - -* [dwm-6.1-xft-with-fallback-font.diff](dwm-6.1-xft-with-fallback-font.diff) (20k) (2015-02-28) - -Author ------- - -* [Eric Pruitt](https://github.com/ericpruitt/) diff --git a/dwm.suckless.org/patches/xft.md b/dwm.suckless.org/patches/xft.md @@ -1,19 +0,0 @@ -xft -=== - -Description ------------ - -This patch implements Xft. This allows users to utilize the UTF8 character set. - -Download --------- - -* [dwm-6.0-xft.diff](dwm-6.0-xft.diff) (6.6k) (16 May 2012) - * memory leak fixed and improved implementation. - - -Author ------- - -* Lee Fallat (lf94)<ircsurfer33@gmail.com> diff --git a/dwm.suckless.org/scripts/simple_monitors.md b/dwm.suckless.org/scripts/simple_monitors.md @@ -12,10 +12,16 @@ Battery Your battery may be called something different, so check /proc/acpi for its name. Also, change 89000 to whatever the capacity is for your battery. This returns the remaining battery power as a percentage. - $(echo $(awk '/rem/ { print $3/89000 }' /proc/acpi/battery/BAT0/state| hoc| cut -c3,4)% + $(echo $(awk '/rem/ { print $3/89000 }' /proc/acpi/battery/BAT0/state| hoc| cut -c3,4)% hoc comes from plan9port or 9base. +Depending on your system, you can also use + + cat /sys/class/power_supply/BAT0/capacity + +to get your battery status in percentage. + Ram used --- @@ -33,7 +39,7 @@ Returns the temperature of the cpu, in celcius. Volume --- - amixer get Front | tail -1 | sed 's/.*\[\([0-9]*%\)\].*/\1/' + amixer get Front | tail -n1 | awk '{ print $5 }' | tr -d [] Change "Front" to your audio device diff --git a/dwm.suckless.org/tutorial.md b/dwm.suckless.org/tutorial.md @@ -1,3 +1,8 @@ +Launching +--------- + +To launch dwm, ideally you should setup a `~/.xinitrc` with at least `exec dwm`. + Introduction ------------ @@ -14,21 +19,40 @@ By default there are 9 tags. Window model ------------ -Launch a few terminals `[Shift]+[Alt]+[Enter]` and dwm will _tile_ the windows +Launch a few terminals with `[Shift]+[Alt]+[Enter]` and dwm will _tile_ the windows between the **master** and **stack**. A new terminal appears on the **master** window. Existing windows are pushed upon a **stack** to the right of the screen. `[Alt]+[Enter]` toggles windows between master and stack. -To move a terminal pane/tile/window to another tag you select the window by -hovering over the window. Then execute the bind `[Shift]+[Alt]+[2]` to move the -window to the 2 tag. `[Alt]+[2]` moves your focus to tag 2. + +------+----------------------------------+--------+ + | tags | title | status + + +------+---------------------+------------+--------+ + | | | + | | | + | | | + | | | + | master | stack | + | | | + | | | + | | | + | | | + +----------------------------+---------------------+ + +Moving Around +------------- + +To **move to another terminal**, press `[Alt]+[j]` or `[Alt]+[k]`. + +To **move a terminal to another _tag_**, hover to the terminal and press `[Shift]+[Alt]+[2]`. + +To **focus on another _tag_**, press `[Alt]+[tag number]`. + +To **move a terminal to master or stack**, press `[Alt]+[d]` or `[Alt]+[i]`. As stated in the dwm manpage, you can click tags with the left mouse button and simulating `[Alt]+[tag number]`, but you can also click another tag with the right mouse button in order to bring those windows additionally into your current focus. -To kill a window: - - [Shift]+[Alt]+[c] +To **kill a window**, press `[Shift]+[Alt]+[c]`. Layouts ------- @@ -82,14 +106,7 @@ Using the tools of X.org, this can be set using: % xsetroot -name "Some Text" There are various tools and methods to populate this text with useful -information from your system or services running on your system. A barebone -for doing this in C is [dwmstatus](http://dwm.suckless.org/dwmstatus/). -See the [xinitrc](http://dwm.suckless.org/xinitrc.example) -example for how to do it using a script. - -Launching ---------- - -To launch dwm, ideally you should setup an -[xinitrc](http://dwm.suckless.org/xinitrc.example). - +information from your system or services running on your system. A barebone for +doing this in C is [dwmstatus](http://dwm.suckless.org/dwmstatus/). See the +[xinitrc](http://dwm.suckless.org/xinitrc.example) example for how to do it +using a script. diff --git a/st.suckless.org/index.md b/st.suckless.org/index.md @@ -31,7 +31,7 @@ be implemented or fixed. What has been implemented: -* 256 colors +* 256 colors and [true colors](https://gist.github.com/XVilka/8346728) * most VT10X escape sequences * utf8 * X11 copy/paste diff --git a/st.suckless.org/patches/1clipboard.diff b/st.suckless.org/patches/1clipboard.diff @@ -1,14 +0,0 @@ -diff --git a/st.c b/st.c -index bb64c55..5ff1a36 100644 ---- a/st.c -+++ b/st.c -@@ -1155,6 +1155,9 @@ xsetsel(char *str, Time t) { - XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); - if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) - selclear(0); -+ -+ clipcopy(NULL); -+ - } - - void diff --git a/st.suckless.org/patches/1clipboard.md b/st.suckless.org/patches/1clipboard.md @@ -1,25 +0,0 @@ -# One clipboard - -## Description - -<abbr title="simple terminal">st</abbr> since [March 2015 only sets PRIMARY on -selection](http://git.suckless.org/st/commit/?id=28259f5750f0dc7f52bbaf8b746ec3dc576a58ee), -in accordance to the [Freedesktop -standard](http://standards.freedesktop.org/clipboards-spec/clipboards-latest.txt). - -However I don't like this <abbr title="User eXperience">UX</abbr>. I don't like -having to think about two clipboards. I don't like having to use typically -three key combination to copy my selected text into the clipboard used by my -browser. - -## Download - -* [1clipboard.diff](1clipboard.diff) - -or - -Append `clipcopy(NULL);` to the end of the xsetsel function in [st.c](http://git.suckless.org/st/tree/st.c). - -## Author - -[Kai Hendry](http://hendry.iki.fi/) diff --git a/st.suckless.org/patches/argbbg.md b/st.suckless.org/patches/argbbg.md @@ -5,21 +5,22 @@ argbbg ## 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) +Note that *you need an X composite manager* (e.g. compton, xcompmgr) to +make this patch effective. ## Important Notes ## - The alpha value affects the default background only. - - The color designated by `defaultbg` should not be used elsewhere. + - The color designated by 'defaultbg' should not be used elsewhere. - Embedding might fail after applying this patch. ## Download ## * [st-0.4.1-argbbg.diff](st-0.4.1-argbbg.diff) * [st-0.5-argbbg.diff](st-0.5-argbbg.diff) - * [st-git-20141122-argbbg.diff](st-git-20141122-argbbg.diff) - * [st-git-20150611-argbbg.diff](st-git-20150611-argbbg.diff) + * [st-0.6-argbbg.diff](st-0.6-argbbg.diff) + * [st-git-20160131-argbbg.diff](st-git-20160131-argbbg.diff) ## Authors ## * Eon S. Jeon - esjeon@hyunmu.am * pr - protodev@gmx.net (st-0.5 port) - * Juan Aguilar - aritmeeul@gmail.com (st-git-20141122 port) - * Laslo Hunhold - dev@frign.de (st-git-20150601 port) + * Laslo Hunhold - dev@frign.de (st-0.6 port) + * David Phillips - dbphillipsnz@gmail.com (st-git-20160131 port) diff --git a/st.suckless.org/patches/boldcolor.md b/st.suckless.org/patches/boldcolor.md @@ -4,16 +4,16 @@ boldcolor Description ----------- -This is a hack to allow using different color for bold, italic -or underlined text when the text is in defaultfg color otherwise. +This is a hack allowing to use different colors for bold, italic +and underlined text when the text would be in defaultfg color otherwise. -Makes the special attributes more visible, when no bold or italic -font is available, or the defaultfg is a special color (>255 value). +This makes the special attributes more visible when no bold or italic +font is available or defaultfg is a special color (> 255). Usage ----- -example config.h +config.h example: static const char *colorname[] = { // ... @@ -39,11 +39,9 @@ example config.h Download -------- -* [st-0.3-boldcolor.diff][0] - -[0]: st-0.3-boldcolor.diff +* [st-0.3-boldcolor.diff](st-0.3-boldcolor.diff) Author ------ - * Szabolcs Nagy - nsz + * Szabolcs Nagy - nsz@port70.net diff --git a/st.suckless.org/patches/clipboard.md b/st.suckless.org/patches/clipboard.md @@ -0,0 +1,21 @@ +# clipboard + +## Description + +st only sets PRIMARY on selection since +[March 2015](http://git.suckless.org/st/commit/?id=28259f5750f0dc7f52bbaf8b746ec3dc576a58ee) +according to the +[Freedesktop standard](http://standards.freedesktop.org/clipboards-spec/clipboards-latest.txt). + +This patch brings back the old behaviour, namely additionally setting +CLIPBOARD. + +## Download + +* [st-0.6-clipboard.diff](st-0.6-clipboard.diff) +* [st-git-20150917-clipboard.diff](st-git-20150917-clipboard.diff) + +## Authors + + * Kai Hendry - hendry@iki.fi + * Laslo Hunhold - dev@frign.de (st-git-20150917 port) diff --git a/st.suckless.org/patches/configwordbreak.md b/st.suckless.org/patches/configwordbreak.md @@ -1,29 +0,0 @@ -configwordbreak -=============== - -Description ------------ - -This is a patch to allow configuring which characters are used as -word boundaries for double click selection (instead of just ' '). -This feature is already implemented in all versions later than 0.5. - -Usage ------ - -example config.h - - #define WORD_BREAK " ()<>[]\"" - -Download --------- -* [st-0.3-configwordbreak.diff](st-0.3-configwordbreak.diff) -* [st-0.4-configwordbreak.diff](st-0.4-configwordbreak.diff) -* [st-0.4.1-configwordbreak.diff](st-0.4.1-configwordbreak.diff) -* [st-0.5-configwordbreak.diff](st-0.5-configwordbreak.diff) - -Author ------- - - * Stephen Paul Weber - singpolyma - * FRIGN - dev@frign.de (st-0.4, st-0.4.1, st-0.5 ports) diff --git a/st.suckless.org/patches/copyurl.md b/st.suckless.org/patches/copyurl.md @@ -4,17 +4,24 @@ copyurl Description ----------- -Select and copy the last URL in the display. Multiple invocations cycle through -the available URLs. +Select and copy the last URL displayed with Mod1+l. +Multiple invocations cycle through the available URLs. + +Notes +----- + +URLs spanning multiple lines are not handled and only the first +URL on each line is selected. Download -------- -* [st-git-20141017-copyurl.diff](st-git-20141017-copyurl.diff) -* [st-git-20150601-copyurl.diff](st-git-20150601-copyurl.diff) + * [st-0.6-copyurl.diff](st-0.6-copyurl.diff) + * [st-git-20160210-copyurl.diff](st-git-20160210-copyurl.diff) -Author ------- +Authors +------- * Brandon Mulcahy - brandon@jangler.info - * FRIGN - dev@frign.de (git port) + * Laslo Hunhold - dev@frign.de (st-0.6 port) + * David Phillips - dbphillipsnz@gmail.com (st-git-20160210 port) diff --git a/st.suckless.org/patches/delkey.md b/st.suckless.org/patches/delkey.md @@ -4,14 +4,16 @@ delkey Description ----------- -Return BS in Backspace and DEL in Delete key. +Return BS on pressing backspace and DEL on pressing the delete key. Download -------- -* [st-git-delkey.diff](st-git-delkey.diff) + * [st-0.6-delkey.diff](st-0.6-delkey.diff) + * [st-git-20150917-delkey.diff](st-git-20150917-delkey.diff) -Author ------- +Authors +------- * Roberto E. Vargas Caballero - k0ga@shike2.com + * Laslo Hunhold - dev@frign.de (st-0.6, st-git-20150917 ports) diff --git a/st.suckless.org/patches/externalpipe.md b/st.suckless.org/patches/externalpipe.md @@ -1,44 +1,36 @@ -External Pipe -============= +externalpipe +============ Description ----------- -This patch lets you write st's screen text out through a pipe, for example, -url-select (below). +Reading and writing st's screen through a pipe. Example ------- -Bind alt+u to extract all visible urls and present dmenu, to choose and open -said urls: +config.h example, binding Mod1+u to extract all visible URLs and present +dmenu to select and open one: static Shortcut shortcuts[] = { ... - { MODKEY, 'u', externalpipe, { .s = "xurls | dmenu -l 10 | xargs -r open" } }, + { MODKEY, 'u', externalpipe, { .v = "xurls | dmenu -l 10 | xargs -r open" } }, }; - -([xurls][1] and [open][2] are external scripts) +([xurls](https://raw.github.com/bobrippling/perlbin/master/xurls) and +[open](https://github.com/bobrippling/open) are external scripts) Download -------- -* [st-0.4.1-externalpipe.diff][0] -* [st-0.5-externalpipe.diff][3] -* [st-0.6-externalpipe.diff][4] -* [st-git-20150824-externalpipe.diff][5] - -[0]: st-0.4.1-externalpipe.diff -[1]: https://raw.github.com/bobrippling/perlbin/master/xurls -[2]: https://github.com/bobrippling/open -[3]: http://witsquash.com/~marty/st-0.5-externalpipe.diff -[4]: st-0.6-externalpipe.diff -[5]: st-git-20150824-externalpipe.diff +* [st-0.4.1-externalpipe.diff](st-0.4.1-externalpipe.diff) +* [st-0.5-externalpipe.diff](st-0.5-externalpipe.diff) +* [st-0.6-externalpipe.diff](st-0.6-externalpipe.diff) +* [st-git-20160204-externalpipe.diff](st-git-20160204-externalpipe.diff) +Authors +------- -Author ------- - - * Rob Pilling - my name @ gmail + * Rob Pilling - robpilling@gmail.com + * Laslo Hunhold - dev@frign.de (st-0.4.1, st-0.5, st-0.6, st-git-20150917 ports) diff --git a/st.suckless.org/patches/hide_X_cursor.md b/st.suckless.org/patches/hide_X_cursor.md @@ -1,20 +0,0 @@ -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-0.6-hidexcursor.diff](st-0.6-hidexcursor.diff) -* [st-git-hidexcursor.diff](st-git-hidexcursor.diff) - -Author ------- - - * Ivan Delalande - colona diff --git a/st.suckless.org/patches/hidecursor.md b/st.suckless.org/patches/hidecursor.md @@ -0,0 +1,21 @@ +hidecursor +========== + +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-hidecursor.diff](st-0.5-hidecursor.diff) +* [st-0.6-hidecursor.diff](st-0.6-hidecursor.diff) +* [st-git-20150917-hidecursor.diff](st-git-20150917-hidecursor.diff) + +Author +------ + + * Ivan Delalande - colona@ycc.fr + * Laslo Hunhold - dev@frign.de (st-git-20150917 port) diff --git a/st.suckless.org/patches/openbsd.md b/st.suckless.org/patches/openbsd.md @@ -0,0 +1,37 @@ +openbsd +======= + +Description +----------- + +OpenBSD primarily searches for terminfo descriptions in +terminfo databases before considering terminfo files. +Given the terminfo currently stored in the global database +is for st 0.1.1, this leads to conflicts and misbehaviour. + +This patch renames st to st-git forcing OpenBSD to use the provided +terminfo file. + + +Notes +----- + +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, effectively making this patch obsolete for +future stable releases. +More information on this issue can be found in this +[thread](http://marc.info/?l=openbsd-misc&m=139540215025526&w=2). + + +Download +-------- + +* [st-git-20150920-openbsd.diff](st-git-20150920-openbsd.diff) + + +Authors +------- + + * Nils Reuße - nilsreusse@gmail.com + * Laslo Hunhold - dev@frign.de (st-git-20150920 port) diff --git a/st.suckless.org/patches/scrollback.md b/st.suckless.org/patches/scrollback.md @@ -1,19 +1,35 @@ -# Scrollback +scrollback +========== -## Description +Description +----------- -Scroll back through terminal output. +Scroll back through terminal output using Shift+{PageUp, PageDown}. -## Download +Download +-------- -Apply only one of them: +* [st-git-20151217-scrollback.diff](st-git-20151217-scrollback.diff) -* [st-scrollback.diff](st-scrollback.diff) (against current git master) -* [st-scrollback-shift-mouse.diff](st-scrollback-shift-mouse.diff) - With shift - mouse +Apply the following patch on top of the previous to allow scrolling +using `Shift+MouseWheel`. -## Author +* [st-git-20151106-scrollback-mouse.diff](st-git-20151106-scrollback-mouse.diff) - * Jochen Sprickerhof - dwm @ jochen . sprickerhof . de - * M Farkas-Dyck - strake888 @ gmail . com - * Ivan Tham - pickfire @ riseup . net (The gluer) +Apply the following patch on top of the previous two to allow scrollback using +mouse wheel only when not in `MODE_ALTSCREEN`. eg. The content is being +scrolled instead of the scrollback buffer in `less`. Consequently the Shift +modifier for scrolling is not needed anymore. **Note: It might break other +mkeys excluding scrolling functions.** + +* [st-git-20160203-scrollback-mouse-altscreen.diff](st-git-20160203-scrollback-mouse-altscreen.diff) + +Authors +------- + + * Jochen Sprickerhof - dwm@jochen.sprickerhof.de + * M Farkas-Dyck - strake888@gmail.com + * Ivan Tham - pickfire@riseup.net (mouse scrolling, st-git-20151122 port) + * Laslo Hunhold - dev@frign.de (unscrambling, st-git-20151106 port) + * Ori Bernstein - ori@eigenstate.org (fix memory bug, st-git-20151216 port) + * Matthias Schoth - mschoth@gmail.com (auto altscreen scrolling) diff --git a/st.suckless.org/patches/solarized.md b/st.suckless.org/patches/solarized.md @@ -0,0 +1,58 @@ +solarized +========= + +Description +----------- + +[Solarized](http://ethanschoonover.com/solarized) is a color scheme by +Ethan Schoonover which exists in a dark and a light variant. These +patches make the Solarized color scheme available for st. + + +Notes +----- + +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](https://bbs.archlinux.org/viewtopic.php?id=164108). + + +Example +------- + +->[![Screenshot](st-solarized-light-s.png)](st-solarized-light.png)<- + +->[![Screenshot](st-solarized-dark-s.png)](st-solarized-dark.png)<- + +The font used is Source Code Pro. + +Download +-------- + +To get correct colors, you first need to apply the following patch +to disable lighting up bold colors. + + * [st-0.5-no-bold-colors.diff](st-0.5-no-bold-colors.diff) + * [st-0.6-no-bold-colors.diff](st-0.6-no-bold-colors.diff) + * [st-git-20150917-no-bold-colors.diff](st-git-20150917-no-bold-colors.diff) + +Choose one of the following patches to get either the light +or the dark color scheme: + +*Light*: + + * [st-0.5-solarized-light.diff](st-0.5-solarized-light.diff) + * [st-0.6-solarized-light.diff](st-0.6-solarized-light.diff) + * [st-git-20151119-solarized-light.diff](st-git-20151119-solarized-light.diff) + +*Dark*: + + * [st-0.5-solarized-dark.diff](st-0.5-solarized-dark.diff) + * [st-0.6-solarized-dark.diff](st-0.6-solarized-dark.diff) + * [st-git-20151119-solarized-dark.diff](st-git-20151119-solarized-dark.diff) + +Authors +------- + + * Nils Reuße - nilsreusse@gmail.com + * Laslo Hunhold - dev@frign.de (st-0.5, st-0.6, st-git-20150917 ports) diff --git a/st.suckless.org/patches/solarized_color_scheme.md b/st.suckless.org/patches/solarized_color_scheme.md @@ -1,58 +0,0 @@ -Solarized color scheme -====================== - -Description ------------ - -[Solarized][1] is a color scheme by Ethan Schoonover which 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][8] (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-s.png)](st-solarized-light.png) -[![Screenshot](st-solarized-dark-s.png)](st-solarized-dark.png) - -The font is [Source Code Pro][6]. - -Download --------- - - * [st-0.5-no-bold-colors.diff][7] - * [st-0.6-no-bold-colors.diff][8] - * [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 -[8]: st-0.6-no-bold-colors.diff - -Author ------- - - * Nils Reuße - nilsreusse @ gmail diff --git a/st.suckless.org/patches/spoiler.md b/st.suckless.org/patches/spoiler.md @@ -0,0 +1,28 @@ +spoiler +======= + +Description +----------- + +Use inverted defaultbg/fg for selection when bg/fg are the same + +The background/foreground of selected text is currently set by setting +ATTR_REVERSE, which flips its normal bg/fg. When the text being selected +has the same bg and fg, it won't be readable after selecting it, either. + +The main use case is black-on-black text used to mark 'spoilers'. + +This patch allows that text to be read by selecting it, turning it into +text with white bg and black fg (given default values for defaultbg/fg), +just like most normal unformatted text when selected. + +Download +-------- + + * [st-0.6-spoiler.diff](st-0.6-spoiler.diff) + * [st-git-20150922-spoiler.diff](st-git-20150922-spoiler.diff) + +Author +------ + + * dequis - dx@dxzone.com.ar diff --git a/st.suckless.org/patches/st-0.3-configwordbreak.diff b/st.suckless.org/patches/st-0.3-wordbreak.diff diff --git a/st.suckless.org/patches/st-0.4-configwordbreak.diff b/st.suckless.org/patches/st-0.4-wordbreak.diff diff --git a/st.suckless.org/patches/st-0.4.1-externalpipe.diff b/st.suckless.org/patches/st-0.4.1-externalpipe.diff @@ -1,17 +1,8 @@ -From 7982a2d238925028b45d5143db470e408b97469a Mon Sep 17 00:00:00 2001 -From: Rob Pilling <robpilling@gmail.com> -Date: Fri, 20 Dec 2013 12:40:55 +0000 -Subject: [PATCH] Add externalpipe() for piping out screen text - ---- - st.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 68 insertions(+), 6 deletions(-) - diff --git a/st.c b/st.c -index 4fb3311..adef257 100644 +index 686ed5d..697cd43 100644 --- a/st.c +++ b/st.c -@@ -299,6 +299,7 @@ typedef union { +@@ -249,6 +249,7 @@ typedef union { unsigned int ui; float f; const void *v; @@ -19,7 +10,7 @@ index 4fb3311..adef257 100644 } Arg; typedef struct { -@@ -313,6 +314,7 @@ static void clippaste(const Arg *); +@@ -263,6 +264,7 @@ static void clippaste(const Arg *); static void numlock(const Arg *); static void selpaste(const Arg *); static void xzoom(const Arg *); @@ -27,14 +18,14 @@ index 4fb3311..adef257 100644 /* Config.h for applying patches and the configuration. */ #include "config.h" -@@ -1204,15 +1206,22 @@ execsh(void) { +@@ -1024,15 +1026,22 @@ execsh(void) { void sigchld(int a) { int stat = 0; + pid_t r; - if(waitpid(pid, &stat, 0) < 0) -- die("Waiting for pid %hd failed: %s\n", pid, SERRNO); +- die("Waiting for pid %hd failed: %s\n", pid, SERRNO); + r = wait(&stat); + if(r < 0) + die("wait(): %s\n", SERRNO); @@ -44,7 +35,7 @@ index 4fb3311..adef257 100644 - } else { - exit(EXIT_FAILURE); + if(r == pid){ -+ /* _the_ sub porcess */ ++ /* _the_ sub process */ + if(WIFEXITED(stat)) { + exit(WEXITSTATUS(stat)); + } else { @@ -56,7 +47,7 @@ index 4fb3311..adef257 100644 } void -@@ -2928,6 +2937,59 @@ xzoom(const Arg *arg) { +@@ -2593,6 +2602,59 @@ xzoom(const Arg *arg) { } void @@ -114,8 +105,5 @@ index 4fb3311..adef257 100644 + +void xinit(void) { + XSetWindowAttributes attrs; XGCValues gcvalues; - Cursor cursor; --- -1.7.10.4 - diff --git a/st.suckless.org/patches/st-0.4.1-configwordbreak.diff b/st.suckless.org/patches/st-0.4.1-wordbreak.diff diff --git a/st.suckless.org/patches/st-0.5-externalpipe.diff b/st.suckless.org/patches/st-0.5-externalpipe.diff @@ -0,0 +1,109 @@ +diff --git a/st.c b/st.c +index 392f12d..31660c8 100644 +--- a/st.c ++++ b/st.c +@@ -301,6 +301,7 @@ typedef union { + unsigned int ui; + float f; + const void *v; ++ const char *s; + } Arg; + + typedef struct { +@@ -315,6 +316,7 @@ static void clippaste(const Arg *); + static void numlock(const Arg *); + static void selpaste(const Arg *); + static void xzoom(const Arg *); ++static void externalpipe(const Arg *); + static void printsel(const Arg *); + static void printscreen(const Arg *) ; + static void toggleprinter(const Arg *); +@@ -1179,15 +1181,22 @@ execsh(void) { + void + sigchld(int a) { + int stat = 0; ++ pid_t r; + +- if(waitpid(pid, &stat, 0) < 0) +- die("Waiting for pid %hd failed: %s\n", pid, SERRNO); ++ r = wait(&stat); ++ if(r < 0) ++ die("wait(): %s\n", strerror(errno)); + +- if(WIFEXITED(stat)) { +- exit(WEXITSTATUS(stat)); +- } else { +- exit(EXIT_FAILURE); ++ if(r == pid){ ++ /* _the_ sub process */ ++ if(WIFEXITED(stat)) { ++ exit(WEXITSTATUS(stat)); ++ } else { ++ exit(EXIT_FAILURE); ++ } + } ++ ++ /* something else we've forked out */ + } + + void +@@ -2982,6 +2991,59 @@ xzoom(const Arg *arg) { + } + + void ++externalpipe(const Arg *arg) ++{ ++ int to[2]; /* 0 = read, 1 = write */ ++ pid_t child; ++ int y, x; ++ void (*oldsigpipe)(int); ++ ++ if(pipe(to) == -1) ++ return; ++ ++ /* sigchld() handles this */ ++ switch((child = fork())){ ++ case -1: ++ close(to[0]), close(to[1]); ++ return; ++ case 0: ++ /* child */ ++ close(to[1]); ++ dup2(to[0], STDIN_FILENO); /* 0<&to */ ++ close(to[0]); ++ execvp( ++ "sh", ++ (char *const []){ ++ "/bin/sh", ++ "-c", ++ (char *)arg->s, ++ 0 ++ }); ++ exit(127); ++ } ++ ++ /* parent */ ++ close(to[0]); ++ /* ignore sigpipe for now, in case child exits early */ ++ oldsigpipe = signal(SIGPIPE, SIG_IGN); ++ ++ for(y = 0; y < term.row; y++){ ++ for(x = 0; x < term.col; x++){ ++ if(write(to[1], term.line[y][x].c, 1) == -1) ++ goto done; ++ } ++ if(write(to[1], "\n", 1) == -1) ++ break; ++ } ++ ++done: ++ close(to[1]); ++ ++ /* restore */ ++ signal(SIGPIPE, oldsigpipe); ++} ++ ++void + xinit(void) { + XGCValues gcvalues; + Cursor cursor; diff --git a/st.suckless.org/patches/st-0.5-hidecursor.diff b/st.suckless.org/patches/st-0.5-hidecursor.diff @@ -0,0 +1,82 @@ +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; + diff --git a/st.suckless.org/patches/st-0.5-hidexcursor.diff b/st.suckless.org/patches/st-0.5-hidexcursor.diff @@ -1,96 +0,0 @@ -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 @@ -1,7 +1,8 @@ diff --git a/st.c b/st.c +index 392f12d..f893147 100644 --- a/st.c +++ b/st.c -@@ -3203,7 +3203,7 @@ +@@ -3152,7 +3152,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { if(base.mode & ATTR_BOLD) { if(BETWEEN(base.fg, 0, 7)) { /* basic system colors */ diff --git a/st.suckless.org/patches/st-0.5-solarized-dark.diff b/st.suckless.org/patches/st-0.5-solarized-dark.diff @@ -0,0 +1,65 @@ +diff --git a/config.def.h b/config.def.h +index 58b470e..f1c5ed1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -51,30 +51,23 @@ static unsigned int tabspaces = 8; + + /* 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 @@ static const char *colorname[] = { + * 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-0.5-solarized-light.diff b/st.suckless.org/patches/st-0.5-solarized-light.diff @@ -0,0 +1,65 @@ +diff --git a/config.def.h b/config.def.h +index 58b470e..ec39cca 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -51,30 +51,23 @@ static unsigned int tabspaces = 8; + + /* 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 @@ static const char *colorname[] = { + * 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-0.5-configwordbreak.diff b/st.suckless.org/patches/st-0.5-wordbreak.diff diff --git a/st.suckless.org/patches/st-0.6-argbbg.diff b/st.suckless.org/patches/st-0.6-argbbg.diff @@ -0,0 +1,170 @@ +diff --git a/config.def.h b/config.def.h +index 64e75b8..9a27c14 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -58,6 +58,8 @@ static char termname[] = "st-256color"; + + static unsigned int tabspaces = 8; + ++/* bg opacity */ ++static const int alpha = 0xdd; + + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { +@@ -85,6 +87,7 @@ static const char *colorname[] = { + + /* more colors can be added after 255 to use with DefaultXX */ + "#cccccc", ++ "black", + }; + + +@@ -93,7 +96,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 67844dc..005b1c6 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} -lm -lrt -lX11 -lutil -lXext -lXft \ ++LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft -lXrender\ + `pkg-config --libs fontconfig` \ + `pkg-config --libs freetype2` + +diff --git a/st.c b/st.c +index b89d094..d212134 100644 +--- a/st.c ++++ b/st.c +@@ -61,6 +61,7 @@ char *argv0; + #define XK_ANY_MOD UINT_MAX + #define XK_NO_MOD 0 + #define XK_SWITCH_MOD (1<<13) ++#define OPAQUE 0Xff + + /* macros */ + #define MIN(a, b) ((a) < (b) ? (a) : (b)) +@@ -77,6 +78,7 @@ char *argv0; + #define IS_SET(flag) ((term.mode & (flag)) != 0) + #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6) + #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) ++#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL) + + #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) + #define IS_TRUECOL(x) (1 << 24 & (x)) +@@ -265,6 +267,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 */ + int cursor; /* cursor style */ + } XWindow; +@@ -2895,8 +2898,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); + } +@@ -2946,6 +2948,14 @@ xloadcols(void) { + else + die("Could not allocate color %d\n", i); + } ++ ++ /* 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; ++ } ++ + loaded = true; + } + +@@ -3189,7 +3199,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()) +@@ -3199,7 +3240,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 */ +@@ -3222,16 +3266,17 @@ xinit(void) { + if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) + parent = XRootWindow(xw.dpy, xw.scr); + xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, +- 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.6-clipboard.diff b/st.suckless.org/patches/st-0.6-clipboard.diff @@ -0,0 +1,13 @@ +diff --git a/st.c b/st.c +index b89d094..6658e6a 100644 +--- a/st.c ++++ b/st.c +@@ -1155,6 +1155,8 @@ xsetsel(char *str, Time t) { + XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); + if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) + selclear(0); ++ ++ clipcopy(NULL); + } + + void diff --git a/st.suckless.org/patches/st-0.6-copyurl.diff b/st.suckless.org/patches/st-0.6-copyurl.diff @@ -0,0 +1,88 @@ +diff --git a/config.def.h b/config.def.h +index 64e75b8..c3d4e88 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -128,6 +128,7 @@ static Shortcut shortcuts[] = { + { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, + { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, + { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, ++ { MODKEY, XK_l, copyurl, {.i = 0} }, + }; + + /* +diff --git a/st.c b/st.c +index b89d094..dafd5ba 100644 +--- a/st.c ++++ b/st.c +@@ -332,6 +332,7 @@ static void xzoomreset(const Arg *); + static void printsel(const Arg *); + static void printscreen(const Arg *) ; + static void toggleprinter(const Arg *); ++static void copyurl(const Arg *); + + /* Config.h for applying patches and the configuration. */ + #include "config.h" +@@ -4080,3 +4081,63 @@ run: + return 0; + } + ++/* select and copy the previous url on screen (do nothing if there's no url). ++ * known bug: doesn't handle urls that span multiple lines (wontfix) ++ * known bug: only finds first url on line (mightfix) ++ */ ++void ++copyurl(const Arg *arg) { ++ /* () and [] can appear in urls, but excluding them here will reduce false ++ * positives when figuring out where a given url ends. ++ */ ++ static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ "abcdefghijklmnopqrstuvwxyz" ++ "0123456789-._~:/?#@!$&'*+,;=%"; ++ ++ int i, row, startrow; ++ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ ++ char *c, *match = NULL; ++ ++ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y-1 : term.bot; ++ LIMIT(row, term.top, term.bot); ++ startrow = row; ++ ++ /* find the start of the last url before selection */ ++ do { ++ for (i = 0; i < term.col; ++i) { ++ if (term.line[row][i].u > 127) /* assume ascii */ ++ continue; ++ linestr[i] = term.line[row][i].u; ++ } ++ linestr[term.col] = '\0'; ++ if ((match = strstr(linestr, "http://")) ++ || (match = strstr(linestr, "https://"))) ++ break; ++ if (--row < term.top) ++ row = term.bot; ++ } while (row != startrow); ++ ++ if (match) { ++ /* must happen before trim */ ++ selclear(NULL); ++ sel.ob.x = strlen(linestr) - strlen(match); ++ ++ /* trim the rest of the line from the url match */ ++ for (c = match; *c != '\0'; ++c) ++ if (!strchr(URLCHARS, *c)) { ++ *c = '\0'; ++ break; ++ } ++ ++ /* select and copy */ ++ sel.mode = 1; ++ sel.type = SEL_REGULAR; ++ sel.oe.x = sel.ob.x + strlen(match)-1; ++ sel.ob.y = sel.oe.y = row; ++ selnormalize(); ++ tsetdirt(sel.nb.y, sel.ne.y); ++ selcopy(0); ++ } ++ ++ free(linestr); ++} diff --git a/st.suckless.org/patches/st-0.6-delkey.diff b/st.suckless.org/patches/st-0.6-delkey.diff @@ -0,0 +1,45 @@ +diff --git a/config.def.h b/config.def.h +index 64e75b8..0811af4 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -211,7 +211,7 @@ static Key key[] = { + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, +- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, ++ { XK_KP_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, + { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0, 0}, + { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0, 0}, +@@ -266,8 +266,7 @@ static Key key[] = { + { XK_Delete, ShiftMask, "\033[2K", -1, 0, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, + { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, +- { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, +- { XK_BackSpace, XK_NO_MOD, "\177", 0, 0, 0}, ++ { XK_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1, 0}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1, 0}, + { XK_Home, XK_ANY_MOD, "\033[H", 0, -1, 0}, +diff --git a/st.info b/st.info +index 2acd8b2..21b4734 100644 +--- a/st.info ++++ b/st.info +@@ -53,7 +53,7 @@ st| simpleterm, + ka3=\E[5~, + kc1=\E[4~, + kc3=\E[6~, +- kbs=\177, ++ kbs=\010, + kcbt=\E[Z, + kb2=\EOu, + kcub1=\EOD, +@@ -73,7 +73,7 @@ st| simpleterm, + kri=\E[1;2A, + kclr=\E[3;5~, + kdl1=\E[3;2~, +- kdch1=\E[3~, ++ kdch1=\177~, + kich1=\E[2~, + kend=\E[4~, + kf1=\EOP, diff --git a/st.suckless.org/patches/st-0.6-externalpipe.diff b/st.suckless.org/patches/st-0.6-externalpipe.diff @@ -1,17 +1,5 @@ -diff --git a/config.def.h b/config.def.h -index 64e75b8..9245814 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -128,6 +128,7 @@ static Shortcut shortcuts[] = { - { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, - { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, - { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, -+ { MODKEY, XK_u, externalpipe, {.v = "rot13 > /tmp/test-externalpipe.txt"} }, - }; - - /* diff --git a/st.c b/st.c -index b89d094..941deb5 100644 +index b89d094..124ed16 100644 --- a/st.c +++ b/st.c @@ -326,6 +326,7 @@ static void clipcopy(const Arg *); diff --git a/st.suckless.org/patches/st-0.6-hidecursor.diff b/st.suckless.org/patches/st-0.6-hidecursor.diff @@ -0,0 +1,84 @@ +diff --git a/st.c b/st.c +index b89d094..d2979ff 100644 +--- a/st.c ++++ b/st.c +@@ -257,6 +257,11 @@ typedef struct { + Draw draw; + Visual *vis; + XSetWindowAttributes attrs; ++ /* Here, we use the term *pointer* to differentiate the cursor ++ * one sees when hovering the mouse over the terminal from, e.g., ++ * a green rectangle where text would be entered. */ ++ Cursor vpointer, bpointer; /* visible and hidden pointers */ ++ bool pointerisvisible; + int scr; + bool isfixed; /* is fixed geometry? */ + int l, t; /* left and top offset */ +@@ -1181,6 +1186,13 @@ void + bmotion(XEvent *e) { + int oldey, oldex, oldsby, oldsey; + ++ if(!xw.pointerisvisible) { ++ XDefineCursor(xw.dpy, xw.win, xw.vpointer); ++ xw.pointerisvisible = true; ++ if(!IS_SET(MODE_MOUSEMANY)) ++ xsetpointermotion(0); ++ } ++ + if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + mousereport(e); + return; +@@ -3182,9 +3194,11 @@ xzoomreset(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"); +@@ -3257,11 +3271,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.vpointer = XCreateFontCursor(xw.dpy, XC_xterm); ++ XDefineCursor(xw.dpy, xw.win, xw.vpointer); ++ XRecolorCursor(xw.dpy, xw.vpointer, &xcwhite, &xcblack); ++ xw.pointerisvisible = true; ++ blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1); ++ xw.bpointer = 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); +@@ -3725,6 +3741,8 @@ unmap(XEvent *ev) { + + void + xsetpointermotion(int set) { ++ if(!set && !xw.pointerisvisible) ++ return; + MODBIT(xw.attrs.event_mask, set, PointerMotionMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); + } +@@ -3818,6 +3836,12 @@ kpress(XEvent *ev) { + Status status; + Shortcut *bp; + ++ if(xw.pointerisvisible) { ++ XDefineCursor(xw.dpy, xw.win, xw.bpointer); ++ xsetpointermotion(1); ++ xw.pointerisvisible = false; ++ } ++ + if(IS_SET(MODE_KBDLOCK)) + return; + diff --git a/st.suckless.org/patches/st-0.6-hidexcursor.diff b/st.suckless.org/patches/st-0.6-hidexcursor.diff @@ -1,100 +0,0 @@ -From 700158aa952756a52b043fa6c665053d48cb2de2 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. - -[ s/cursor/pointer - Alex Pilon ] ---- - st.c | 36 ++++++++++++++++++++++++++++++------ - 1 file changed, 30 insertions(+), 6 deletions(-) - -diff --git a/st.c b/st.c -index 39d3fee..b95a4a5 100644 ---- a/st.c -+++ b/st.c -@@ -248,6 +248,11 @@ typedef struct { - Draw draw; - Visual *vis; - XSetWindowAttributes attrs; -+ /* Here, we use the term *pointer* to differentiate the cursor -+ * one sees when hovering the mouse over the terminal from, e.g., -+ * a green rectangle where text would be entered. */ -+ Cursor vpointer, bpointer; /* visible and hidden pointers */ -+ bool pointerisvisible; - int scr; - bool isfixed; /* is fixed geometry? */ - int l, t; /* left and top offset */ -@@ -1155,6 +1160,13 @@ void - bmotion(XEvent *e) { - int oldey, oldex, oldsby, oldsey; - -+ if(!xw.pointerisvisible) { -+ XDefineCursor(xw.dpy, xw.win, xw.vpointer); -+ xw.pointerisvisible = true; -+ if(!IS_SET(MODE_MOUSEMANY)) -+ xsetpointermotion(0); -+ } -+ - if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { - mousereport(e); - return; -@@ -3173,9 +3185,11 @@ xzoomreset(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"); -@@ -3248,11 +3262,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.vpointer = XCreateFontCursor(xw.dpy, XC_xterm); -+ XDefineCursor(xw.dpy, xw.win, xw.vpointer); -+ XRecolorCursor(xw.dpy, xw.vpointer, &xcwhite, &xcblack); -+ xw.pointerisvisible = true; -+ blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1); -+ xw.bpointer = 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); -@@ -3739,6 +3755,8 @@ unmap(XEvent *ev) { - - void - xsetpointermotion(int set) { -+ if(!set && !xw.pointerisvisible) -+ return; - MODBIT(xw.attrs.event_mask, set, PointerMotionMask); - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); - } -@@ -3832,6 +3850,12 @@ kpress(XEvent *ev) { - Status status; - Shortcut *bp; - -+ if(xw.pointerisvisible) { -+ XDefineCursor(xw.dpy, xw.win, xw.bpointer); -+ xsetpointermotion(1); -+ xw.pointerisvisible = false; -+ } -+ - if(IS_SET(MODE_KBDLOCK)) - return; - --- -2.3.3 - diff --git a/st.suckless.org/patches/st-0.6-solarized-dark.diff b/st.suckless.org/patches/st-0.6-solarized-dark.diff @@ -0,0 +1,65 @@ +diff --git a/config.def.h b/config.def.h +index 64e75b8..bc8d298 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -61,30 +61,23 @@ static unsigned int tabspaces = 8; + + /* 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 */ + }; + + +@@ -92,9 +85,9 @@ static const char *colorname[] = { + * 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-0.6-solarized-light.diff b/st.suckless.org/patches/st-0.6-solarized-light.diff @@ -0,0 +1,65 @@ +diff --git a/config.def.h b/config.def.h +index 64e75b8..fba47b1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -61,30 +61,23 @@ static unsigned int tabspaces = 8; + + /* 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 */ + }; + + +@@ -92,9 +85,9 @@ static const char *colorname[] = { + * 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-0.6-spoiler.diff b/st.suckless.org/patches/st-0.6-spoiler.diff @@ -0,0 +1,22 @@ +diff --git a/st.c b/st.c +index b89d094..88c78f5 100644 +--- a/st.c ++++ b/st.c +@@ -3483,9 +3483,14 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + } + + if(base.mode & ATTR_REVERSE) { +- temp = fg; +- fg = bg; +- bg = temp; ++ if (bg == fg) { ++ bg = &dc.col[defaultfg]; ++ fg = &dc.col[defaultbg]; ++ } else { ++ temp = fg; ++ fg = bg; ++ bg = temp; ++ } + } + + if((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) { diff --git a/st.suckless.org/patches/st-git-20141017-copyurl.diff b/st.suckless.org/patches/st-git-20141017-copyurl.diff @@ -1,84 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1667ed6..be25f2a 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -120,6 +120,7 @@ static Shortcut shortcuts[] = { - { ShiftMask, XK_Insert, selpaste, {.i = 0} }, - { MODKEY|ShiftMask, XK_Insert, clippaste, {.i = 0} }, - { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, -+ { MODKEY, XK_l, copyurl, {.i = 0} }, - }; - - /* -diff --git a/st.c b/st.c -index bcf96e9..38e923e 100644 ---- a/st.c -+++ b/st.c -@@ -323,6 +323,7 @@ static void xzoomreset(const Arg *); - static void printsel(const Arg *); - static void printscreen(const Arg *) ; - static void toggleprinter(const Arg *); -+static void copyurl(const Arg *); - - /* Config.h for applying patches and the configuration. */ - #include "config.h" -@@ -3989,3 +3990,59 @@ run: - return 0; - } - -+/* select and copy the previous url on screen (do nothing if there's no url). -+ * known bug: doesn't handle urls that span multiple lines (wontfix) -+ * known bug: only finds first url on line (mightfix) -+ */ -+void -+copyurl(const Arg *arg) { -+ /* () and [] can appear in urls, but excluding them here will reduce false -+ * positives when figuring out where a given url ends. -+ */ -+ static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -+ "abcdefghijklmnopqrstuvwxyz" -+ "0123456789-._~:/?#@!$&'*+,;=%"; -+ -+ int i, row, startrow; -+ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ -+ char *c, *match = NULL; -+ -+ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y-1 : term.bot; -+ row = startrow = LIMIT(row, term.top, term.bot); -+ -+ /* find the start of the last url before selection */ -+ do { -+ for (i = 0; i < term.col; ++i) -+ linestr[i] = term.line[row][i].c[0]; -+ linestr[term.col] = '\0'; -+ if ((match = strstr(linestr, "http://")) -+ || (match = strstr(linestr, "https://"))) -+ break; -+ if (--row < term.top) -+ row = term.bot; -+ } while (row != startrow); -+ -+ if (match) { -+ /* must happen before trim */ -+ selclear(NULL); -+ sel.ob.x = strlen(linestr) - strlen(match); -+ -+ /* trim the rest of the line from the url match */ -+ for (c = match; *c != '\0'; ++c) -+ if (!strchr(URLCHARS, *c)) { -+ *c = '\0'; -+ break; -+ } -+ -+ /* select and copy */ -+ sel.mode = 1; -+ sel.type = SEL_REGULAR; -+ sel.oe.x = sel.ob.x + strlen(match)-1; -+ sel.ob.y = sel.oe.y = row; -+ selnormalize(); -+ tsetdirt(sel.nb.y, sel.ne.y); -+ selcopy(); -+ } -+ -+ free(linestr); -+} diff --git a/st.suckless.org/patches/st-git-20141122-argbbg.diff b/st.suckless.org/patches/st-git-20141122-argbbg.diff @@ -1,169 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1667ed6..09b8fd3 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -52,6 +52,8 @@ static char termname[] = "st-256color"; - - static unsigned int tabspaces = 8; - -+/* bg opacity */ -+static const int alpha = 0xdd; - - /* Terminal colors (16 first used in escape sequence) */ - static const char *colorname[] = { -@@ -79,6 +81,7 @@ static const char *colorname[] = { - - /* more colors can be added after 255 to use with DefaultXX */ - "#cccccc", -+ "black", - }; - - -@@ -87,7 +90,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 298484e..69baf24 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} -lm -lrt -lX11 -lutil -lXext -lXft \ -+LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft -lXrender\ - `pkg-config --libs fontconfig` \ - `pkg-config --libs freetype2` - -diff --git a/st.c b/st.c -index fc91334..d4f0642 100644 ---- a/st.c -+++ b/st.c -@@ -62,6 +62,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 IS_SET(flag) ((term.mode & (flag)) != 0) - #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6) - #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) -+#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL) - - #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) - #define IS_TRUECOL(x) (1 << 24 & (x)) -@@ -258,6 +260,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; - -@@ -2786,8 +2789,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); - } -@@ -2827,6 +2829,13 @@ xloadcols(void) { - die("Could not allocate color %d\n", i); - } - -+ /* 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 [232-255] ; grayscale */ - for(; i < 256; i++) { - color.red = color.green = color.blue = 0x0808 + 0x0a0a * (i-(6*6*6+16)); -@@ -3114,7 +3123,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()) -@@ -3124,7 +3164,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 */ -@@ -3147,16 +3190,17 @@ xinit(void) { - if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) - parent = XRootWindow(xw.dpy, xw.scr); - xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, -- 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-git-20150601-argbbg.diff b/st.suckless.org/patches/st-git-20150601-argbbg.diff @@ -1,169 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index bb5596e..11ab57f 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -58,6 +58,8 @@ static char termname[] = "st-256color"; - - static unsigned int tabspaces = 8; - -+/* bg opacity */ -+static const int alpha = 0xdd; - - /* Terminal colors (16 first used in escape sequence) */ - static const char *colorname[] = { -@@ -85,6 +87,7 @@ static const char *colorname[] = { - - /* more colors can be added after 255 to use with DefaultXX */ - "#cccccc", -+ "black", - }; - - -@@ -93,7 +96,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 3026d87..f20d222 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} -lm -lrt -lX11 -lutil -lXext -lXft \ -+LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft -lXrender\ - `pkg-config --libs fontconfig` \ - `pkg-config --libs freetype2` - -diff --git a/st.c b/st.c -index 3460a37..4561527 100644 ---- a/st.c -+++ b/st.c -@@ -61,6 +61,7 @@ char *argv0; - #define XK_ANY_MOD UINT_MAX - #define XK_NO_MOD 0 - #define XK_SWITCH_MOD (1<<13) -+#define OPAQUE 0Xff - - /* macros */ - #define MIN(a, b) ((a) < (b) ? (a) : (b)) -@@ -77,6 +78,7 @@ char *argv0; - #define IS_SET(flag) ((term.mode & (flag)) != 0) - #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6) - #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) -+#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL) - - #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) - #define IS_TRUECOL(x) (1 << 24 & (x)) -@@ -265,6 +267,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 */ - int cursor; /* cursor style */ - } XWindow; -@@ -2895,8 +2898,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); - } -@@ -2910,6 +2912,13 @@ bool - xloadcolor(int i, const char *name, Color *ncolor) { - XRenderColor color = { .alpha = 0xffff }; - -+ /* 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; -+ } -+ - if(!name) { - if(BETWEEN(i, 16, 255)) { /* 256 color */ - if(i < 6*6*6+16) { /* same colors as xterm */ -@@ -3190,7 +3199,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()) -@@ -3200,7 +3240,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 */ -@@ -3223,16 +3266,17 @@ xinit(void) { - if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) - parent = XRootWindow(xw.dpy, xw.scr); - xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, -- 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-git-20150601-copyurl.diff b/st.suckless.org/patches/st-git-20150601-copyurl.diff @@ -1,85 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index bb5596e..34ce569 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -128,6 +128,7 @@ static Shortcut shortcuts[] = { - { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, - { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, - { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, -+ { MODKEY, XK_l, copyurl, {.i = 0} }, - }; - - /* -diff --git a/st.c b/st.c -index 3460a37..699ec3b 100644 ---- a/st.c -+++ b/st.c -@@ -332,6 +332,7 @@ static void xzoomreset(const Arg *); - static void printsel(const Arg *); - static void printscreen(const Arg *) ; - static void toggleprinter(const Arg *); -+static void copyurl(const Arg *); - - /* Config.h for applying patches and the configuration. */ - #include "config.h" -@@ -4074,3 +4075,60 @@ run: - return 0; - } - -+/* select and copy the previous url on screen (do nothing if there's no url). -+ * known bug: doesn't handle urls that span multiple lines (wontfix) -+ * known bug: only finds first url on line (mightfix) -+ */ -+void -+copyurl(const Arg *arg) { -+ /* () and [] can appear in urls, but excluding them here will reduce false -+ * positives when figuring out where a given url ends. -+ */ -+ static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -+ "abcdefghijklmnopqrstuvwxyz" -+ "0123456789-._~:/?#@!$&'*+,;=%"; -+ -+ int i, row, startrow; -+ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ -+ char *c, *match = NULL; -+ -+ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y-1 : term.bot; -+ startrow = LIMIT(row, term.top, term.bot); -+ row = startrow; -+ -+ /* find the start of the last url before selection */ -+ do { -+ for (i = 0; i < term.col; ++i) -+ linestr[i] = term.line[row][i].u; -+ linestr[term.col] = '\0'; -+ if ((match = strstr(linestr, "http://")) -+ || (match = strstr(linestr, "https://"))) -+ break; -+ if (--row < term.top) -+ row = term.bot; -+ } while (row != startrow); -+ -+ if (match) { -+ /* must happen before trim */ -+ selclear(NULL); -+ sel.ob.x = strlen(linestr) - strlen(match); -+ -+ /* trim the rest of the line from the url match */ -+ for (c = match; *c != '\0'; ++c) -+ if (!strchr(URLCHARS, *c)) { -+ *c = '\0'; -+ break; -+ } -+ -+ /* select and copy */ -+ sel.mode = 1; -+ sel.type = SEL_REGULAR; -+ sel.oe.x = sel.ob.x + strlen(match)-1; -+ sel.ob.y = sel.oe.y = row; -+ selnormalize(); -+ tsetdirt(sel.nb.y, sel.ne.y); -+ selcopy(0); -+ } -+ -+ free(linestr); -+} diff --git a/st.suckless.org/patches/st-git-20150611-argbbg.diff b/st.suckless.org/patches/st-git-20150611-argbbg.diff @@ -1,170 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index bb5596e..11ab57f 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -58,6 +58,8 @@ static char termname[] = "st-256color"; - - static unsigned int tabspaces = 8; - -+/* bg opacity */ -+static const int alpha = 0xdd; - - /* Terminal colors (16 first used in escape sequence) */ - static const char *colorname[] = { -@@ -85,6 +87,7 @@ static const char *colorname[] = { - - /* more colors can be added after 255 to use with DefaultXX */ - "#cccccc", -+ "black", - }; - - -@@ -93,7 +96,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 3026d87..f20d222 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} -lm -lrt -lX11 -lutil -lXext -lXft \ -+LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft -lXrender\ - `pkg-config --libs fontconfig` \ - `pkg-config --libs freetype2` - -diff --git a/st.c b/st.c -index 3dd5caf..dfa51b7 100644 ---- a/st.c -+++ b/st.c -@@ -61,6 +61,7 @@ char *argv0; - #define XK_ANY_MOD UINT_MAX - #define XK_NO_MOD 0 - #define XK_SWITCH_MOD (1<<13) -+#define OPAQUE 0Xff - - /* macros */ - #define MIN(a, b) ((a) < (b) ? (a) : (b)) -@@ -77,6 +78,7 @@ char *argv0; - #define IS_SET(flag) ((term.mode & (flag)) != 0) - #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6) - #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) -+#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL) - - #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) - #define IS_TRUECOL(x) (1 << 24 & (x)) -@@ -265,6 +267,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 */ - int cursor; /* cursor style */ - } XWindow; -@@ -2895,8 +2898,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); - } -@@ -2946,6 +2948,14 @@ xloadcols(void) { - else - die("Could not allocate color %d\n", i); - } -+ -+ /* 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; -+ } -+ - loaded = true; - } - -@@ -3190,7 +3200,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()) -@@ -3200,7 +3241,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 */ -@@ -3223,16 +3267,17 @@ xinit(void) { - if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) - parent = XRootWindow(xw.dpy, xw.scr); - xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, -- 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-git-20150824-externalpipe.diff b/st.suckless.org/patches/st-git-20150824-externalpipe.diff @@ -1,75 +0,0 @@ -diff --git a/st.c b/st.c -index 35a840b..bb2dd17 100644 ---- a/st.c -+++ b/st.c -@@ -327,6 +327,7 @@ static void clipcopy(const Arg *); - static void clippaste(const Arg *); - static void numlock(const Arg *); - static void selpaste(const Arg *); -+static void externalpipe(const Arg *); - static void xzoom(const Arg *); - static void xzoomabs(const Arg *); - static void xzoomreset(const Arg *); -@@ -2888,6 +2889,62 @@ eschandle(uchar ascii) - } - - void -+externalpipe(const Arg *arg) -+{ -+ int to[2]; /* 0 = read, 1 = write */ -+ pid_t child; -+ int n; -+ void (*oldsigpipe)(int); -+ char buf[UTF_SIZ]; -+ Glyph *bp, *end; -+ -+ if(pipe(to) == -1) -+ return; -+ -+ /* sigchld() handles this */ -+ switch(child = fork()){ -+ case -1: -+ close(to[0]), close(to[1]); -+ return; -+ case 0: -+ /* child */ -+ close(to[1]); -+ dup2(to[0], STDIN_FILENO); /* 0<&to */ -+ close(to[0]); -+ execvp( -+ "sh", -+ (char *const []){ -+ "/bin/sh", -+ "-c", -+ (char *)arg->v, -+ 0 -+ }); -+ exit(127); -+ } -+ -+ /* parent */ -+ close(to[0]); -+ /* ignore sigpipe for now, in case child exits early */ -+ oldsigpipe = signal(SIGPIPE, SIG_IGN); -+ -+ for(n = 0; n < term.row; n++){ -+ bp = &term.line[n][0]; -+ end = &bp[MIN(tlinelen(n), term.col) - 1]; -+ if(bp != end || bp->u != ' ') -+ for(; bp <= end; ++bp) -+ if(xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0) -+ break; -+ if(xwrite(to[1], "\n", 1) < 0) -+ break; -+ } -+ -+ close(to[1]); -+ -+ /* restore */ -+ signal(SIGPIPE, oldsigpipe); -+} -+ -+void - tputc(Rune u) - { - char c[UTF_SIZ]; diff --git a/st.suckless.org/patches/st-git-20150917-clipboard.diff b/st.suckless.org/patches/st-git-20150917-clipboard.diff @@ -0,0 +1,13 @@ +diff --git a/st.c b/st.c +index bd8b815..73c4573 100644 +--- a/st.c ++++ b/st.c +@@ -1262,6 +1262,8 @@ xsetsel(char *str, Time t) + XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); + if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) + selclear(0); ++ ++ clipcopy(NULL); + } + + void diff --git a/st.suckless.org/patches/st-git-20150917-delkey.diff b/st.suckless.org/patches/st-git-20150917-delkey.diff @@ -0,0 +1,45 @@ +diff --git a/config.def.h b/config.def.h +index b6adc5e..ceaafa0 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -238,7 +238,7 @@ static Key key[] = { + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, +- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, ++ { XK_KP_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, + { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0, 0}, + { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0, 0}, +@@ -293,8 +293,7 @@ static Key key[] = { + { XK_Delete, ShiftMask, "\033[2K", -1, 0, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, + { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, +- { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, +- { XK_BackSpace, XK_NO_MOD, "\177", 0, 0, 0}, ++ { XK_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1, 0}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1, 0}, + { XK_Home, XK_ANY_MOD, "\033[H", 0, -1, 0}, +diff --git a/st.info b/st.info +index b70fefa..d979946 100644 +--- a/st.info ++++ b/st.info +@@ -53,7 +53,7 @@ st| simpleterm, + ka3=\E[5~, + kc1=\E[4~, + kc3=\E[6~, +- kbs=\177, ++ kbs=\010, + kcbt=\E[Z, + kb2=\EOu, + kcub1=\EOD, +@@ -73,7 +73,7 @@ st| simpleterm, + kri=\E[1;2A, + kclr=\E[3;5~, + kdl1=\E[3;2~, +- kdch1=\E[3~, ++ kdch1=\177~, + kich1=\E[2~, + kend=\E[4~, + kf1=\EOP, diff --git a/st.suckless.org/patches/st-git-20150917-hidecursor.diff b/st.suckless.org/patches/st-git-20150917-hidecursor.diff @@ -0,0 +1,88 @@ +diff --git a/st.c b/st.c +index bd8b815..9a8e872 100644 +--- a/st.c ++++ b/st.c +@@ -259,6 +259,11 @@ typedef struct { + Draw draw; + Visual *vis; + XSetWindowAttributes attrs; ++ /* Here, we use the term *pointer* to differentiate the cursor ++ * one sees when hovering the mouse over the terminal from, e.g., ++ * a green rectangle where text would be entered. */ ++ Cursor vpointer, bpointer; /* visible and hidden pointers */ ++ int pointerisvisible; + int scr; + int isfixed; /* is fixed geometry? */ + int l, t; /* left and top offset */ +@@ -1290,6 +1295,13 @@ bmotion(XEvent *e) + { + int oldey, oldex, oldsby, oldsey; + ++ if(!xw.pointerisvisible) { ++ XDefineCursor(xw.dpy, xw.win, xw.vpointer); ++ xw.pointerisvisible = 1; ++ if(!IS_SET(MODE_MOUSEMANY)) ++ xsetpointermotion(0); ++ } ++ + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + mousereport(e); + return; +@@ -3440,10 +3452,10 @@ void + xinit(void) + { + XGCValues gcvalues; +- Cursor cursor; + Window parent; + pid_t thispid = getpid(); + XColor xmousefg, xmousebg; ++ Pixmap blankpm; + + if (!(xw.dpy = XOpenDisplay(NULL))) + die("Can't open display\n"); +@@ -3516,8 +3528,9 @@ xinit(void) + die("XCreateIC failed. Could not obtain input method.\n"); + + /* white cursor, black outline */ +- cursor = XCreateFontCursor(xw.dpy, mouseshape); +- XDefineCursor(xw.dpy, xw.win, cursor); ++ xw.pointerisvisible = 1; ++ xw.vpointer = XCreateFontCursor(xw.dpy, mouseshape); ++ XDefineCursor(xw.dpy, xw.win, xw.vpointer); + + if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) { + xmousefg.red = 0xffff; +@@ -3531,7 +3544,10 @@ xinit(void) + xmousebg.blue = 0x0000; + } + +- XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); ++ XRecolorCursor(xw.dpy, xw.vpointer, &xmousefg, &xmousebg); ++ blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1); ++ xw.bpointer = XCreatePixmapCursor(xw.dpy, blankpm, blankpm, ++ &xmousefg, &xmousebg, 0, 0); + + xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); + xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); +@@ -4006,6 +4022,8 @@ unmap(XEvent *ev) + void + xsetpointermotion(int set) + { ++ if(!set && !xw.pointerisvisible) ++ return; + MODBIT(xw.attrs.event_mask, set, PointerMotionMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); + } +@@ -4105,6 +4123,12 @@ kpress(XEvent *ev) + Status status; + Shortcut *bp; + ++ if(xw.pointerisvisible) { ++ XDefineCursor(xw.dpy, xw.win, xw.bpointer); ++ xsetpointermotion(1); ++ xw.pointerisvisible = 0; ++ } ++ + if (IS_SET(MODE_KBDLOCK)) + return; + diff --git a/st.suckless.org/patches/st-git-20150917-no-bold-colors.diff b/st.suckless.org/patches/st-git-20150917-no-bold-colors.diff @@ -0,0 +1,13 @@ +diff --git a/st.c b/st.c +index bd8b815..ae5a7ba 100644 +--- a/st.c ++++ b/st.c +@@ -3724,7 +3724,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + + /* Change basic system colors [0-7] to bright system colors [8-15] */ + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) +- fg = &dc.col[base.fg + 8]; ++ fg = &dc.col[base.fg]; + + if (IS_SET(MODE_REVERSE)) { + if (fg == &dc.col[defaultfg]) { diff --git a/st.suckless.org/patches/st-git-20150917-solarized-dark.diff b/st.suckless.org/patches/st-git-20150917-solarized-dark.diff @@ -0,0 +1,65 @@ +diff --git a/config.def.h b/config.def.h +index b6adc5e..9dc0faa 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -70,30 +70,23 @@ static unsigned int tabspaces = 8; + + /* 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 */ + }; + + +@@ -101,9 +94,9 @@ static const char *colorname[] = { + * 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; + + /* + * Default shape of cursor diff --git a/st.suckless.org/patches/st-git-20150917-solarized-light.diff b/st.suckless.org/patches/st-git-20150917-solarized-light.diff @@ -0,0 +1,65 @@ +diff --git a/config.def.h b/config.def.h +index b6adc5e..69dbf07 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -70,30 +70,23 @@ static unsigned int tabspaces = 8; + + /* 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 */ + }; + + +@@ -101,9 +94,9 @@ static const char *colorname[] = { + * 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; + + /* + * Default shape of cursor diff --git a/st.suckless.org/patches/st-git-20150920-openbsd.diff b/st.suckless.org/patches/st-git-20150920-openbsd.diff @@ -0,0 +1,27 @@ +diff --git a/Makefile b/Makefile +index 6158ab2..9b81f88 100644 +--- a/Makefile ++++ b/Makefile +@@ -49,7 +49,8 @@ install: all + @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 +index b6adc5e..ffc2e74 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -63,7 +63,7 @@ static unsigned int cursorthickness = 2; + 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-git-20150922-spoiler.diff b/st.suckless.org/patches/st-git-20150922-spoiler.diff @@ -0,0 +1,22 @@ +diff --git a/st.c b/st.c +index bcf74b3..0763f9f 100644 +--- a/st.c ++++ b/st.c +@@ -3752,9 +3752,14 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + } + + if (base.mode & ATTR_REVERSE) { +- temp = fg; +- fg = bg; +- bg = temp; ++ if (bg == fg) { ++ bg = &dc.col[defaultfg]; ++ fg = &dc.col[defaultbg]; ++ } else { ++ temp = fg; ++ fg = bg; ++ bg = temp; ++ } + } + + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) { diff --git a/st.suckless.org/patches/st-git-20151106-scrollback-mouse.diff b/st.suckless.org/patches/st-git-20151106-scrollback-mouse.diff @@ -0,0 +1,62 @@ +diff --git a/config.def.h b/config.def.h +index 35060d7..30fa7a6 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -137,8 +137,14 @@ static unsigned int defaultunderline = 7; + */ + static MouseShortcut mshortcuts[] = { + /* button mask string */ +- { Button4, XK_ANY_MOD, "\031" }, +- { Button5, XK_ANY_MOD, "\005" }, ++ { Button4, XK_NO_MOD, "\031" }, ++ { Button5, XK_NO_MOD, "\005" }, ++}; ++ ++static MouseKey mkeys[] = { ++ /* button mask function argument */ ++ { Button4, ShiftMask, kscrollup, {.i = 1} }, ++ { Button5, ShiftMask, kscrolldown, {.i = 1} }, + }; + + /* Internal keyboard shortcuts. */ +diff --git a/st.c b/st.c +index 03b9473..91d4230 100644 +--- a/st.c ++++ b/st.c +@@ -322,6 +322,13 @@ typedef union { + } Arg; + + typedef struct { ++ uint b; ++ uint mask; ++ void (*func)(const Arg *); ++ const Arg arg; ++} MouseKey; ++ ++typedef struct { + uint mod; + KeySym keysym; + void (*func)(const Arg *); +@@ -952,6 +959,7 @@ bpress(XEvent *e) + { + struct timespec now; + MouseShortcut *ms; ++ MouseKey *mk; + + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + mousereport(e); +@@ -966,6 +974,14 @@ bpress(XEvent *e) + } + } + ++ for (mk = mkeys; mk < mkeys + LEN(mkeys); mk++) { ++ if (e->xbutton.button == mk->b ++ && match(mk->mask, e->xbutton.state)) { ++ mk->func(&mk->arg); ++ return; ++ } ++ } ++ + if (e->xbutton.button == Button1) { + clock_gettime(CLOCK_MONOTONIC, &now); + diff --git a/st.suckless.org/patches/st-git-20151119-solarized-dark.diff b/st.suckless.org/patches/st-git-20151119-solarized-dark.diff @@ -0,0 +1,68 @@ +diff --git a/config.def.h b/config.def.h +index fd09d72..1c0c1f9 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -69,31 +69,23 @@ static unsigned int tabspaces = 8; + + /* 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", +- "#555555", ++ /* 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 */ + }; + + +@@ -101,10 +93,10 @@ static const char *colorname[] = { + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +-static unsigned int defaultfg = 7; +-static unsigned int defaultbg = 0; +-static unsigned int defaultcs = 256; +-static unsigned int defaultrcs = 257; ++static unsigned int defaultfg = 12; ++static unsigned int defaultbg = 8; ++static unsigned int defaultcs = 14; ++static unsigned int defaultrcs = 15; + + /* + * Default shape of cursor diff --git a/st.suckless.org/patches/st-git-20151119-solarized-light.diff b/st.suckless.org/patches/st-git-20151119-solarized-light.diff @@ -0,0 +1,68 @@ +diff --git a/config.def.h b/config.def.h +index fd09d72..2d3c9d0 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -69,31 +69,23 @@ static unsigned int tabspaces = 8; + + /* 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", +- "#555555", ++ /* 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 */ + }; + + +@@ -101,10 +93,10 @@ static const char *colorname[] = { + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +-static unsigned int defaultfg = 7; +-static unsigned int defaultbg = 0; +-static unsigned int defaultcs = 256; +-static unsigned int defaultrcs = 257; ++static unsigned int defaultfg = 12; ++static unsigned int defaultbg = 8; ++static unsigned int defaultcs = 14; ++static unsigned int defaultrcs = 15; + + /* + * Default shape of cursor diff --git a/st.suckless.org/patches/st-git-20151217-scrollback.diff b/st.suckless.org/patches/st-git-20151217-scrollback.diff @@ -0,0 +1,388 @@ +diff --git a/config.def.h b/config.def.h +index fd09d72..96892f1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -7,6 +7,7 @@ + */ + static char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; + static int borderpx = 2; ++#define histsize 2000 + + /* + * What program is execed by st depends of these precedence rules: +@@ -157,6 +158,8 @@ static Shortcut shortcuts[] = { + { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, + { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, + { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, ++ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, ++ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, + }; + + /* +diff --git a/st.c b/st.c +index c5d62c1..c58c8c5 100644 +--- a/st.c ++++ b/st.c +@@ -85,6 +85,8 @@ char *argv0; + #define TRUERED(x) (((x) & 0xff0000) >> 8) + #define TRUEGREEN(x) (((x) & 0xff00)) + #define TRUEBLUE(x) (((x) & 0xff) << 8) ++#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \ ++ + histsize + 1) % histsize] : term.line[(y) - term.scr]) + + + enum glyph_attribute { +@@ -227,26 +229,6 @@ typedef struct { + int narg; /* nb of args */ + } STREscape; + +-/* Internal representation of the screen */ +-typedef struct { +- int row; /* nb row */ +- int col; /* nb col */ +- Line *line; /* screen */ +- Line *alt; /* alternate screen */ +- int *dirty; /* dirtyness of lines */ +- XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */ +- TCursor c; /* cursor */ +- int top; /* top scroll limit */ +- int bot; /* bottom scroll limit */ +- int mode; /* terminal mode flags */ +- int esc; /* escape state flags */ +- char trantbl[4]; /* charset table translation */ +- int charset; /* current charset */ +- int icharset; /* selected charset for sequence */ +- int numlock; /* lock numbers in keyboard */ +- int *tabs; +-} Term; +- + /* Purely graphic info */ + typedef struct { + Display *dpy; +@@ -326,6 +308,8 @@ typedef struct { + /* function definitions used in config.h */ + static void clipcopy(const Arg *); + static void clippaste(const Arg *); ++static void kscrolldown(const Arg *); ++static void kscrollup(const Arg *); + static void numlock(const Arg *); + static void selpaste(const Arg *); + static void xzoom(const Arg *); +@@ -359,6 +343,29 @@ typedef struct { + GC gc; + } DC; + ++/* Internal representation of the screen */ ++typedef struct { ++ int row; /* nb row */ ++ int col; /* nb col */ ++ Line *line; /* screen */ ++ Line *alt; /* alternate screen */ ++ Line hist[histsize]; /* history buffer */ ++ int histi; /* history index */ ++ int scr; /* scroll back */ ++ int *dirty; /* dirtyness of lines */ ++ XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */ ++ TCursor c; /* cursor */ ++ int top; /* top scroll limit */ ++ int bot; /* bottom scroll limit */ ++ int mode; /* terminal mode flags */ ++ int esc; /* escape state flags */ ++ char trantbl[4]; /* charset table translation */ ++ int charset; /* current charset */ ++ int icharset; /* selected charset for sequence */ ++ int numlock; /* lock numbers in keyboard */ ++ int *tabs; ++} Term; ++ + static void die(const char *, ...); + static void draw(void); + static void redraw(void); +@@ -398,8 +405,8 @@ static void tputtab(int); + static void tputc(Rune); + static void treset(void); + static void tresize(int, int); +-static void tscrollup(int, int); +-static void tscrolldown(int, int); ++static void tscrollup(int, int, int); ++static void tscrolldown(int, int, int); + static void tsetattr(int *, int); + static void tsetchar(Rune, Glyph *, int, int); + static void tsetscroll(int, int); +@@ -730,10 +737,10 @@ tlinelen(int y) + { + int i = term.col; + +- if (term.line[y][i - 1].mode & ATTR_WRAP) ++ if (TLINE(y)[i - 1].mode & ATTR_WRAP) + return i; + +- while (i > 0 && term.line[y][i - 1].u == ' ') ++ while (i > 0 && TLINE(y)[i - 1].u == ' ') + --i; + + return i; +@@ -795,7 +802,7 @@ selsnap(int *x, int *y, int direction) + * Snap around if the word wraps around at the end or + * beginning of a line. + */ +- prevgp = &term.line[*y][*x]; ++ prevgp = &TLINE(*y)[*x]; + prevdelim = ISDELIM(prevgp->u); + for (;;) { + newx = *x + direction; +@@ -810,14 +817,14 @@ selsnap(int *x, int *y, int direction) + yt = *y, xt = *x; + else + yt = newy, xt = newx; +- if (!(term.line[yt][xt].mode & ATTR_WRAP)) ++ if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) + break; + } + + if (newx >= tlinelen(newy)) + break; + +- gp = &term.line[newy][newx]; ++ gp = &TLINE(newy)[newx]; + delim = ISDELIM(gp->u); + if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim + || (delim && gp->u != prevgp->u))) +@@ -838,14 +845,14 @@ selsnap(int *x, int *y, int direction) + *x = (direction < 0) ? 0 : term.col - 1; + if (direction < 0) { + for (; *y > 0; *y += direction) { +- if (!(term.line[*y-1][term.col-1].mode ++ if (!(TLINE(*y-1)[term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } else if (direction > 0) { + for (; *y < term.row-1; *y += direction) { +- if (!(term.line[*y][term.col-1].mode ++ if (!(TLINE(*y)[term.col-1].mode + & ATTR_WRAP)) { + break; + } +@@ -1011,13 +1018,13 @@ getsel(void) + } + + if (sel.type == SEL_RECTANGULAR) { +- gp = &term.line[y][sel.nb.x]; ++ gp = &TLINE(y)[sel.nb.x]; + lastx = sel.ne.x; + } else { +- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; ++ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; + lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; + } +- last = &term.line[y][MIN(lastx, linelen-1)]; ++ last = &TLINE(y)[MIN(lastx, linelen-1)]; + while (last >= gp && last->u == ' ') + --last; + +@@ -1490,6 +1497,9 @@ ttyread(void) + /* keep any uncomplete utf8 char for the next call */ + memmove(buf, ptr, buflen); + ++ if (term.scr > 0 && term.scr < histsize-1) ++ term.scr++; ++ + return ret; + } + +@@ -1499,6 +1509,9 @@ ttywrite(const char *s, size_t n) + fd_set wfd, rfd; + ssize_t r; + size_t lim = 256; ++ Arg arg = (Arg){ .i = term.scr }; ++ ++ kscrolldown(&arg); + + /* + * Remember that we are using a pty, which might be a modem line. +@@ -1690,13 +1703,53 @@ tswapscreen(void) + } + + void +-tscrolldown(int orig, int n) ++kscrolldown(const Arg* a) ++{ ++ int n = a->i; ++ ++ if (n < 0) ++ n = term.row + n; ++ ++ if (n > term.scr) ++ n = term.scr; ++ ++ if (term.scr > 0) { ++ term.scr -= n; ++ selscroll(0, -n); ++ tfulldirt(); ++ } ++} ++ ++void ++kscrollup(const Arg* a) ++{ ++ int n = a->i; ++ ++ if (n < 0) ++ n = term.row + n; ++ ++ if (term.scr <= histsize - n) { ++ term.scr += n; ++ selscroll(0, n); ++ tfulldirt(); ++ } ++} ++ ++void ++tscrolldown(int orig, int n, int copyhist) + { + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + ++ if (copyhist) { ++ term.histi = (term.histi - 1 + histsize) % histsize; ++ temp = term.hist[term.histi]; ++ term.hist[term.histi] = term.line[term.bot]; ++ term.line[term.bot] = temp; ++ } ++ + tsetdirt(orig, term.bot-n); + tclearregion(0, term.bot-n+1, term.col-1, term.bot); + +@@ -1710,13 +1763,20 @@ tscrolldown(int orig, int n) + } + + void +-tscrollup(int orig, int n) ++tscrollup(int orig, int n, int copyhist) + { + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + ++ if (copyhist) { ++ term.histi = (term.histi + 1) % histsize; ++ temp = term.hist[term.histi]; ++ term.hist[term.histi] = term.line[orig]; ++ term.line[orig] = temp; ++ } ++ + tclearregion(0, orig, term.col-1, orig+n-1); + tsetdirt(orig+n, term.bot); + +@@ -1765,7 +1825,7 @@ tnewline(int first_col) + int y = term.c.y; + + if (y == term.bot) { +- tscrollup(term.top, 1); ++ tscrollup(term.top, 1, 1); + } else { + y++; + } +@@ -1930,14 +1990,14 @@ void + tinsertblankline(int n) + { + if (BETWEEN(term.c.y, term.top, term.bot)) +- tscrolldown(term.c.y, n); ++ tscrolldown(term.c.y, n, 0); + } + + void + tdeleteline(int n) + { + if (BETWEEN(term.c.y, term.top, term.bot)) +- tscrollup(term.c.y, n); ++ tscrollup(term.c.y, n, 0); + } + + int32_t +@@ -2371,11 +2431,11 @@ csihandle(void) + break; + case 'S': /* SU -- Scroll <n> line up */ + DEFAULT(csiescseq.arg[0], 1); +- tscrollup(term.top, csiescseq.arg[0]); ++ tscrollup(term.top, csiescseq.arg[0], 0); + break; + case 'T': /* SD -- Scroll <n> line down */ + DEFAULT(csiescseq.arg[0], 1); +- tscrolldown(term.top, csiescseq.arg[0]); ++ tscrolldown(term.top, csiescseq.arg[0], 0); + break; + case 'L': /* IL -- Insert <n> blank lines */ + DEFAULT(csiescseq.arg[0], 1); +@@ -2871,7 +2931,7 @@ eschandle(uchar ascii) + return 0; + case 'D': /* IND -- Linefeed */ + if (term.c.y == term.bot) { +- tscrollup(term.top, 1); ++ tscrollup(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y+1); + } +@@ -2884,7 +2944,7 @@ eschandle(uchar ascii) + break; + case 'M': /* RI -- Reverse index */ + if (term.c.y == term.top) { +- tscrolldown(term.top, 1); ++ tscrolldown(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y-1); + } +@@ -3047,7 +3107,7 @@ tputc(Rune u) + void + tresize(int col, int row) + { +- int i; ++ int i, j; + int minrow = MIN(row, term.row); + int mincol = MIN(col, term.col); + int *bp; +@@ -3087,6 +3147,14 @@ tresize(int col, int row) + term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); + term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); + ++ for (i = 0; i < histsize; i++) { ++ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); ++ for (j = mincol; j < col; j++) { ++ term.hist[i][j] = term.c.attr; ++ term.hist[i][j].u = ' '; ++ } ++ } ++ + /* resize each row to new width, zero-pad if needed */ + for (i = 0; i < minrow; i++) { + term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); +@@ -3984,11 +4052,11 @@ drawregion(int x1, int y1, int x2, int y2) + term.dirty[y] = 0; + + specs = term.specbuf; +- numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); ++ numspecs = xmakeglyphfontspecs(specs, &TLINE(y)[x1], x2 - x1, x1, y); + + i = ox = 0; + for (x = x1; x < x2 && i < numspecs; x++) { +- new = term.line[y][x]; ++ new = TLINE(y)[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (ena_sel && selected(x, y)) +@@ -4008,7 +4076,8 @@ drawregion(int x1, int y1, int x2, int y2) + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y); + } +- xdrawcursor(); ++ if (term.scr == 0) ++ xdrawcursor(); + } + + void + diff --git a/st.suckless.org/patches/st-git-20160131-argbbg.diff b/st.suckless.org/patches/st-git-20160131-argbbg.diff @@ -0,0 +1,161 @@ +diff --git a/config.def.h b/config.def.h +index fd09d72..d2cf4d6 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -96,6 +96,8 @@ static const char *colorname[] = { + "#555555", + }; + ++/* bg opacity */ ++static const int alpha = 0xdd; + + /* + * Default colors (colorname index) +@@ -123,6 +125,7 @@ static unsigned int mousefg = 7; + static unsigned int mousebg = 0; + + /* ++ "black", + * Colors used, when the specific fg == defaultfg. So in reverse mode this + * will reverse too. Another logic would only make the simple feature too + * complex. +diff --git a/config.mk b/config.mk +index 81e3e47..ab35200 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} -lm -lrt -lX11 -lutil -lXft \ ++LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXft -lXrender \ + `pkg-config --libs fontconfig` \ + `pkg-config --libs freetype2` + +diff --git a/st.c b/st.c +index 41f6942..b908778 100644 +--- a/st.c ++++ b/st.c +@@ -61,6 +61,7 @@ char *argv0; + #define XK_ANY_MOD UINT_MAX + #define XK_NO_MOD 0 + #define XK_SWITCH_MOD (1<<13) ++#define OPAQUE 0xff + + /* macros */ + #define MIN(a, b) ((a) < (b) ? (a) : (b)) +@@ -79,6 +80,7 @@ char *argv0; + #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ + (t1.tv_nsec-t2.tv_nsec)/1E6) + #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) ++#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL) + + #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) + #define IS_TRUECOL(x) (1 << 24 & (x)) +@@ -267,6 +269,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 */ + int cursor; /* cursor style */ + } XWindow; +@@ -3137,8 +3140,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); + } +@@ -3192,6 +3194,14 @@ xloadcols(void) + else + die("Could not allocate color %d\n", i); + } ++ ++ /* 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; ++ } ++ + loaded = 1; + } + +@@ -3453,7 +3463,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()) +@@ -3463,7 +3504,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 */ +@@ -3486,16 +3530,17 @@ xinit(void) + if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) + parent = XRootWindow(xw.dpy, xw.scr); + xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, +- 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-git-20160203-scrollback-mouse-altscreen.diff b/st.suckless.org/patches/st-git-20160203-scrollback-mouse-altscreen.diff @@ -0,0 +1,40 @@ +diff --git a/config.def.h b/config.def.h +index db0bf24..1610013 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -143,8 +143,8 @@ static MouseShortcut mshortcuts[] = { + + static MouseKey mkeys[] = { + /* button mask function argument */ +- { Button4, ShiftMask, kscrollup, {.i = 1} }, +- { Button5, ShiftMask, kscrolldown, {.i = 1} }, ++ { Button4, XK_NO_MOD, kscrollup, {.i = 1} }, ++ { Button5, XK_NO_MOD, kscrolldown, {.i = 1} }, + }; + + /* Internal keyboard shortcuts. */ +diff --git a/st.c b/st.c +index 1c9df8f..acb4d8a 100644 +--- a/st.c ++++ b/st.c +@@ -967,13 +967,14 @@ bpress(XEvent *e) + return; + } + +- for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { +- if (e->xbutton.button == ms->b +- && match(ms->mask, e->xbutton.state)) { +- ttysend(ms->s, strlen(ms->s)); +- return; ++ if (IS_SET(MODE_ALTSCREEN)) ++ for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { ++ if (e->xbutton.button == ms->b ++ && match(ms->mask, e->xbutton.state)) { ++ ttysend(ms->s, strlen(ms->s)); ++ return; ++ } + } +- } + + for (mk = mkeys; mk < mkeys + LEN(mkeys); mk++) { + if (e->xbutton.button == mk->b diff --git a/st.suckless.org/patches/st-git-20160204-externalpipe.diff b/st.suckless.org/patches/st-git-20160204-externalpipe.diff @@ -0,0 +1,75 @@ +diff --git a/st.c b/st.c +index 0536b6f..59f982c 100644 +--- a/st.c ++++ b/st.c +@@ -335,6 +335,7 @@ static void printsel(const Arg *); + static void printscreen(const Arg *) ; + static void toggleprinter(const Arg *); + static void sendbreak(const Arg *); ++static void externalpipe(const Arg *); + + /* Config.h for applying patches and the configuration. */ + #include "config.h" +@@ -2923,6 +2924,62 @@ eschandle(uchar ascii) + } + + void ++externalpipe(const Arg *arg) ++{ ++ int to[2]; /* 0 = read, 1 = write */ ++ pid_t child; ++ int n; ++ void (*oldsigpipe)(int); ++ char buf[UTF_SIZ]; ++ Glyph *bp, *end; ++ ++ if(pipe(to) == -1) ++ return; ++ ++ /* sigchld() handles this */ ++ switch(child = fork()){ ++ case -1: ++ close(to[0]), close(to[1]); ++ return; ++ case 0: ++ /* child */ ++ close(to[1]); ++ dup2(to[0], STDIN_FILENO); /* 0<&to */ ++ close(to[0]); ++ execvp( ++ "sh", ++ (char *const []){ ++ "/bin/sh", ++ "-c", ++ (char *)arg->v, ++ 0 ++ }); ++ exit(127); ++ } ++ ++ /* parent */ ++ close(to[0]); ++ /* ignore sigpipe for now, in case child exits early */ ++ oldsigpipe = signal(SIGPIPE, SIG_IGN); ++ ++ for(n = 0; n < term.row; n++){ ++ bp = &term.line[n][0]; ++ end = &bp[MIN(tlinelen(n), term.col) - 1]; ++ if(bp != end || bp->u != ' ') ++ for(; bp <= end; ++bp) ++ if(xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0) ++ break; ++ if(xwrite(to[1], "\n", 1) < 0) ++ break; ++ } ++ ++ close(to[1]); ++ ++ /* restore */ ++ signal(SIGPIPE, oldsigpipe); ++} ++ ++void + tputc(Rune u) + { + char c[UTF_SIZ]; diff --git a/st.suckless.org/patches/st-git-20160209-visualbell.diff b/st.suckless.org/patches/st-git-20160209-visualbell.diff @@ -0,0 +1,42 @@ +diff --git a/st.c b/st.c +index 0536b6f..948de40 100644 +--- a/st.c ++++ b/st.c +@@ -532,6 +532,7 @@ static char *opt_line = NULL; + static char *opt_name = NULL; + static char *opt_title = NULL; + static int oldbutton = 3; /* button event on startup: 3 = release */ ++static int bellon = 0; /* visual bell status */ + + static char *usedfont = NULL; + static double usedfontsize = 0; +@@ -2767,6 +2768,15 @@ tcontrolcode(uchar ascii) + xseturgency(1); + if (bellvolume) + XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); ++ ++ /* visual bell*/ ++ if (!bellon) { ++ bellon = 1; ++ MODBIT(term.mode, !IS_SET(MODE_REVERSE), MODE_REVERSE); ++ redraw(); ++ XFlush(xw.dpy); ++ MODBIT(term.mode, !IS_SET(MODE_REVERSE), MODE_REVERSE); ++ } + } + break; + case '\033': /* ESC */ +@@ -4303,7 +4313,12 @@ run(void) + (handler[ev.type])(&ev); + } + +- draw(); ++ if (bellon) { ++ bellon = 0; ++ redraw(); ++ } ++ else draw(); ++ + XFlush(xw.dpy); + + if (xev && !FD_ISSET(xfd, &rfd)) diff --git a/st.suckless.org/patches/st-git-20160210-copyurl.diff b/st.suckless.org/patches/st-git-20160210-copyurl.diff @@ -0,0 +1,88 @@ +diff --git a/config.def.h b/config.def.h +index fd09d72..05fbba5 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -157,6 +157,7 @@ static Shortcut shortcuts[] = { + { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, + { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, + { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, ++ { MODKEY, XK_l, copyurl, {.i = 0} }, + }; + + /* +diff --git a/st.c b/st.c +index 41f6942..aa5ed41 100644 +--- a/st.c ++++ b/st.c +@@ -335,6 +335,7 @@ static void printsel(const Arg *); + static void printscreen(const Arg *) ; + static void toggleprinter(const Arg *); + static void sendbreak(const Arg *); ++static void copyurl(const Arg *); + + /* Config.h for applying patches and the configuration. */ + #include "config.h" +@@ -4411,3 +4412,63 @@ run: + return 0; + } + ++/* select and copy the previous url on screen (do nothing if there's no url). ++ * known bug: doesn't handle urls that span multiple lines (wontfix) ++ * known bug: only finds first url on line (mightfix) ++ */ ++void ++copyurl(const Arg *arg) { ++ /* () and [] can appear in urls, but excluding them here will reduce false ++ * positives when figuring out where a given url ends. ++ */ ++ static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ "abcdefghijklmnopqrstuvwxyz" ++ "0123456789-._~:/?#@!$&'*+,;=%"; ++ ++ int i, row, startrow; ++ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ ++ char *c, *match = NULL; ++ ++ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y-1 : term.bot; ++ LIMIT(row, term.top, term.bot); ++ startrow = row; ++ ++ /* find the start of the last url before selection */ ++ do { ++ for (i = 0; i < term.col; ++i) { ++ if (term.line[row][i].u > 127) /* assume ascii */ ++ continue; ++ linestr[i] = term.line[row][i].u; ++ } ++ linestr[term.col] = '\0'; ++ if ((match = strstr(linestr, "http://")) ++ || (match = strstr(linestr, "https://"))) ++ break; ++ if (--row < term.top) ++ row = term.bot; ++ } while (row != startrow); ++ ++ if (match) { ++ /* must happen before trim */ ++ selclear(NULL); ++ sel.ob.x = strlen(linestr) - strlen(match); ++ ++ /* trim the rest of the line from the url match */ ++ for (c = match; *c != '\0'; ++c) ++ if (!strchr(URLCHARS, *c)) { ++ *c = '\0'; ++ break; ++ } ++ ++ /* select and copy */ ++ sel.mode = 1; ++ sel.type = SEL_REGULAR; ++ sel.oe.x = sel.ob.x + strlen(match)-1; ++ sel.ob.y = sel.oe.y = row; ++ selnormalize(); ++ tsetdirt(sel.nb.y, sel.ne.y); ++ selcopy(0); ++ } ++ ++ free(linestr); ++} diff --git a/st.suckless.org/patches/st-git-delkey.diff b/st.suckless.org/patches/st-git-delkey.diff @@ -1,45 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 930e468..b427840 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -228,7 +228,7 @@ static Key key[] = { - { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0, 0}, - { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, - { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, -- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, -+ { XK_KP_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, - { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0, 0}, - { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0, 0}, - { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0, 0}, -@@ -283,8 +283,7 @@ static Key key[] = { - { XK_Delete, ShiftMask, "\033[2K", -1, 0, 0}, - { XK_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, - { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, -- { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, -- { XK_BackSpace, XK_NO_MOD, "\177", 0, 0, 0}, -+ { XK_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, - { XK_Home, ShiftMask, "\033[2J", 0, -1, 0}, - { XK_Home, ShiftMask, "\033[1;2H", 0, +1, 0}, - { XK_Home, XK_ANY_MOD, "\033[H", 0, -1, 0}, -diff --git a/st.info b/st.info -index 2acd8b2..21b4734 100644 ---- a/st.info -+++ b/st.info -@@ -53,7 +53,7 @@ st| simpleterm, - ka3=\E[5~, - kc1=\E[4~, - kc3=\E[6~, -- kbs=\177, -+ kbs=\010, - kcbt=\E[Z, - kb2=\EOu, - kcub1=\EOD, -@@ -73,7 +73,7 @@ st| simpleterm, - kri=\E[1;2A, - kclr=\E[3;5~, - kdl1=\E[3;2~, -- kdch1=\E[3~, -+ kdch1=\177~, - kich1=\E[2~, - kend=\E[4~, - kf1=\EOP, diff --git a/st.suckless.org/patches/st-git-hidexcursor.diff b/st.suckless.org/patches/st-git-hidexcursor.diff @@ -1,104 +0,0 @@ -From 679b7353a8a6146c81f9fbb5a4012324e87f8008 Mon Sep 17 00:00:00 2001 -From: Ivan Delalande <colona@ycc.fr> -Date: Thu, 30 Jul 2015 01:53:26 -0700 -Subject: [PATCH] Hide X mouse cursor when typing. - -Hide the X cursor when typing in the terminal. The cursor is displayed again -when the mouse is moved. - -[ s/cursor/pointer - Alex Pilon ] ---- - st.c | 32 ++++++++++++++++++++++++++++---- - 1 file changed, 28 insertions(+), 4 deletions(-) - -diff --git a/st.c b/st.c -index 1df4fde..96b58e3 100644 ---- a/st.c -+++ b/st.c -@@ -258,6 +258,11 @@ typedef struct { - Draw draw; - Visual *vis; - XSetWindowAttributes attrs; -+ /* Here, we use the term *pointer* to differentiate the cursor -+ * one sees when hovering the mouse over the terminal from, e.g., -+ * a green rectangle where text would be entered. */ -+ Cursor vpointer, bpointer; /* visible and hidden pointers */ -+ int pointerisvisible; - int scr; - int isfixed; /* is fixed geometry? */ - int l, t; /* left and top offset */ -@@ -1285,6 +1290,13 @@ bmotion(XEvent *e) - { - int oldey, oldex, oldsby, oldsey; - -+ if(!xw.pointerisvisible) { -+ XDefineCursor(xw.dpy, xw.win, xw.vpointer); -+ xw.pointerisvisible = 1; -+ if(!IS_SET(MODE_MOUSEMANY)) -+ xsetpointermotion(0); -+ } -+ - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { - mousereport(e); - return; -@@ -3408,10 +3420,10 @@ void - xinit(void) - { - XGCValues gcvalues; -- Cursor cursor; - Window parent; - pid_t thispid = getpid(); - XColor xmousefg, xmousebg; -+ Pixmap blankpm; - - if (!(xw.dpy = XOpenDisplay(NULL))) - die("Can't open display\n"); -@@ -3484,8 +3496,9 @@ xinit(void) - die("XCreateIC failed. Could not obtain input method.\n"); - - /* white cursor, black outline */ -- cursor = XCreateFontCursor(xw.dpy, mouseshape); -- XDefineCursor(xw.dpy, xw.win, cursor); -+ xw.pointerisvisible = 1; -+ xw.vpointer = XCreateFontCursor(xw.dpy, mouseshape); -+ XDefineCursor(xw.dpy, xw.win, xw.vpointer); - - if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) { - xmousefg.red = 0xffff; -@@ -3499,7 +3512,10 @@ xinit(void) - xmousebg.blue = 0x0000; - } - -- XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); -+ XRecolorCursor(xw.dpy, xw.vpointer, &xmousefg, &xmousebg); -+ blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1); -+ xw.bpointer = XCreatePixmapCursor(xw.dpy, blankpm, blankpm, -+ &xmousefg, &xmousebg, 0, 0); - - xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); - xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); -@@ -3974,6 +3990,8 @@ unmap(XEvent *ev) - void - xsetpointermotion(int set) - { -+ if(!set && !xw.pointerisvisible) -+ return; - MODBIT(xw.attrs.event_mask, set, PointerMotionMask); - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); - } -@@ -4073,6 +4091,12 @@ kpress(XEvent *ev) - Status status; - Shortcut *bp; - -+ if(xw.pointerisvisible) { -+ XDefineCursor(xw.dpy, xw.win, xw.bpointer); -+ xsetpointermotion(1); -+ xw.pointerisvisible = 0; -+ } -+ - if (IS_SET(MODE_KBDLOCK)) - return; - --- -2.4.6 - diff --git a/st.suckless.org/patches/st-no-bold-colors.diff b/st.suckless.org/patches/st-no-bold-colors.diff @@ -1,13 +0,0 @@ -diff --git a/st.c b/st.c -index 64e2cec..13ceadc 100644 ---- a/st.c -+++ b/st.c -@@ -3680,7 +3680,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i - - /* Change basic system colors [0-7] to bright system colors [8-15] */ - if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) -- fg = &dc.col[base.fg + 8]; -+ fg = &dc.col[base.fg]; - - if (IS_SET(MODE_REVERSE)) { - if (fg == &dc.col[defaultfg]) { diff --git a/st.suckless.org/patches/st-on-openbsd.diff b/st.suckless.org/patches/st-on-openbsd.diff @@ -1,25 +0,0 @@ -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-scrollback-shift-mouse.diff b/st.suckless.org/patches/st-scrollback-shift-mouse.diff @@ -1,408 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 930e468..0601fe5 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -7,6 +7,7 @@ - */ - static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=false"; - static int borderpx = 2; -+static int histsize = 2000; - - /* - * What program is execed by st depends of these precedence rules: -@@ -123,10 +124,16 @@ static unsigned int defaultunderline = 7; - - /* Internal mouse shortcuts. */ - /* Beware that overloading Button1 will disable the selection. */ --static Mousekey mshortcuts[] = { -+static Mousekey mkeys[] = { - /* button mask string */ -- { Button4, XK_ANY_MOD, "\031" }, -- { Button5, XK_ANY_MOD, "\005" }, -+ { Button4, XK_NO_MOD, "\031" }, -+ { Button5, XK_NO_MOD, "\005" }, -+}; -+ -+static MouseShortcut mshortcuts[] = { -+ /* button mask function argument */ -+ { Button4, ShiftMask, kscrollup, { .i = 1 } }, -+ { Button5, ShiftMask, kscrolldown, { .i = 1 } }, - }; - - /* Internal keyboard shortcuts. */ -@@ -145,6 +152,8 @@ static Shortcut shortcuts[] = { - { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, - { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, - { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, -+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, -+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, - }; - - /* -diff --git a/st.c b/st.c -index 35a840b..bb97783 100644 ---- a/st.c -+++ b/st.c -@@ -84,6 +84,8 @@ char *argv0; - #define TRUERED(x) (((x) & 0xff0000) >> 8) - #define TRUEGREEN(x) (((x) & 0xff00)) - #define TRUEBLUE(x) (((x) & 0xff) << 8) -+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \ -+ + histsize + 1) % histsize] : term.line[(y) - term.scr]) - - - enum glyph_attribute { -@@ -232,6 +234,9 @@ typedef struct { - int col; /* nb col */ - Line *line; /* screen */ - Line *alt; /* alternate screen */ -+ Line *hist; /* history buffer */ -+ int histi; /* history index */ -+ int scr; /* scroll back */ - int *dirty; /* dirtyness of lines */ - XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */ - TCursor c; /* cursor */ -@@ -316,6 +321,13 @@ typedef union { - } Arg; - - typedef struct { -+ uint b; -+ uint mask; -+ void (*func)(const Arg *); -+ const Arg arg; -+} MouseShortcut; -+ -+typedef struct { - uint mod; - KeySym keysym; - void (*func)(const Arg *); -@@ -325,6 +337,8 @@ typedef struct { - /* function definitions used in config.h */ - static void clipcopy(const Arg *); - static void clippaste(const Arg *); -+static void kscrolldown(const Arg *); -+static void kscrollup(const Arg *); - static void numlock(const Arg *); - static void selpaste(const Arg *); - static void xzoom(const Arg *); -@@ -396,8 +410,8 @@ static void tputtab(int); - static void tputc(Rune); - static void treset(void); - static void tresize(int, int); --static void tscrollup(int, int); --static void tscrolldown(int, int); -+static void tscrollup(int, int, int); -+static void tscrolldown(int, int, int); - static void tsetattr(int *, int); - static void tsetchar(Rune, Glyph *, int, int); - static void tsetscroll(int, int); -@@ -727,10 +741,10 @@ tlinelen(int y) - { - int i = term.col; - -- if (term.line[y][i - 1].mode & ATTR_WRAP) -+ if (TLINE(y)[i - 1].mode & ATTR_WRAP) - return i; - -- while (i > 0 && term.line[y][i - 1].u == ' ') -+ while (i > 0 && TLINE(y)[i - 1].u == ' ') - --i; - - return i; -@@ -792,7 +806,7 @@ selsnap(int *x, int *y, int direction) - * Snap around if the word wraps around at the end or - * beginning of a line. - */ -- prevgp = &term.line[*y][*x]; -+ prevgp = &TLINE(*y)[*x]; - prevdelim = ISDELIM(prevgp->u); - for (;;) { - newx = *x + direction; -@@ -807,14 +821,14 @@ selsnap(int *x, int *y, int direction) - yt = *y, xt = *x; - else - yt = newy, xt = newx; -- if (!(term.line[yt][xt].mode & ATTR_WRAP)) -+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) - break; - } - - if (newx >= tlinelen(newy)) - break; - -- gp = &term.line[newy][newx]; -+ gp = &TLINE(newy)[newx]; - delim = ISDELIM(gp->u); - if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim - || (delim && gp->u != prevgp->u))) -@@ -835,14 +849,14 @@ selsnap(int *x, int *y, int direction) - *x = (direction < 0) ? 0 : term.col - 1; - if (direction < 0) { - for (; *y > 0; *y += direction) { -- if (!(term.line[*y-1][term.col-1].mode -+ if (!(TLINE(*y-1)[term.col-1].mode - & ATTR_WRAP)) { - break; - } - } - } else if (direction > 0) { - for (; *y < term.row-1; *y += direction) { -- if (!(term.line[*y][term.col-1].mode -+ if (!(TLINE(*y)[term.col-1].mode - & ATTR_WRAP)) { - break; - } -@@ -942,13 +956,14 @@ bpress(XEvent *e) - { - struct timespec now; - Mousekey *mk; -+ MouseShortcut *ms; - - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { - mousereport(e); - return; - } - -- for (mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) { -+ for (mk = mkeys; mk < mkeys + LEN(mkeys); mk++) { - if (e->xbutton.button == mk->b - && match(mk->mask, e->xbutton.state)) { - ttysend(mk->s, strlen(mk->s)); -@@ -956,6 +971,14 @@ bpress(XEvent *e) - } - } - -+ for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { -+ if (e->xbutton.button == ms->b -+ && match(ms->mask, e->xbutton.state)) { -+ ms->func(&ms->arg); -+ return; -+ } -+ } -+ - if (e->xbutton.button == Button1) { - clock_gettime(CLOCK_MONOTONIC, &now); - -@@ -1005,13 +1028,13 @@ getsel(void) - linelen = tlinelen(y); - - if (sel.type == SEL_RECTANGULAR) { -- gp = &term.line[y][sel.nb.x]; -+ gp = &TLINE(y)[sel.nb.x]; - lastx = sel.ne.x; - } else { -- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; -+ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; - lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; - } -- last = &term.line[y][MIN(lastx, linelen-1)]; -+ last = &TLINE(y)[MIN(lastx, linelen-1)]; - while (last >= gp && last->u == ' ') - --last; - -@@ -1484,6 +1507,8 @@ ttyread(void) - - /* keep any uncomplete utf8 char for the next call */ - memmove(buf, ptr, buflen); -+ if (term.scr > 0 && term.scr < histsize-1) -+ term.scr++; - } - - void -@@ -1492,6 +1517,9 @@ ttywrite(const char *s, size_t n) - fd_set wfd; - struct timespec tv; - ssize_t r; -+ Arg arg = (Arg){ .i = term.scr }; -+ -+ kscrolldown(&arg); - - /* - * Remember that we are using a pty, which might be a modem line. -@@ -1682,13 +1710,53 @@ tswapscreen(void) - } - - void --tscrolldown(int orig, int n) -+kscrolldown(const Arg* a) -+{ -+ int n = a->i; -+ -+ if (n < 0) -+ n = term.row + n; -+ -+ if (n > term.scr) -+ n = term.scr; -+ -+ if (term.scr > 0) { -+ term.scr -= n; -+ selscroll(0, -n); -+ tfulldirt(); -+ } -+} -+ -+void -+kscrollup(const Arg* a) -+{ -+ int n = a->i; -+ -+ if (n < 0) -+ n = term.row + n; -+ -+ if (term.scr <= histsize - n) { -+ term.scr += n; -+ selscroll(0, n); -+ tfulldirt(); -+ } -+} -+ -+void -+tscrolldown(int orig, int n, int copyhist) - { - int i; - Line temp; - - LIMIT(n, 0, term.bot-orig+1); - -+ if (copyhist) { -+ term.histi = (term.histi - 1 + histsize) % histsize; -+ temp = term.hist[term.histi]; -+ term.hist[term.histi] = term.line[term.bot]; -+ term.line[term.bot] = temp; -+ } -+ - tsetdirt(orig, term.bot-n); - tclearregion(0, term.bot-n+1, term.col-1, term.bot); - -@@ -1702,13 +1770,20 @@ tscrolldown(int orig, int n) - } - - void --tscrollup(int orig, int n) -+tscrollup(int orig, int n, int copyhist) - { - int i; - Line temp; - - LIMIT(n, 0, term.bot-orig+1); - -+ if (copyhist) { -+ term.histi = (term.histi + 1) % histsize; -+ temp = term.hist[term.histi]; -+ term.hist[term.histi] = term.line[orig]; -+ term.line[orig] = temp; -+ } -+ - tclearregion(0, orig, term.col-1, orig+n-1); - tsetdirt(orig+n, term.bot); - -@@ -1757,7 +1832,7 @@ tnewline(int first_col) - int y = term.c.y; - - if (y == term.bot) { -- tscrollup(term.top, 1); -+ tscrollup(term.top, 1, 1); - } else { - y++; - } -@@ -1922,14 +1997,14 @@ void - tinsertblankline(int n) - { - if (BETWEEN(term.c.y, term.top, term.bot)) -- tscrolldown(term.c.y, n); -+ tscrolldown(term.c.y, n, 0); - } - - void - tdeleteline(int n) - { - if (BETWEEN(term.c.y, term.top, term.bot)) -- tscrollup(term.c.y, n); -+ tscrollup(term.c.y, n, 0); - } - - int32_t -@@ -2363,11 +2438,11 @@ csihandle(void) - break; - case 'S': /* SU -- Scroll <n> line up */ - DEFAULT(csiescseq.arg[0], 1); -- tscrollup(term.top, csiescseq.arg[0]); -+ tscrollup(term.top, csiescseq.arg[0], 0); - break; - case 'T': /* SD -- Scroll <n> line down */ - DEFAULT(csiescseq.arg[0], 1); -- tscrolldown(term.top, csiescseq.arg[0]); -+ tscrolldown(term.top, csiescseq.arg[0], 0); - break; - case 'L': /* IL -- Insert <n> blank lines */ - DEFAULT(csiescseq.arg[0], 1); -@@ -2837,7 +2912,7 @@ eschandle(uchar ascii) - return 0; - case 'D': /* IND -- Linefeed */ - if (term.c.y == term.bot) { -- tscrollup(term.top, 1); -+ tscrollup(term.top, 1, 1); - } else { - tmoveto(term.c.x, term.c.y+1); - } -@@ -2850,7 +2925,7 @@ eschandle(uchar ascii) - break; - case 'M': /* RI -- Reverse index */ - if (term.c.y == term.top) { -- tscrolldown(term.top, 1); -+ tscrolldown(term.top, 1, 1); - } else { - tmoveto(term.c.x, term.c.y-1); - } -@@ -3013,7 +3088,7 @@ tputc(Rune u) - void - tresize(int col, int row) - { -- int i; -+ int i, j; - int minrow = MIN(row, term.row); - int mincol = MIN(col, term.col); - int *bp; -@@ -3050,9 +3125,18 @@ tresize(int col, int row) - /* resize to new height */ - term.line = xrealloc(term.line, row * sizeof(Line)); - term.alt = xrealloc(term.alt, row * sizeof(Line)); -+ term.hist = xrealloc(term.hist, histsize * sizeof(Line)); - term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); - term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); - -+ for (i = 0; i < histsize; i++) { -+ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); -+ for (j = mincol; j < col; j++) { -+ term.hist[i][j] = term.c.attr; -+ term.hist[i][j].u = ' '; -+ } -+ } -+ - /* resize each row to new width, zero-pad if needed */ - for (i = 0; i < minrow; i++) { - term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); -@@ -3924,11 +4008,11 @@ drawregion(int x1, int y1, int x2, int y2) - term.dirty[y] = 0; - - specs = term.specbuf; -- numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); -+ numspecs = xmakeglyphfontspecs(specs, &TLINE(y)[x1], x2 - x1, x1, y); - - i = ox = 0; - for (x = x1; x < x2 && i < numspecs; x++) { -- new = term.line[y][x]; -+ new = TLINE(y)[x]; - if (new.mode == ATTR_WDUMMY) - continue; - if (ena_sel && selected(x, y)) -@@ -3948,7 +4032,8 @@ drawregion(int x1, int y1, int x2, int y2) - if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y); - } -- xdrawcursor(); -+ if (term.scr == 0) -+ xdrawcursor(); - } - - void diff --git a/st.suckless.org/patches/st-scrollback.diff b/st.suckless.org/patches/st-scrollback.diff @@ -1,343 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 930e468..14d94fe 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -7,6 +7,7 @@ - */ - static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=false"; - static int borderpx = 2; -+static int histsize = 2000; - - /* - * What program is execed by st depends of these precedence rules: -@@ -145,6 +146,8 @@ static Shortcut shortcuts[] = { - { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, - { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, - { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, -+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, -+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, - }; - - /* -diff --git a/st.c b/st.c -index 1df4fde..91f95a8 100644 ---- a/st.c -+++ b/st.c -@@ -84,6 +84,8 @@ char *argv0; - #define TRUERED(x) (((x) & 0xff0000) >> 8) - #define TRUEGREEN(x) (((x) & 0xff00)) - #define TRUEBLUE(x) (((x) & 0xff) << 8) -+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \ -+ + histsize + 1) % histsize] : term.line[(y) - term.scr]) - - - enum glyph_attribute { -@@ -232,6 +234,9 @@ typedef struct { - int col; /* nb col */ - Line *line; /* screen */ - Line *alt; /* alternate screen */ -+ Line *hist; /* history buffer */ -+ int histi; /* history index */ -+ int scr; /* scroll back */ - int *dirty; /* dirtyness of lines */ - XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */ - TCursor c; /* cursor */ -@@ -325,6 +330,8 @@ typedef struct { - /* function definitions used in config.h */ - static void clipcopy(const Arg *); - static void clippaste(const Arg *); -+static void kscrolldown(const Arg *); -+static void kscrollup(const Arg *); - static void numlock(const Arg *); - static void selpaste(const Arg *); - static void xzoom(const Arg *); -@@ -396,8 +403,8 @@ static void tputtab(int); - static void tputc(Rune); - static void treset(void); - static void tresize(int, int); --static void tscrollup(int, int); --static void tscrolldown(int, int); -+static void tscrollup(int, int, int); -+static void tscrolldown(int, int, int); - static void tsetattr(int *, int); - static void tsetchar(Rune, Glyph *, int, int); - static void tsetscroll(int, int); -@@ -727,10 +734,10 @@ tlinelen(int y) - { - int i = term.col; - -- if (term.line[y][i - 1].mode & ATTR_WRAP) -+ if (TLINE(y)[i - 1].mode & ATTR_WRAP) - return i; - -- while (i > 0 && term.line[y][i - 1].u == ' ') -+ while (i > 0 && TLINE(y)[i - 1].u == ' ') - --i; - - return i; -@@ -792,7 +799,7 @@ selsnap(int *x, int *y, int direction) - * Snap around if the word wraps around at the end or - * beginning of a line. - */ -- prevgp = &term.line[*y][*x]; -+ prevgp = &TLINE(*y)[*x]; - prevdelim = ISDELIM(prevgp->u); - for (;;) { - newx = *x + direction; -@@ -807,14 +814,14 @@ selsnap(int *x, int *y, int direction) - yt = *y, xt = *x; - else - yt = newy, xt = newx; -- if (!(term.line[yt][xt].mode & ATTR_WRAP)) -+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) - break; - } - - if (newx >= tlinelen(newy)) - break; - -- gp = &term.line[newy][newx]; -+ gp = &TLINE(newy)[newx]; - delim = ISDELIM(gp->u); - if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim - || (delim && gp->u != prevgp->u))) -@@ -835,14 +842,14 @@ selsnap(int *x, int *y, int direction) - *x = (direction < 0) ? 0 : term.col - 1; - if (direction < 0) { - for (; *y > 0; *y += direction) { -- if (!(term.line[*y-1][term.col-1].mode -+ if (!(TLINE(*y-1)[term.col-1].mode - & ATTR_WRAP)) { - break; - } - } - } else if (direction > 0) { - for (; *y < term.row-1; *y += direction) { -- if (!(term.line[*y][term.col-1].mode -+ if (!(TLINE(*y)[term.col-1].mode - & ATTR_WRAP)) { - break; - } -@@ -1005,13 +1012,13 @@ getsel(void) - linelen = tlinelen(y); - - if (sel.type == SEL_RECTANGULAR) { -- gp = &term.line[y][sel.nb.x]; -+ gp = &TLINE(y)[sel.nb.x]; - lastx = sel.ne.x; - } else { -- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; -+ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; - lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; - } -- last = &term.line[y][MIN(lastx, linelen-1)]; -+ last = &TLINE(y)[MIN(lastx, linelen-1)]; - while (last >= gp && last->u == ' ') - --last; - -@@ -1484,6 +1491,8 @@ ttyread(void) - - /* keep any uncomplete utf8 char for the next call */ - memmove(buf, ptr, buflen); -+ if (term.scr > 0 && term.scr < histsize-1) -+ term.scr++; - } - - void -@@ -1492,6 +1501,9 @@ ttywrite(const char *s, size_t n) - fd_set wfd; - struct timespec tv; - ssize_t r; -+ Arg arg = (Arg){ .i = term.scr }; -+ -+ kscrolldown(&arg); - - /* - * Remember that we are using a pty, which might be a modem line. -@@ -1682,13 +1694,53 @@ tswapscreen(void) - } - - void --tscrolldown(int orig, int n) -+kscrolldown(const Arg* a) -+{ -+ int n = a->i; -+ -+ if (n < 0) -+ n = term.row + n; -+ -+ if (n > term.scr) -+ n = term.scr; -+ -+ if (term.scr > 0) { -+ term.scr -= n; -+ selscroll(0, -n); -+ tfulldirt(); -+ } -+} -+ -+void -+kscrollup(const Arg* a) -+{ -+ int n = a->i; -+ -+ if (n < 0) -+ n = term.row + n; -+ -+ if (term.scr <= histsize - n) { -+ term.scr += n; -+ selscroll(0, n); -+ tfulldirt(); -+ } -+} -+ -+void -+tscrolldown(int orig, int n, int copyhist) - { - int i; - Line temp; - - LIMIT(n, 0, term.bot-orig+1); - -+ if (copyhist) { -+ term.histi = (term.histi - 1 + histsize) % histsize; -+ temp = term.hist[term.histi]; -+ term.hist[term.histi] = term.line[term.bot]; -+ term.line[term.bot] = temp; -+ } -+ - tsetdirt(orig, term.bot-n); - tclearregion(0, term.bot-n+1, term.col-1, term.bot); - -@@ -1702,13 +1754,20 @@ tscrolldown(int orig, int n) - } - - void --tscrollup(int orig, int n) -+tscrollup(int orig, int n, int copyhist) - { - int i; - Line temp; - - LIMIT(n, 0, term.bot-orig+1); - -+ if (copyhist) { -+ term.histi = (term.histi + 1) % histsize; -+ temp = term.hist[term.histi]; -+ term.hist[term.histi] = term.line[orig]; -+ term.line[orig] = temp; -+ } -+ - tclearregion(0, orig, term.col-1, orig+n-1); - tsetdirt(orig+n, term.bot); - -@@ -1757,7 +1816,7 @@ tnewline(int first_col) - int y = term.c.y; - - if (y == term.bot) { -- tscrollup(term.top, 1); -+ tscrollup(term.top, 1, 1); - } else { - y++; - } -@@ -1922,14 +1981,14 @@ void - tinsertblankline(int n) - { - if (BETWEEN(term.c.y, term.top, term.bot)) -- tscrolldown(term.c.y, n); -+ tscrolldown(term.c.y, n, 0); - } - - void - tdeleteline(int n) - { - if (BETWEEN(term.c.y, term.top, term.bot)) -- tscrollup(term.c.y, n); -+ tscrollup(term.c.y, n, 0); - } - - int32_t -@@ -2363,11 +2422,11 @@ csihandle(void) - break; - case 'S': /* SU -- Scroll <n> line up */ - DEFAULT(csiescseq.arg[0], 1); -- tscrollup(term.top, csiescseq.arg[0]); -+ tscrollup(term.top, csiescseq.arg[0], 0); - break; - case 'T': /* SD -- Scroll <n> line down */ - DEFAULT(csiescseq.arg[0], 1); -- tscrolldown(term.top, csiescseq.arg[0]); -+ tscrolldown(term.top, csiescseq.arg[0], 0); - break; - case 'L': /* IL -- Insert <n> blank lines */ - DEFAULT(csiescseq.arg[0], 1); -@@ -2837,7 +2896,7 @@ eschandle(uchar ascii) - return 0; - case 'D': /* IND -- Linefeed */ - if (term.c.y == term.bot) { -- tscrollup(term.top, 1); -+ tscrollup(term.top, 1, 1); - } else { - tmoveto(term.c.x, term.c.y+1); - } -@@ -2850,7 +2909,7 @@ eschandle(uchar ascii) - break; - case 'M': /* RI -- Reverse index */ - if (term.c.y == term.top) { -- tscrolldown(term.top, 1); -+ tscrolldown(term.top, 1, 1); - } else { - tmoveto(term.c.x, term.c.y-1); - } -@@ -3013,7 +3072,7 @@ tputc(Rune u) - void - tresize(int col, int row) - { -- int i; -+ int i, j; - int minrow = MIN(row, term.row); - int mincol = MIN(col, term.col); - int *bp; -@@ -3050,9 +3109,18 @@ tresize(int col, int row) - /* resize to new height */ - term.line = xrealloc(term.line, row * sizeof(Line)); - term.alt = xrealloc(term.alt, row * sizeof(Line)); -+ term.hist = xrealloc(term.hist, histsize * sizeof(Line)); - term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); - term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); - -+ for (i = 0; i < histsize; i++) { -+ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); -+ for (j = mincol; j < col; j++) { -+ term.hist[i][j] = term.c.attr; -+ term.hist[i][j].u = ' '; -+ } -+ } -+ - /* resize each row to new width, zero-pad if needed */ - for (i = 0; i < minrow; i++) { - term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); -@@ -3924,11 +3992,11 @@ drawregion(int x1, int y1, int x2, int y2) - term.dirty[y] = 0; - - specs = term.specbuf; -- numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); -+ numspecs = xmakeglyphfontspecs(specs, &TLINE(y)[x1], x2 - x1, x1, y); - - i = ox = 0; - for (x = x1; x < x2 && i < numspecs; x++) { -- new = term.line[y][x]; -+ new = TLINE(y)[x]; - if (new.mode == ATTR_WDUMMY) - continue; - if (ena_sel && selected(x, y)) -@@ -3948,7 +4016,8 @@ drawregion(int x1, int y1, int x2, int y2) - if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y); - } -- xdrawcursor(); -+ if (term.scr == 0) -+ xdrawcursor(); - } - - void diff --git a/st.suckless.org/patches/st-solarized-dark.diff b/st.suckless.org/patches/st-solarized-dark.diff @@ -1,64 +0,0 @@ -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-light.diff b/st.suckless.org/patches/st-solarized-light.diff @@ -1,64 +0,0 @@ -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_on_openbsd.md b/st.suckless.org/patches/st_on_openbsd.md @@ -1,42 +0,0 @@ -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/patches/visualbell.md b/st.suckless.org/patches/visualbell.md @@ -0,0 +1,24 @@ +visualbell +========== + +Description +----------- + +Briefly inverts window content on terminal bell event. + +Notes +----- + +In order to be noticeable you might have to reduce the `xfps` +value in `config.h` to less than equal the refresh rate of your +monitor. + +Download +-------- + + * [st-git-20160209-visualbell.diff](st-git-20160209-visualbell.diff) + +Authors +------- + + * Matthias Schoth - mschoth@gmail.com diff --git a/st.suckless.org/patches/wordbreak.md b/st.suckless.org/patches/wordbreak.md @@ -0,0 +1,29 @@ +wordbreak +========= + +Description +----------- + +This patch allows you to configure which characters are used as +word boundaries for double click selections (instead of just ' '). +This feature is already implemented in all versions later than 0.5. + +Usage +----- + +config.h example: + + #define WORD_BREAK " ()<>[]\"" + +Download +-------- +* [st-0.3-wordbreak.diff](st-0.3-wordbreak.diff) +* [st-0.4-wordbreak.diff](st-0.4-wordbreak.diff) +* [st-0.4.1-wordbreak.diff](st-0.4.1-wordbreak.diff) +* [st-0.5-wordbreak.diff](st-0.5-wordbreak.diff) + +Authors +------- + + * Stephen Paul Weber - singpolyma@singpolyma.net + * Laslo Hunhold - dev@frign.de (st-0.4, st-0.4.1, st-0.5 ports) diff --git a/st.suckless.org/patches/xterm_fallback.diff b/st.suckless.org/patches/xterm_fallback.diff @@ -1,51 +0,0 @@ -From 592c9f76bd234a12131a67e7c6dfdffa2f04f6e8 Mon Sep 17 00:00:00 2001 -From: Alex Kozadaev <akozadaev at yahoo com> -Date: Wed, 12 Aug 2015 09:02:36 +0100 -Subject: [PATCH] Wrapper for xterm to fix missing .terminfo. - -The patch allows automatic fallback to xterm and xterm-256color in case the st -and st-256color is not available. This setup allows hassle-free work on multiple -remote SSH servers when uploading .terminfo on every one of them isn't an option. ---- - config.def.h | 2 +- - st.info | 7 ++++++- - 2 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 930e468..61c6c50 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -63,7 +63,7 @@ static unsigned int cursorthickness = 2; - static int bellvolume = 0; - - /* TERM value */ --static char termname[] = "st-256color"; -+static char termname[] = "xterm"; - - static unsigned int tabspaces = 8; - -diff --git a/st.info b/st.info -index b70fefa..72ea938 100644 ---- a/st.info -+++ b/st.info -@@ -187,7 +187,6 @@ st| simpleterm, - xenl, - vpa=\E[%i%p1%dd, - -- - st-256color| simpleterm with 256 colors, - use=st, - colors#256, -@@ -211,3 +210,9 @@ st-meta-256color| simpleterm with meta key and 256 colors, - smm=\E[?1034h, - rs2=\E[4l\E>\E[?1034h, - is2=\E[4l\E>\E[?1034h, -+ -+xterm| st, -+ use=st, -+ -+xterm-256color| st-256-color, -+ use=st-256color, --- -2.1.4 - diff --git a/st.suckless.org/patches/xterm_fallback.md b/st.suckless.org/patches/xterm_fallback.md @@ -1,22 +0,0 @@ -#XTerm fallback - -##Description -The patch redefines xterm and xterm-256color terminals to be aliases of st and st-256color respsectively. If the st terminfo is installed - the st terminal is used. If however it is not - the terminal falls back to the xterm terminal and thus ensures seamless operation on a remote SSH servers. - -*PLEASE NOTE: This patch assumes the st is the only terminal in the system. If it is not the case however, please see alternative solution as recommended by Roberto E. Vargas Caballero (k0ga)* - -##Download - -* [xterm_fallback.diff](xterm_fallback.diff) - -or - -add the following in the .bashrc (thanks k0ga): - -```bash - alias ssh='TERM=xterm ssh' -``` - -##Author - -[Alex Kozadaev](snobb@gmx.com) diff --git a/st.suckless.org/screenshots/index.md b/st.suckless.org/screenshots/index.md @@ -1,6 +1,5 @@ -[![Screenshot](putain-ouais-s.png)](putain-ouais.png) +->[![st screenshot](putain-ouais-s.png)](putain-ouais.png)<- -[![Screenshot](hendry-s.png)](hendry.png) - -[![Screenshot](20h-2012-s.png)](20h-2012.png) +->[![st screenshot](hendry-s.png)](hendry.png)<- +->[![st screenshot](20h-2012-s.png)](20h-2012.png)<- diff --git a/sta.li/README b/sta.li/README @@ -0,0 +1 @@ +Moved to [git.sta.li/sites](http://git.sta.li/sites) diff --git a/sta.li/_werc/config b/sta.li/_werc/config @@ -1,3 +0,0 @@ -siteTitle='sta.li' -siteSubtitle='stali - static linux' -menuTitle='about' diff --git a/sta.li/faq.md b/sta.li/faq.md @@ -1,146 +0,0 @@ -FAQ -=== - -Aren't statically linked executables huge? -------------------------------------------- -It depends. Linking a stripped hello world program with glibc results in 600kb. -Linking it with uclibc in about 7kb. Linking OpenBSD's stripped [ksh](git://github.com/dryfish/openbsd-pdksh.git), which -will be stali's default shell, statically against uclibc results in a 170kb -binary -- linking it dynamically against glibc results in 234kb. -Of course this won't scale with every binary, for example we expect surf -being about 5-6MB in size, but the normal Unix userland will be rather small, -compared to most popular linux distros. - -See also - -* <http://9fans.net/archive/2008/11/142> - -Aren't whole libraries linked into a static executable? -------------------------------------------------------- -No. Good libraries implement each library function in separate object (.o) -files, this enables the linker (ld) to only extract and link those -object files from an archive (.a) that export the symbols that are -actually used by a program. Additionally, link-time optimization and -dead code elimination (available in most modern GNU and LLVM based toolchains) -allows for the extraction of necessary code on a _function-by-function_ basis, -while eliminating _all_ unused library code, resulting in a smaller, faster, -and more secure executables. - -See also - -* <http://9fans.net/archive/2002/02/21> - -What's wrong with glibc? ------------------------- -We think nearly everything is wrong with it. Its enormous complexity, -its lack of good structure and well separated object files -(otherwise linking trivial programs wouldn't result in 600kb overhead) and -even worse than that, its design decision to use dlopen for certain -"separated" library features (NSS, locales, IDN, ...), which makes it nearly -impossible to use glibc for static linking in non-trivial programs. -Unfortunately, for certain tools we will ship glibc for pragmatic reasons. - -Of course [Ulrich Drepper thinks that dynamic linking is -great](http://people.redhat.com/drepper/no_static_linking.html), but clearly -that's because of his lack of experience and his delusions of grandeur. - - -Aren't statically linked executables less secure? ----------------------------------------------- -Several people argue (with implicitly requiring ABI-stability) that dynamically -linked executables benefit from security fixes in libraries they depend on. -While this is true to some extent, statically linked executables aren't -en-masse affected by vulnerabilities in the dynamic libraries installed on your -system in the first place. - -We know that there is some overhead in re-compiling all affected executables if -a dependent library is insecure, but we don't see this as a critical -disadvantage, because we also focus on a small and maintainable userland, where -only one tool for each task exists. - -Another argument often heard is that static functions have predictable -addresses, whereas dynamic linking provides the ability of address -randomization. We have two answers to this. The first is: it is -simple to use position-independent code in static executables and (assuming -a modern kernel that supports address randomization for executables) fully -[position-independent -executables](https://en.wikipedia.org/wiki/Position-independent_code) -are easily created on all modern operating systems. The second is: In reality, -address randomization is predictable and we usually see the same addresses when -a dynamic library is loaded or has been pre-loaded again and again. Thus we -consider this as an issue with low impact and this is not a real focus for us. - -If you are really concerned about the security of statically linked executables, -have a look at what [great ldd exploits](http://www.catonmat.net/blog/ldd-arbitrary-code-execution/) exist. - -Another security issue with dynamic linking is versioning, see [this -excerpt](http://harmful.cat-v.org/software/dynamic-linking/versioned-symbols) -for some insight. - -Also a security issue with dynamically linked libraries are executables with -the suid flag. A user can easily run dynamic library code using LD_PRELOAD in -conjunction with some trivial program like ping. Using a static -executable with the suid flag eliminates this problem completely. - -Apart from that we link against libraries with low footprint (eg uclibc instead -of glibc when possible). This leads to an increased likelihood -of lesser vulnerabilities, simply because lesser code contains fewer bugs from -a statistical point of view. - -See also: -* [On the Effectiveness of Address-Space Randomization](http://benpfaff.org/papers/asrandom.pdf) - -Aren't statically linked executables consuming more memory? --------------------------------------------------------- -We believe that due to the small size of the base system the opposite will be -the case. First of all, the kernel will load each static executable's .rodata, .data, -.text and .comment sections only once for all instances into memory. -Second, because each static binary has only been linked with the object files -necessary, it has already been optimized at linkage time for memory -consumption. When loading it, we don't require the kernel to map all -dependent dynamic libraries into memory from which our binary might only use 5% -of the functions they provide. So, in reality, the memory footprint is becoming -less, and the dead code hold in memory (or paged) reduces overall consumption. -This is also true for programs, like surf, which don't use all webkit/gtk/glib -functions. - -Isn't starting statically linked executables slower? ----------------------------------------------------- -In nearly all cases the answer is "No". In the theoretical case of a huge static -executable, the payload might be loading the executable into memory; but we -focus on small, static executables. In experiments, the execution time of a static -executable was about 4000% faster than its dynamically linked counterpart -when no dependent libraries (except glibc) were pre-loaded, and 100% faster when -the dependent libraries were pre-loaded. We believe the overhead for looking up -all needed symbols in the dynamically loaded libraries seems to be very -expensive. On modern hardware this is only noticeable with endlessly executing -the static and dynamic executable in a loop for several minutes and counting -the number of executions. - -A general conclusion is, the more dynamic libraries an executable depends on, -the slower it'll start, regardless if the libraries are preloaded or not. -This also means that usually big static executables (which we try to avoid) -easily outperform dynamic executables with lots of dependencies. If a big -static executable is already running, executing another one is nearly -instantaneously, because the payload is already in the memory. In the dynamic -case the startup is not instantaneously because the dynamic linker has to make -sure that there were no updates in the dependencies. - -So all in all dynamic executables are painfully slow, regardless of what -inelegant hacks people came up with in the past. There is zero evidence that -dynamic linking makes executables faster. There is only some evidence that -preloading dynamic libraries vs not preloading dynamic libraries improves the -startup of dynamic executables. But the introduction of preloading comes at a -cost as well, the kernel will have to do much more work when supporting such -contrivances. - -Dynamic linking also greatly increases the complexity of the kernel VM and -makes it much slower. And kludgy solutions to this make things more -complicated and add many more points of total failure. - -See also --------- -* [A Web OS? Are You Dense?](http://web.archive.org/web/20120509105723/http://teddziuba.com/2008/09/a-web-os-are-you-dense.html) -* [Breaking the links: Exploiting the linker](http://www.nth-dimension.org.uk/pub/BTL.pdf) -* [On the Effectiveness of Address-Space Randomization](http://benpfaff.org/papers/asrandom.pdf) - diff --git a/sta.li/filesystem.md b/sta.li/filesystem.md @@ -1,29 +0,0 @@ -Filesystem -========== - -This is a editable proposal for a filesystem layout that -will fit the changed principles of the OS. - - /bin - all executables - /boot - all boot files - /dev - devices - /etc - system configuration - /home - user directories - /root - the root home - /var - spool, run, log, cache - /share - man pages, locales, dependencies - /devel - development environment - /devel/include - /devel/lib - /devel/src - -Based on the Linux assumption: - - /sys - sys files - /proc - proc files - -For old style emulation: - - /emul - chroot for packages that are too infected - - diff --git a/sta.li/index.md b/sta.li/index.md @@ -1,36 +0,0 @@ -![stali](/stali.png) - -static linux is based on a hand selected collection of the best tools for each -task and each tool being statically linked (including some X clients such as -st, surf, dwm, dmenu), - -It also targets binary size reduction through the avoidance of glibc and other -bloated GNU libraries where possible (early experiments show that statically -linked binaries are usually smaller than their dynamically linked glibc -counterparts!!!). Note, this is pretty much contrary to what Ulrich Drepper -reckons about static linking. - -Due to the side-benefit that statically linked binaries start faster, the -distribution also targets performance gains. - -Contributing ------------- - -Sta.li is still in a design phase. You can contribute by adding ideas -to the [sandbox](http://sta.li/sandbox) or by working on -[the masterplan](http://sta.li/masterplan). - -Join the [suckless community](http://suckless.org/community) to -discuss further development of sta.li. - -Some related links ------------------- -* [morpheus](http://morpheus.2f30.org/) - a statically linked musl based distro -* [starch linux](http://starchlinux.org/) - a statically linked archlinux variant -* [Bifrost/Linux](http://bifrost.slu.se/) - a minimalist Linux distro for USB media -* [$6M libc](http://codingrelic.geekhold.com/2008/11/six-million-dollar-libc.html) - Bionic is a nice library, though only usable for sane stuff -* [ldd arbitrary code execution](http://www.catonmat.net/blog/ldd-arbitrary-code-execution/) - Nice exploit -* [static linking](http://wayback.archive.org/web/20090525150626/http://blog.garbe.us/2008/02/08/01_Static_linking/) - My old blog entry -* [blog post about stali](http://wayback.archive.org/web/20110727064007/http://elevenislouder.blogspot.com/2010/02/stali.html) -* [On the Effectiveness of Address-Space Randomization](http://benpfaff.org/papers/asrandom.pdf) -* [musl libc](http://www.musl-libc.org/) diff --git a/sta.li/masterplan.md b/sta.li/masterplan.md @@ -1,58 +0,0 @@ -04.04.2012 - -The Masterplan -============== - -Building a different OS with a complete different mindset from -what is mainly used is difficult and time-consuming. To keep -the ideals of suckless in its design and principles there needs -to be a certain guideline how to accomplish sta.li. - -Steps ------ - -* Get a static base environment working -* Allow the emulation of the old dynamically-linked environment -* Make the installation user-friendly -* Maintain the community - -1.) Get a static base environment working ------------------------------------------ - -Steps in this direction have been done in the -[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. - -2.) Allow the emulation of the old behaviour --------------------------------------------- - -In this step some easy way to emulate the old dynamic linking, -which will allow to use pre-existing packages for other -distributions, is needed to be implemented. - -A proposal for the emulation directory is '/emul'. All applications -running below this directory will be run in a chroot under this -path. - -Linux is still struggling with Windows compatibility, which brought -really obscure design decisions to the Open Source environment. It -will take a long time to convert active developers to our principles. - -3.) Make the installation user-friendly ---------------------------------------- - -For this step the Arch Linux way of text installation could be -simply copied. The GUI way of Ubuntu will stop people from -thinking. - -4.) Maintain the community --------------------------- - -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 @@ -1,42 +0,0 @@ -Sandbox -======= - -Ideas that could be worthwhile for the development of sta.li -will be collected here. Just add them using the known ways -of suckless wiki editing. - -Principles ----------- - -* follow the UNIX philosophy -* each executable is statically linked - -Ideas ------ - -* maybe a different format to ELF -* kernel is a monolithic Linux kernel - * still make less used modules loadable (all kind of USB) -* system loader is linux loader -* no initrd -* make the whole system a ramdisk -* a basic initsystem -* updating is rsyncing the build files and rebuilding what is needed -* all applications need dbus to be removed - -Quick Ideas ------------ - -* 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 -* first use X11 for graphics until Wayland is getting sane - * if kernel graphics is getting faster use a framebuffer - -Needed application replacements -------------------------------- - -* new bluetooth stack without dbus -* simple mDNS without dbus diff --git a/sta.li/stali.png b/sta.li/stali.png Binary files differ. diff --git a/sta.li/technologies.md b/sta.li/technologies.md @@ -1,34 +0,0 @@ -Software / Techologies sta.li could use -======================================= - -This list is a proposal of software, which sta.li should include. The rules -are: Be as simple as possible and as useful as possible. - -* base system - * [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/) -* services - * [runit](http://smarden.org/runit/) - * [svc](http://git.r-36.net/svc/) -* logging - * [socklog](http://smarden.org/socklog/) -* documents - * [ted](http://www.nllgg.nl/ted/) -* udev - * [mdev](http://lists.busybox.net/pipermail/busybox/2005-December/017183.html) - * [nldev](http://git.r-36.net/nldev/) - * [smdev](http://git.2f30.org/smdev/) -* wm - * [dwm](http://dwm.suckless.org) - * [nowm](https://github.com/patrickhaller/no-wm) -* dyndns - * [tinydyndns](http://smarden.org/tinydyndns/) -* dhcp - * [sdhcp](http://galos.no-ip.org/sdhcp) -* shell - * [rc](http://plan9.bell-labs.com/sys/doc/rc.html) - * [loksh](https://github.com/dimkr/loksh) - * [mksh](https://www.mirbsd.org/mksh.htm) diff --git a/suckless.org/coding_style.md b/suckless.org/coding_style.md @@ -0,0 +1,161 @@ +Style +===== +Note that the following are guidelines and the most important aspect of style is consistency. Strive to keep your style consistent with the project on which you are working. + +Recommended Reading +------------------- +The following contain good information, some of which is repeated below, some of which is contradicted below. + +* <http://doc.cat-v.org/bell_labs/pikestyle> +* <https://www.kernel.org/doc/Documentation/CodingStyle> +* <http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man9/style.9?query=style&sec=9> + +File Layout +----------- +* Comment with LICENSE and possibly short explanation of file/tool +* Headers +* Macros +* Types +* Function declarations + * Include variable names + * For short files these can be left out + * Group/order in logical manner +* Global variables +* Function definitions in same order as declarations +* `main` + +C Features +---------- +* Use C99 without extensions (ISO/IEC 9899:1999) + * When using gcc compile with -std=c99 -pedantic +* Use POSIX.1-2008 + * When using gcc define `_POSIX_C_SOURCE 200809L` + * Alternatively define `_XOPEN_SOURCE 700` +* Do not mix declarations and code +* Do not use for loop initial declarations +* Use `/* */` for comments, not `//` +* Variadic macros are acceptable, but remember + * `__VA_ARGS__` not a named parameter + * Arg list cannot be empty + +Blocks +------ +* All variable declarations at top of block +* `{` on same line preceded by single space (except functions) +* `}` on own line unless continuing statement (`if else`, `do while`, ...) +* Use block for single statements iff + * Inner statement needs a block + + for (;;) { + if (foo) { + bar; + baz; + } + } + * Another branch of same statement needs a block + + if (foo) { + bar; + } else { + baz; + qux; + } + +Leading Whitespace +------------------ +* Use tabs for indentation +* Use spaces for alignment + * This means no tabs except beginning of line + * Everything will line up independent of tab size + * Use spaces not tabs for multiline macros as the indentation level is 0, where the `#define` began + +Functions +--------- +* Return type and modifiers on own line +* Function name and argument list on next line +* Opening `{` on own line (function definitions are a special case of blocks as they cannot be nested) +* Functions not used outside translation unit should be declared and defined `static` + +Variables +--------- +* Global variables not used outside translation unit should be declared `static` +* In declaration of pointers the `*` is adjacent to variable name, not type + +Keywords +-------- +* Use a space after `if`, `for`, `while`, `switch` (they are not function calls) +* Do not use a space after the opening `(` and before the closing `)` +* Always use `()` with `sizeof` +* Do not use a space with `sizeof()` (it does act like a function call) + +Switch +------ +* Do not indent cases another level +* Comment cases that FALLTHROUGH + +Headers +------- +* Place system/libc headers first in alphabetical order + * If headers must be included in a specific order comment to explain +* Place local headers after an empty line +* When writing and using local headers + * Do not use `#ifndef` guards + * Instead ensure they are included where and when they are needed + * Read <https://talks.golang.org/2012/splash.article#TOC_5.> + * Read <http://plan9.bell-labs.com/sys/doc/comp.html> + +User Defined Types +------------------ +* Do not use `type_t` naming (it is reserved for POSIX and less readable) +* Typedef structs +* Do not typedef builtin types +* Capitalize the type name +* Typedef the type name, if possible without first naming the struct + + typedef struct { + double x, y, z; + } Point; + +Line Length +----------- +* Keep lines to reasonable length (current debate as to reasonable) +* If your lines are too long your code is likely too complex + +Tests and Boolean Values +------------------------ +* Do not test against `NULL` explicitly +* Do not test against `0` explicitly +* Do not use `bool` types (stick to integer types) +* Assign at declaration when possible + + Type *p = malloc(sizeof(*p)); + if (!p) + hcf(); +* Otherwise use compound assignment and tests unless the line grows too long + + if (!(p = malloc(sizeof(*p)))) + hcf(); + +Handling Errors +--------------- +* When functions `return -1` for error test against `0` not `-1` + + if (func() < 0) + hcf(); +* Use `goto` to unwind and cleanup when necessary instead of multiple nested levels +* `return` or `exit` early on failures instead of multiple nested levels +* Unreachable code should have a NOTREACHED comment +* Think long and hard on whether or not you should cleanup on fatal errors + +Enums vs #define +---------------- +* Use enums for values that are grouped semantically and #define otherwise. + + #define MAXSZ 4096 + #define MAGIC1 0xdeadbeef + + enum { + DIRECTION_X, + DIRECTION_Y, + DIRECTION_Z + }; diff --git a/suckless.org/community.md b/suckless.org/community.md @@ -11,9 +11,19 @@ Mailing lists ### Best practice -When beginning a new discussion on the `dev@suckless.org` mailing -list, please mention `dwm` or `dmenu` in the subject *only* if your -email is strictly `dwm` or `dmenu` related. +When beginning a new discussion on the mailinglists, except for the wiki@ +mailinglist, prepend your subject with the project name you are referring to. +This makes it easier for project maintainers to answer your questions. + + +Here is an example: + + Subject: [st] X not working + + +If you are not referring to any project of course use whatever subject you +like. + ### Mailing list commands @@ -37,6 +47,20 @@ following addresses to perform the described action. ### `hackers@suckless.org` +When sending a patch use the following commands: + + cd $project + git send-email --subject-prefix="$(basename $(pwd))][PATCH" \ + --to hackers@suckless.org -1 + +This will send the last commit of the repository to the mailinglist adding a +prefix to the subject which includes the appropriate project name. This allows +easier referencing and filtering of the e-mails for the maintainers subscribed +to hackers@. + +Be sure to have setup your sender address in git and be subscribed to the +mailinglist so you can see eventual comments on your patches. + * `hackers+subscribe@MAILHOST` - subscribe to the mailing list (read/write) * `hackers+subscribe-digest@MAILHOST` - subscribe to the digest version of the mailing list (read/write) * `hackers+subscribe-nomail@MAILHOST` - subscribe without receiving e-mails from the mailing list (write) @@ -110,7 +134,7 @@ Other popular channels: [devarchive]: http://lists.suckless.org/dev/ [dwmarchive]: http://lists.suckless.org/dwm/ [hackersarchive]: http://lists.suckless.org/hackers/ -[newsarchive]: http://lists.suckless.org/hackers/ +[newsarchive]: http://lists.suckless.org/news/ [wikiarchive]: http://lists.suckless.org/wiki/ [wmiiarchive]: http://lists.suckless.org/wmii/ diff --git a/suckless.org/conference/2013.md b/suckless.org/conference/2013.md @@ -1,8 +1,8 @@ suckless conference 2013, Munich ================================ -Saturday 22 June 2013 -===================== +Saturday, 2013-06-22 +==================== LMU MÃœNCHEN (Ludwig-Maximilians-Universität) Theresienstr 39 @@ -15,87 +15,72 @@ Saturday 22 June 2013 Talks ----- -10.00am - 10.40am: *Welcome the future of dwm*, Anselm R Garbe ([slides](/slcon13.pdf)) +(10:00-10:40) *Welcome the future of dwm*, Anselm R Garbe ([slides](/slcon13.pdf)) Anselm presented his plan about the next steps of the dwm development. -<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.suckless.org/slcon/2013/slcon-2013-0-arg-welcome_to_the_future_of_dwm.png"> - <source src="http://dl.suckless.org/slcon/2013/slcon-2013-0-arg-welcome_to_the_future_of_dwm.webm" type="video/webm"> - <a href="http://dl.suckless.org/slcon/2013/slcon-2013-0-arg-welcome_to_the_future_of_dwm.webm">slcon-2013-0-arg-welcome_to_the_future_of_dwm.webm</a> +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2013/slcon-2013-0-arg-welcome_to_the_future_of_dwm.png"> + <source src="http://dl.sta.li/slcon/2013/slcon-2013-0-arg-welcome_to_the_future_of_dwm.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2013/slcon-2013-0-arg-welcome_to_the_future_of_dwm.webm">slcon-2013-0-arg-welcome_to_the_future_of_dwm.webm</a> </video> -10.40am - 11.20am: *st - the past and future*, Christoph Lohmann ([slides](/20h_on_st.pdf)) +(10:40-11:20) *st - the past and future*, Christoph Lohmann ([slides](/20h_on_st.pdf)) Christoph presented his plan about the next steps of st development. -<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.suckless.org/slcon/2013/slcon-2013-1-20h-st-the_past_and_future.png"> - <source src="http://dl.suckless.org/slcon/2013/slcon-2013-1-20h-st-the_past_and_future.webm" type="video/webm"> - <a href="http://dl.suckless.org/slcon/2013/slcon-2013-1-20h-st-the_past_and_future.webm">slcon-2013-1-20h-st-the_past_and_future.webm</a> +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2013/slcon-2013-1-20h-st-the_past_and_future.png"> + <source src="http://dl.sta.li/slcon/2013/slcon-2013-1-20h-st-the_past_and_future.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2013/slcon-2013-1-20h-st-the_past_and_future.webm">slcon-2013-1-20h-st-the_past_and_future.webm</a> </video> -11.45am - 13.00am: *Bugs found by musl*, Szabolcs Nagy ([slides](http://port70.net/~nsz/slcon/bugs_talk.html)) +(11:45-13:00) *Bugs found by musl*, Szabolcs Nagy ([slides](http://port70.net/~nsz/slcon/bugs_talk.html)) Szabolcs picked a few issues found by musl and to show how a new libc can be (and is) beneficial. -Part 1 - -<iframe width="560" height="315" src="http://www.youtube.com/embed/m6V-l-9_39E" frameborder="0" allowfullscreen></iframe> - -Part 2 - -<iframe width="560" height="315" src="http://www.youtube.com/embed/gVdC8ebn5Vw" frameborder="0" allowfullscreen></iframe> - -Part 3 - -<iframe width="560" height="315" src="http://www.youtube.com/embed/sNSQ0hQFSK0" frameborder="0" allowfullscreen></iframe> +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2013/slcon-2013-2-nsz-bugs_found_by_musl.png"> + <source src="http://dl.sta.li/slcon/2013/slcon-2013-2-nsz-bugs_found_by_musl.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2013/slcon-2013-2-nsz-bugs_found_by_musl.webm">slcon-2013-2-nsz-bugs_found_by_musl.webm</a> +</video> -02.40pm - 03.20pm: *runit and ignite*, Christian Neukirchen +(14:40-15:20) *runit and ignite*, Christian Neukirchen Christian presented runit and ignite and discussed if these systems are in line with the suckless philosophy. -Part 1 - -<iframe width="560" height="315" src="http://www.youtube.com/embed/wIziZlFHshE" frameborder="0" allowfullscreen></iframe> - -Part 2 - -<iframe width="560" height="315" src="http://www.youtube.com/embed/u1JXOs4OIak" frameborder="0" allowfullscreen></iframe> +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2013/slcon-2013-3-chneukirchen-runit_and_ignite.png"> + <source src="http://dl.sta.li/slcon/2013/slcon-2013-3-chneukirchen-runit_and_ignite.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2013/slcon-2013-3-chneukirchen-runit_and_ignite.webm">slcon-2013-3-chneukirchen-runit_and_ignite.webm</a> +</video> -03.20pm - 04.20pm: *The costs of abstraction*, Szabolcs Nagy ([slides](http://port70.net/~nsz/slcon/abstraction_talk.html)) +(15:20-16:20) *The costs of abstraction*, Szabolcs Nagy ([slides](http://port70.net/~nsz/slcon/abstraction_talk.html)) Szabolcs discussed why C is still the only serious programming language. -Part 1 - -<iframe width="560" height="315" src="http://www.youtube.com/embed/gWuNmgjRnP0" frameborder="0" allowfullscreen></iframe> - -Part 2 - -<iframe width="560" height="315" src="http://www.youtube.com/embed/b-Ik1oONaqU" frameborder="0" allowfullscreen></iframe> - -Part 3 - -<iframe width="560" height="315" src="http://www.youtube.com/embed/KeQp7CaK1s0" frameborder="0" allowfullscreen></iframe> - -Part 4 - -<iframe width="560" height="315" src="http://www.youtube.com/embed/vEJl_H9gK3k" frameborder="0" allowfullscreen></iframe> +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2013/slcon-2013-4-nsz-the_costs_of_abstraction.png"> + <source src="http://dl.sta.li/slcon/2013/slcon-2013-4-nsz-the_costs_of_abstraction.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2013/slcon-2013-4-nsz-the_costs_of_abstraction.webm">slcon-2013-4-nsz-the_costs_of_abstraction.webm</a> +</video> -04.20pm - 4.50pm: *The suckless web ideas*, Christoph Lohmann ([slides](/20h_on_surf.pdf)) +(16:20-16:50) *The suckless web ideas*, Christoph Lohmann ([slides](/20h_on_surf.pdf)) Christoph discussed suckless web ideas. -<iframe width="560" height="315" src="http://www.youtube.com/embed/Dnr4sXArCwI" frameborder="0" allowfullscreen></iframe> +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2013/slcon-2013-5-20h-the_suckless_web_ideas.png"> + <source src="http://dl.sta.li/slcon/2013/slcon-2013-5-20h-the_suckless_web_ideas.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2013/slcon-2013-5-20h-the_suckless_web_ideas.webm">slcon-2013-5-20h-the_suckless_web_ideas.webm</a> +</video> -4.50pm - 5.15pm: *stali and other stuff*, Anselm R Garbe ([slides](/slcon13.pdf)) +(16:50-17:15) *stali and other stuff*, Anselm R Garbe ([slides](/slcon13.pdf)) -<iframe width="560" height="315" src="http://www.youtube.com/embed/Zu9Qm9bNMUU" frameborder="0" allowfullscreen></iframe> +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2013/slcon-2013-6-arg-stali_and_other_stuff.png"> + <source src="http://dl.sta.li/slcon/2013/slcon-2013-6-arg-stali_and_other_stuff.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2013/slcon-2013-6-arg-stali_and_other_stuff.webm">slcon-2013-6-arg-stali_and_other_stuff.webm</a> +</video> diff --git a/suckless.org/conference/2015.md b/suckless.org/conference/2015.md @@ -0,0 +1,165 @@ +suckless conference 2015, Budapest +================================== + +->[![slcon2015 group photo](slcon2015-s.png)](slcon2015.png)<- + +Friday, 2015-10-30 +================== + +Talks +----- + +(11:00-11:15) *Welcome*, Anselm R Garbe + +> Anselm opened slcon2 and gave an overview on the final conference schedule. + +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2015/slcon-2015-00-arg-welcome.png"> + <source src="http://dl.sta.li/slcon/2015/slcon-2015-00-arg-welcome.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2015/slcon-2015-00-arg-welcome.webm">slcon-2015-00-arg-welcome.webm</a> +</video> + + +(11:15-12:00) *suckless core - A suckless userspace foundation*, Laslo Hunhold + +> This talk focused on recent developments in the suckless core + programs, the design and motivation behind them and which issues had been + faced along the way, including ditching POSIX in some places in favor of + suckless design principles and consistency. + Current issues and future plans were discussed in the last part. + +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2015/slcon-2015-01-frign-suckless_core.png"> + <source src="http://dl.sta.li/slcon/2015/slcon-2015-01-frign-suckless_core.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2015/slcon-2015-01-frign-suckless_core.webm">slcon-2015-01-frign-suckless_core.webm</a> +</video> + + +(12.00-12:45) *stali 2015*, Anselm R Garbe + +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2015/slcon-2015-02-arg-stali_2015.png"> + <source src="http://dl.sta.li/slcon/2015/slcon-2015-02-arg-stali_2015.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2015/slcon-2015-02-arg-stali_2015.webm">slcon-2015-02-arg-stali_2015.webm</a> +</video> + + +(12:45-13:45) Lunch + +(13:45-14:30) *new suckless tools*, Anselm R Garbe + +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2015/slcon-2015-03-arg-new_suckless_tools.png"> + <source src="http://dl.sta.li/slcon/2015/slcon-2015-03-arg-new_suckless_tools.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2015/slcon-2015-03-arg-new_suckless_tools.webm">slcon-2015-03-arg-new_suckless_tools.webm</a> +</video> + + +(14:30-15:30) *Farbfeld - Rethinking image-formats*, Laslo Hunhold + +> This talk discussed the deficiencies of the RGBA color space and + presented the Farbfeld format to store images in a device independent + way using the Lab color space. + Additionally, an alternative to incorporated, namely imposed, image + compression was discussed, evaluating the advantages over other image + formats using different kinds of images. + +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2015/slcon-2015-04-frign-farbfeld.png"> + <source src="http://dl.sta.li/slcon/2015/slcon-2015-04-frign-farbfeld.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2015/slcon-2015-04-frign-farbfeld.webm">slcon-2015-04-frign-farbfeld.webm</a> +</video> + + +(15:30-16:00) Coffee/Tea break + +(16:00-16:30) *suckless.org e.V.*, Anselm R Garbe + +> Anselm presented the idea of suckless.org e.V.[<sup>1</sup>][1] and asked + attendees to join. + +(16:30-17:30) *suckless.org foundation*, All + +(17:30-19:00) Refresh break / check your rooms + +(19:00-) Late night social event in Budapest + + +Saturday, 2015-10-31 +==================== + +Talks +----- + +(10:30-10:45) *Opening of day 2*, Anselm R Garbe + +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2015/slcon-2015-06-arg-opening_of_day_2.png"> + <source src="http://dl.sta.li/slcon/2015/slcon-2015-06-arg-opening_of_day_2.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2015/slcon-2015-06-arg-opening_of_day_2.webm">slcon-2015-06-arg-opening_of_day_2.webm</a> +</video> + + +(10:45-11:30) *Simple Jabber - Divide And Conquer XMPP*, Jan Klemkow ([paper](/jan_on_sj.pdf)) + +> The Extensible Messaging and Presence Protocol ([XMPP][2]) is like the web. It is + far too complex to be implemented in one program with the Unix philosophy in mind. + But like the web, you have to deal with it. It is the only open + and widely used instant messaging protocol on the internet. + Its extensibility is the main reason that an implementation in a single + program is nearly impossible. This talk described an approach to master this problem. + +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2015/slcon-2015-07-klenkow-simple_jabber.png"> + <source src="http://dl.sta.li/slcon/2015/slcon-2015-07-klenkow-simple_jabber.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2015/slcon-2015-07-klenkow-simple_jabber.webm">slcon-2015-07-klenkow-simple_jabber.webm</a> +</video> + + +(11:30-12:00) *Finite state document processing*, Manu Raster + +> Mainstream XML processing techniques wastefully consume time + and memory for example in file format conversions popularly + known as 'save as...'. This talk presented a less + wasteful method based on finite-state transducers. + +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2015/slcon-2015-08-raster-finite_state_document_processing.png"> + <source src="http://dl.sta.li/slcon/2015/slcon-2015-08-raster-finite_state_document_processing.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2015/slcon-2015-08-raster-finite_state_document_processing.webm">slcon-2015-08-raster-finite_state_document_processing.webm</a> +</video> + +(12:00-13:00) Lunch + +(13:00-13:15) Conference fee collection + +(13:15-14:15) *UTF-8 everywhere? Writing Unicode compliant software that sucks less*, Laslo Hunhold + +> This talk discussed UTF-8 and its history, how and when you have to + deal with it and which challenges had been faced along the way, evaluating + its advantages over other character encodings. + Besides more trivial problems like decoding and encoding, advanced + issues like string comparison, case conversion and normalization were + discussed, leading to the conclusion that the POSIX wchar-interfaces + are broken by design. + Using suckless principles, problems with the ICU libraries were discussed + and a midway drawn between total localization and minimalism, + presenting possible solutions. + +<video width="600" height="338" controls="" style="display:block;margin:0 auto" poster="http://dl.sta.li/slcon/2015/slcon-2015-09-frign-utf-8_everywhere.png"> + <source src="http://dl.sta.li/slcon/2015/slcon-2015-09-frign-utf-8_everywhere.webm" type="video/webm"> + <a href="http://dl.sta.li/slcon/2015/slcon-2015-09-frign-utf-8_everywhere.webm">slcon-2015-09-frign-utf-8_everywhere.webm</a> +</video> + + +(14:15-14:45) Coffee/Tea break + +(14:45-15:00) *Formal conference talk closing*, Anselm R Garbe + +(15:00-17:00) Hacking + +(17:00-) Social event in Budapest + +Acknowledgment +-------------- +We kindly thank [![genua GmbH](genua.png)](http://www.genua.eu) for +borrowing us the equipment to record the slcon2 conference videos. + +Previous conferences +-------------------- +* [slcon 2013](http://suckless.org/conference/2013) + +[1]: https://en.wikipedia.org/wiki/Eingetragener_Verein +[2]: http://xmpp.org/ diff --git a/suckless.org/conference/genua.png b/suckless.org/conference/genua.png Binary files differ. diff --git a/suckless.org/conference/index.md b/suckless.org/conference/index.md @@ -1,28 +1,13 @@ -suckless conference 2015, Budapest -================================== +suckless conference 2016, Frankfurt/Main, Taunus, Germany +========================================================= -slcon2 will be held in Budapest on Oct 30-31 2015. - -This time it'll be a conference for invited participants *only*. - -Call for Papers ---------------- - -Among suckless.org fellows and contributors who will receive an official -invitation until end of Feb 2015, there are *limited* places left for -interested participants. - -However to be accepted to attend, interested participants must submit their -paper proposal for talks between 20 and 60 minutes until the CfP deadline - -*30. April 2015* - -Please submit your proposed paper to [con@suckless.org](mailto:con@suckless.org). - -Good luck and looking forward! +slcon3 will be held near Frankfurt/Main on 2016-09-(23-25). +At the same occasion the Mitgliederversammlung (annual member meeting) of suckless.org e.V. will be held. +The CfP will start soon. Previous conferences -------------------- +* [slcon 2015](http://suckless.org/conference/2015) * [slcon 2013](http://suckless.org/conference/2013) diff --git a/suckless.org/conference/slcon2015-s.png b/suckless.org/conference/slcon2015-s.png Binary files differ. diff --git a/suckless.org/conference/slcon2015.png b/suckless.org/conference/slcon2015.png Binary files differ. diff --git a/suckless.org/donations.md b/suckless.org/donations.md @@ -24,7 +24,7 @@ Following people have donated to the suckless.org project certain amounts of money, which have been used for the dedicated server rent in the past: -* Jakub Jirutka donated <b>10 USD</b> +* Jakub Jirutka donated <b>20 USD</b> * Surin Anton donated <b>20 USD</b> * Eero Molkoselkä donated <b>10 EUR</b> * Dimitrios Papastamos donated <b>30 GBP</b> diff --git a/suckless.org/index.md b/suckless.org/index.md @@ -5,15 +5,56 @@ Read more about our [philosophy](/philosophy) and join us on the [mailing list]( News ==== +2016-02-29 +---------- +Final suckless.org server renewal will happen this week: + +Heads up for the developers: + + Old fingerprint: a7:35:1c:f2:8e:69:08:85:80:2c:9a:d2:81:a1:23:cb. + New fingerprint: 80:bc:bb:29:a5:21:b7:12:ed:50:40:58:cf:71:54:7c + +The switch itself should be smooth to everyone else. + +2016-02-12 +---------- +[slock 1.3](http://tools.suckless.org/slock) released: [download](http://dl.suckless.org/tools/slock-1.3.tar.gz) + +2016-01-06 +---------- +[farbfeld 1](http://git.suckless.org/farbfeld) released: [download](http://dl.suckless.org/farbfeld/farbfeld-1.tar.gz) + +2015-12-19 +---------- +[surf 0.7](http://surf.suckless.org) released: [download](http://dl.suckless.org/surf/surf-0.7.tar.gz) + +2015-11-25 +---------- +[sent 0.2](http://tools.suckless.org/sent) released: [download](http://dl.suckless.org/tools/sent-0.2.tar.gz) + +2015-11-13 +---------- +Videos of the [slcon2 talks](http://suckless.org/conference/) are now available. + +2015-11-09 +---------- +[dwm 6.1](http://dwm.suckless.org) released: [download](http://dl.suckless.org/dwm/dwm-6.1.tar.gz) + +[dmenu 4.6](http://tools.suckless.org/dmenu) released: [download](http://dl.suckless.org/tools/dmenu-4.6.tar.gz) + +2015-09-23 +---------- +Kai and Anselm gave an interview about suckless.org on Randal Schwartz' [FLOSS Weekly show](https://twit.tv/shows/floss-weekly/episodes/355?autostart=false) + 2015-07-07 ---------- [st 0.6](http://st.suckless.org) released: [download](http://dl.suckless.org/st/st-0.6.tar.gz) 2015-02-14 ---------- -There will be [slcon2](http://suckless.org/conference/) held in Budpast end of Oct 2015. +[slcon2](http://suckless.org/conference/) will be held in Budapest on 2015-10-(30-31). -The CfP for interested participants is now open and will end *30 April 2015*. +The CfP for interested participants is now open and will end on 2015-04-30. 2014-12-22 ---------- @@ -38,10 +79,6 @@ community is invited to come, meet and hack! ---------- [ubase 0.1](http://tools.suckless.org/ubase) released: [download](http://dl.suckless.org/ubase/ubase-0.1.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) @@ -62,10 +99,6 @@ community is invited to come, meet and hack! ---------- We are glad to announce the [slcon 2013](/conference) programme. -2013-02-10 ----------- -[surf 0.6](http://surf.suckless.org) released: [download](http://dl.suckless.org/surf/surf-0.6.tar.gz) - 2012-11-29 ---------- We are glad to announce the switch to git from mercurial in all of our @@ -85,14 +118,6 @@ We will miss him a lot. RIP -2012-01-08 ----------- -[dmenu 4.5](http://tools.suckless.org/dmenu) released: [download](http://dl.suckless.org/tools/dmenu-4.5.tar.gz) - -2011-12-19 ----------- -[dwm 6.0](http://dwm.suckless.org) released: [download](http://dl.suckless.org/dwm/dwm-6.0.tar.gz) - 2011-05-14 ---------- Anselm gave a talk about **The 'suckless.org' universe** at the [LinuxTag 2011](http://www.linuxtag.org) @@ -109,9 +134,9 @@ conference in Berlin. 2010-03-28 ---------- We learned today that the previous wmii maintainer, who wasn't actively -involved since 2007, Denis Grelich, [died on 12 March -2010](http://www.lmt.uni-saarland.de/de/aktuelles/grelich.html). We offer him our -condolences and thank him for his work. Rest in peace. +involved since 2007, Denis Grelich, +[died on 2010-03-12](https://web.archive.org/web/20140208043925/http://www.lmt.uni-saarland.de/de/aktuelles/grelich.html). +We offer him our condolences and thank him for his work. Rest in peace. 2010-03-07 ---------- @@ -119,11 +144,11 @@ We applied as a mentoring organisation for GSoC 2010. See our [project ideas for 2010-02-13 ---------- -Some of us will visit [CLT2010](http://chemnitzer.linux-tage.de/2010/). Anselm will give a [talk](http://chemnitzer.linux-tage.de/2010/vortraege/detail.html?idx=308) about [stali](http://sta.li) on the second day of CLT2010 at 5pm. +Some of us will visit [CLT2010](http://chemnitzer.linux-tage.de/2010/). Anselm will give a [talk](http://chemnitzer.linux-tage.de/2010/vortraege/detail.html?idx=308) about [stali](http://sta.li) on the second day of CLT2010 at 17:00. 2009-12-28 ---------- -There was a small community meeting in Berlin! Thanks to all attenders. +There was a small community meeting in Berlin! Thanks to all attendees. 2008-08-02 ---------- diff --git a/suckless.org/jan_on_sj.pdf b/suckless.org/jan_on_sj.pdf Binary files differ. diff --git a/suckless.org/other_projects.md b/suckless.org/other_projects.md @@ -4,33 +4,33 @@ There are several other projects which are inspired by the spirit of suckless. * [alt](https://github.com/radare/alt) - abstract language tree * [autonet](https://github.com/mrdomino/autonet) - automatic wifi network chooser for OpenBSD +* [bgs](https://github.com/Gottox/bgs) - background setter * [bug](http://vicerveza.homeunix.net/~viric/soft/bug/) - commandline todo-tracking system +* [cross-chroot](https://github.com/radare/cross-chroot) - cross platform qemu-powered chroot utilities (based on the ideas of the maemo sdk) * [dietline](https://github.com/radare/radare2/blob/master/libr/cons/dietline.c) - minimalist implementation of a readline-like library * [dmc](http://git.suckless.org/dmc/) - dynamic mail client * [dvtm](http://www.brain-dump.org/projects/dvtm/) - screen-like dwm (curses) * [dzen](https://github.com/robm/dzen) - display status/notification/menu windows +* [honden](https://github.com/joodan-van-github/honden) - system built on top of oboeta * [ired](https://github.com/radare/ired) - minimalistic hexadecimal editor inspired in radare * [kelp](http://kelp.sf.net) - source code annotation framework * [micy](https://github.com/radare/toys/tree/master/micy) - minimalistic mouse handler (depends on driver) -* [cross-chroot](https://github.com/radare/cross-chroot) - cross platform qemu-powered chroot utilities (based on the ideas of the maemo sdk) * [oboeta](https://github.com/joodan-van-github/oboeta) - minimalistic plain-text flashcard system -* [honden](https://github.com/joodan-van-github/honden) - system built on top of oboeta -* [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://git.2f30.org/sdhcp) - tiny dhcp client +* [sj](https://github.com/younix/sj) - simple jabber: modular FIFO-based XMPP 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 * [smu](https://github.com/Gottox/smu) - simple markup * [spp](https://github.com/radare/spp) - simple pre processor -* [tiv](https://github.com/radare/tiv) - terminal image viewer +* [spt](https://github.com/pickfire/spt) - simple pomodoro timer * [srw](https://bitbucket.org/emg/srw) - simple read wrapper -* [ssg](http://nibble.develsec.org/projects/ssg.html) - slide generation system with markdown-like syntax +* [ssg](https://github.com/jroimartin/ssg) - 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) +* [sw](https://github.com/jroimartin/sw) - minimalistic web framework +* [swx](http://yeuxdelibad.net/Programmation/swx_en.html) - static site generator (inspired from sw) +* [tiv](https://github.com/radare/tiv) - terminal image viewer +* [xbmouse](https://github.com/vlaadbrain/xbmouse) - simply bind a mouse button to a command * [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/20h.md b/suckless.org/people/20h.md @@ -1,8 +1,22 @@ 20h === -Contributor of patches, projects and IRC lurker. +I am one of the maintainers of st and surf and the maintainer of tabbed. I +develop other suckless projects too, but they are minor. For +personal projects I work on see my [repositories](https://git.r-36.net). + +IRC: +__20h__ + +Website: +[https://www.r-36.net](https://www.r-36.net) + +Gopherhole: +[gopher://gopher.r-36.net](gopher://gopher.r-36.net) + +E-Mail: +20h AT R-36 D0T NET + +[Click for further details.](https://r-36.net/about/) -See the suckless mailnglist and my [repositories](http://git.r-36.net/) -for further details. diff --git a/suckless.org/people/hiltjo.md b/suckless.org/people/hiltjo.md @@ -0,0 +1,12 @@ +hiltjo +====== + +Greetings traveler, + +I'm the current developer and maintainer of [dmenu](http://tools.suckless.org/dmenu). + +I have contributed some patches to various suckless projects. + +Some of my other projects are hosted at [2f30](http://git.2f30.org). + +My (personal) projects are available at [codemadness](http://git.codemadness.org). diff --git a/suckless.org/people/k0ga.md b/suckless.org/people/k0ga.md @@ -4,3 +4,4 @@ k0ga I am one of the maintainers of [st](http://st.suckless.org/), author and maintainer of [utmp](http://git.suckless.org/utmp/) and author and maintainer of [scc](http://git.suckless.org/scc/). + diff --git a/suckless.org/people/maandree.md b/suckless.org/people/maandree.md @@ -0,0 +1,9 @@ +Mattias Andrée (maandree) +========================= + +I'm the maintainer of [libzahl](http://git.suckless.org/libzahl/) and +and contibutor to [sbase](http://tools.suckless.org/sbase). + +You can find my PGP key on +[MIT's keyserver](http://pgp.mit.edu:11371/pks/lookup?op=get&search=0xCE306090E98B08C7) and on +[GnuPG's keyserver](http://keys.gnupg.net/pks/lookup?op=get&fingerprint=on&search=0xCE306090E98B08C7). diff --git a/suckless.org/philosophy.md b/suckless.org/philosophy.md @@ -60,3 +60,7 @@ Related links ------------- * [The Duct Tape Programmer](http://www.joelonsoftware.com/items/2009/09/23.html) * [Why should I have written ZeroMQ in C, not C++](http://www.250bpm.com/blog:4) +* [Best practices in application architecture: Use layers to decouple](http://geekandpoke.typepad.com/.a/6a00d8341d3df553ef014e5f920093970c-pi) +* [Facebook's code quality problem](http://www.darkcoding.net/software/facebooks-code-quality-problem/) +* [Minimal Viable Programs](http://joearms.github.io/2014/06/25/minimal-viable-program.html) +* [Why I Write Games in C](http://jonathanwhiting.com/writing/blog/games_in_c/) diff --git a/suckless.org/project_ideas.md b/suckless.org/project_ideas.md @@ -15,7 +15,7 @@ student's progress, as well as of the mentor's. General ideas ------------- Our project ideas in general intend to focus on our innovative development -environment, including graphical user interfaces and development tools. +environment from bare hardware to the graphical interface. * Graphical user interfaces for developers (such as more advanced concepts for mail clients, messaging clients, music players, text editors) @@ -24,9 +24,10 @@ environment, including graphical user interfaces and development tools. * Mobile applications for developers that integrate well into our general development environment * General userland enhancements to Unix-like operating systems, in particular - GNU/Linux + Linux * Foundations of a new windowing system for Unix-like operating systems * Improvements to our existing software projects +* Replacements of bloated existing software in a suckless way. Concrete ideas -------------- @@ -34,6 +35,19 @@ 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. +### Suckless font rendering library + +There is libdrw in suckless now, which still uses xft and fontconfig. +Fontconfig and xft are ugly and require too much internal knowledge to be +useful. The next logical layer in Linux evolved as pango and cairo. Both of +course added HTML formatting and vector drawing. This is not needed to simply +draw some text somewhere. And this is what a suckless font rendering library +should do: Give it a font string and render at some position the given font +without having to care about font specifics. + +***Requirements:*** C knowledge, some X11 knowledge and of course knowledge +about the font formats and how to handle them. + ### Write ld wrapper or replacement for static linking The GNU autotools such as automake and autoconf are completely unusable in @@ -55,20 +69,6 @@ general case. ***Requirements:*** Good C/Unix knowledge is essential, knowledge about linking/linker internals are desirable.. -### goblin - -Write the most useful unix userland commands in the new [Go -language](http://golang.org) created by Google to form a robust base for future -Unix-like userlands that do not suffer from the vulnerabilities that are common -in C or C++ code. The minimum of commands that need to be implemented in Go are -those found in [9base](http://tools.suckless.org/9base), with the exception of -rc and awk which could be separated into a second project for another student. - -Having goblin would allow to migrate decent web frameworks like -[werc](http://werc.cat-v.org) on a proper foundation. - -***Requirements:*** Good C/Unix and Go knowledge is essential. - ### Write a decent bug and issue tracking system We a need a decent ticket management system, as this is a common task in @@ -78,7 +78,8 @@ problems of TTS (Trouble Ticket System), ARS (Action Request System) and IRS (Incident Response System) all together. It also must be usable as a bug tracking system. -* <https://github.com/blog/411-github-issue-tracker> +For now suckless is using a mailinglist which fits all needs. Beware when you +find the new and innovative way to report bugs that this is reality. ***Requirements:*** Good C/Shell/web technology/HTML knowledge would be desirable, knowledge of bug tracking and issue tracking in practice is essential. @@ -123,3 +124,46 @@ This task requires writing a new cookie handler in surf which: ***Requirements:*** Good knowledge of C and POSIX file locking. Basic knowledge of GTK and its other evil friends. + +### Gopher services + +Gopher is a sane protocol which has hierarchy in its design. It allows the +abstraction of a mass of information in a filesystem. The goal of this meta +project is to find ideas how to implement gopher services to easily access the +web and new information. + +See the [protocol](https://en.wikipedia.org/wiki/Gopher_%28protocol%29#Protocol) +for how easy it is to write a `menu`, which can be seen as a directory. + +* [gopherproject.org](http://www.gopherproject.org) +* [gopher proxy](http://gopher.floodgap.com/gopher/) +* [Gopher wikipedia article](https://en.wikipedia.org/wiki/Gopher_%28protocol%29) + +Anyone creating a gopher interface to suckless.org will get a bonus. + +***Requirements:*** Just some shell scripting and a way to setup a gopher +daemon is required. Everyone can do this. + +### A sane backend for surf + +There is dillo, netsurf and abaco which implement HTML. The problem is +Javascript and extension to replace webkit as the big dependency hell for web +rendering in surf. + +If you prepare to work on this project, plan ahead in recruting more +developers. You will need them. + +***Requirements:*** Very good C knowledge, a very good knowledge in web +standards and how to strip them down to the suckless level. + +### A VGA/DVI/Displayport-to-TTY cable + +The emerging graphical revolution has removed the smallest denominator which +combines efficiency in byte transfer and possibilities: vt100. + +The goal of this project is to have some combination of hardware and software +which allows old vt100/etc. devices to use modern display ports. + +***Requirements:*** Hardware, software and converter knowledge. This will +require much hardware work. + diff --git a/suckless.org/rocks.md b/suckless.org/rocks.md @@ -7,7 +7,7 @@ This section is for small, usable development libraries, which can be used for writing software that sucks less. These should preferrably be under the MIT/X consortium or BSD licenses, WTFPL, or public domain, or alternatively LGPL, because it makes them legally -compatible with other suckless projects. +compatible with other suckless projects. libc implementations -------------------- @@ -32,8 +32,10 @@ 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) * [mdocml](http://mdocml.bsd.lv/) - The mandoc UNIX manpage compiler toolset * [morpheus](http://morpheus.2f30.org) - a statically linked musl based Linux distro +* [bare](http://git.uggedal.com/bare/) - simple distro using suckless software * [pjsip](http://www.pjsip.org/) - open source SIP stack (GPL) * [sdhcp](http://git.2f30.org/sdhcp/) - IPV4 DHCP client +* [snore](https://github.com/clamiax/snore) - Sleep with feedback * [termbox](https://github.com/nsf/termbox) - simple ncurses-like library for creating TUIs Programs @@ -46,10 +48,6 @@ for judging a programs as usable are: This covers most console-based programs and programs from [plan9port][]. -Accounting ----------- -* [Ledger](http://ledger-cli.org/) - Audio Players ------------- * [C* Music Player](http://cmus.sourceforge.net/) @@ -60,6 +58,7 @@ Audio Players * [mpg123](http://www.mpg123.de/) - A console mpg player which doesn't use auto*hell, or extra libraries. * [mpg321](http://mpg321.sourceforge.net) * [vorbis-tools](http://www.xiph.org/) (Ogg/FLAC) - Command-line tools to play Ogg and FLAC files. +* [RSound](https://github.com/Themaister/RSound/) - Simple PCM audio server and client BitTorrent Clients ------------------ @@ -72,7 +71,7 @@ Feed aggregators File browsers ------------- * [noice](http://git.2f30.org/noice/) - Small and portable file browser -* [rover](https://github.com/lecram/rover) - Simple file browser for the terminal +* [rover](https://github.com/lecram/rover) - Simple file browser for the terminal File managers ------------- @@ -100,6 +99,7 @@ Image Viewers * [xli](http://web.aanet.com.au/gwg/xli.html) * [xzgv](http://sourceforge.net/projects/xzgv/) * [lel](http://git.2f30.org/lel/) - Suckless imagefile viewer (WIP) +* [imv](https://github.com/exec64/imv) - Simple X11/Wayland Image Viewer. Depends on SDL2 and FreeImage. Instant Messaging Clients ------------------------- @@ -116,9 +116,12 @@ Mail Clients * [Mail][plan9port] - A mail client for [acme][acme]. Included with plan9port. * [dmc](http://git.suckless.org/dmc/) - A minimalistic approach to a commandline mail client (WIP) * [fdm](http://fdm.sourceforge.net/) - MDA +* [isync](http://isync.sourceforge.net/) - MDA that can work better for IMAP * [heirloom-mailx](http://heirloom.sourceforge.net/mailx.html) - A mail client based on the original Berkeley Mail 8.1 with many new features. +* [s-nail](http://sourceforge.net/projects/s-nail/) - An improved heirloom-mailx. * [mutt](http://www.mutt.org/) * [nmh](http://www.nongnu.org/nmh/) +* [mmh](http://marmaro.de/prog/mmh/) * [Prayer](http://www-uxsup.csx.cam.ac.uk/~dpc22/prayer/) - Webmail interface for IMAP servers. Doesn't use javascript or frames and doesn't need cookies. 100% C code. Media Players @@ -159,6 +162,8 @@ Utilities * [slmenu](https://bitbucket.org/rafaelgg/slmenu) - Dmenu spinoff for the console * [dvtm](http://www.brain-dump.org/projects/dvtm/) - dynamic virtual terminal manager * [abduco](http://www.brain-dump.org/projects/abduco/) - session {at,de}tach support +* [nq](https://github.com/chneukirchen/nq) - unix command line queue utility +* [entr](http://entrproject.org/) - Run arbitrary commands when files change Web Browsers ------------ @@ -193,6 +198,8 @@ X11 * [ffcast](https://github.com/lolilolicon/FFcast2) – Simple screencasting. * [swm](https://github.com/dcat/swm) - A simple window manager called Simple Window Manager. Floating but keyboard-accessible. * [wmutils](https://github.com/wmutils/core) - A set of utilities for managing windows. Can be used on their own or to augment a WM itself. Support for tiling present. +* [grabc](http://www.muquit.com/muquit/software/grabc/grabc.html) - Grab the + color of some pixel in X11. [plan9port]: http://swtch.com/plan9port/ [acme]: http://acme.cat-v.org diff --git a/suckless.org/style.md b/suckless.org/style.md @@ -1,161 +0,0 @@ -Style -===== -Note that the following are guidelines and the most important aspect of style is consistency. Strive to keep your style consistent with the project on which you are working. - -Recommended Reading -------------------- -The following contain good information, some of which is repeated below, some of which is contradicted below. - -* <http://doc.cat-v.org/bell_labs/pikestyle> -* <https://www.kernel.org/doc/Documentation/CodingStyle> -* <http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man9/style.9?query=style&sec=9> - -File Layout ------------ -* Comment with LICENSE and possibly short explanation of file/tool -* Headers -* Macros -* Types -* Function declarations - * Include variable names - * For short files these can be left out - * Group/order in logical manner -* Global variables -* Function definitions in same order as declarations -* `main` - -C Features ----------- -* Use C99 without extensions (ISO/IEC 9899:1999) - * When using gcc compile with -std=c99 -pedantic -* Use POSIX.1-2008 - * When using gcc define `_POSIX_C_SOURCE 200809L` - * Alternatively define `_XOPEN_SOURCE 700` -* Do not mix declarations and code -* Do not use for loop initial declarations -* Use `/* */` for comments, not `//` -* Variadic macros are acceptable, but remember - * __VA_ARGS__ not a named parameter - * Arg list cannot be empty - -Blocks ------- -* All variable declarations at top of block -* `{` on same line preceded by single space (except functions) -* `}` on own line unless continuing statement (`if else`, `do while`, ...) -* Use block for single statements iff - * Inner statement needs a block - - for (;;) { - if (foo) { - bar; - baz; - } - } - * Another branch of same statement needs a block - - if (foo) { - bar; - } else { - baz; - qux; - } - -Leading Whitespace ------------------- -* Use tabs for indentation -* Use spaces for alignment - * This means no tabs except beginning of line - * Everything will line up independent of tab size - * Use spaces not tabs for multiline macros as the indentation level is 0, where the `#define` began - -Functions ---------- -* Return type and modifiers on own line -* Function name and argument list on next line -* Opening `{` on own line (function definitions are a special case of blocks as they cannot be nested) -* Functions not used outside translation unit should be declared and defined `static` - -Variables ---------- -* Global variables not used outside translation unit should be declared `static` -* In declaration of pointers the `*` is adjacent to variable name, not type - -Keywords --------- -* Use a space after `if`, `for`, `while`, `switch` (they are not function calls) -* Do not use a space after the opening `(` and before the closing `)` -* Always use `()` with `sizeof` -* Do not use a space with `sizeof()` (it does act like a function call) - -Switch ------- -* Do not indent cases another level -* Comment cases that FALLTHROUGH - -Headers -------- -* Place system/libc headers first in alphabetical order - * If headers must be included in a specific order comment to explain -* Place local headers after an empty line -* When writing and using local headers - * Do not use `#ifndef` guards - * Instead ensure they are included where and when they are needed - * Read <https://talks.golang.org/2012/splash.article#TOC_5.> - * Read <http://plan9.bell-labs.com/sys/doc/comp.html> - -User Defined Types ------------------- -* Do not use `type_t` naming (it is reserved for POSIX and less readable) -* Typedef structs -* Do not typedef builtin types -* Capitalize the type name -* Typedef the type name, if possible without first naming the struct - - typedef struct { - double x, y, z; - } Point; - -Line Length ------------ -* Keep lines to reasonable length (current debate as to reasonable) -* If your lines are too long your code is likely too complex - -Tests and Boolean Values ------------------------- -* Do not test against `NULL` explicitly -* Do not test against `0` explicitly -* Do not use `bool` types (stick to integer types) -* Assign at declaration when possible - - Type *p = malloc(sizeof(*p)); - if (!p) - hcf(); -* Otherwise use compound assignment and tests unless the line grows too long - - if (!(p = malloc(sizeof(*p)))) - hcf(); - -Handling Errors ---------------- -* When functions `return -1` for error test against `0` not `-1` - - if (func() < 0) - hcf(); -* Use `goto` to unwind and cleanup when necessary instead of multiple nested levels -* `return` or `exit` early on failures instead of multiple nested levels -* Unreachable code should have a NOTREACHED comment -* Think long and hard on whether or not you should cleanup on fatal errors - -Enums vs #define ----------------- -* Use enums for values that are grouped semantically and #define otherwise. - - #define MAXSZ 4096 - #define MAGIC1 0xdeadbeef - - enum { - DIRECTION_X, - DIRECTION_Y, - DIRECTION_Z - }; diff --git a/suckless.org/sucks/index.md b/suckless.org/sucks/index.md @@ -3,6 +3,10 @@ Stuff that sucks See the [philosophy](http://suckless.org/philosophy) page about what applies to this page. +Bigger topics that suck: +[systemd](http://suckless.org/sucks/systemd), [the +web](http://suckless.org/sucks/web) + Libraries --------- These libraries are broken/considered harmful and should not be used if it's @@ -92,6 +96,34 @@ The following programs are broken (see [rocking stuff](/rocks) for saner alterna If you still need some program which expects a floating WM, use it in floating mode. +Documentation +------------- +Somewhen GNU tried to make the world a bit more miserable by inventing +[texinfo][texinfo]. The result is that in 2015 man pages are still used and +the documentation of GNU tools requires you to run `info $application`. The +info browser is awkward and unintuitive and the reason why noone gets further +than finding 'q' to quit it. + +Look at GNU tools how to not handle documentation. + +Talking about the suck in enforced HTML documentation, which forces you to open +up a 1 Gb of RAM wasting web browser, just to see some eye-candy, which could +have been described in the source with some easy way to jump to that line in +the source code, is not worth the time. + +The suckless way is to have a short usage and a descriptive manpage. The +complete details are in the source. + +C Compilers +--------- +* [GCC][gcc] is the virus which has spread into nearly every Linux + distribution and has added its language extensions to be not easily + replacable. As of 2015 it is now written in C++ and so complete suck. Why + can't a compiler just be a simple binary doing its work instead of adding + path dependencies deep into the system? +* [Clang][clang] is written in C++. If you don't believe that it sucks, try to + build clang by hand. + See also -------- @@ -101,3 +133,7 @@ The [list of harmful software](http://harmful.cat-v.org/software/) at [cat-v.org [st]: http://st.suckless.org/ [uuterm]: http://etalabs.net/uuterm.html [icccm]: http://tronche.com/gui/x/icccm/ +[texinfo]: https://www.gnu.org/software/texinfo/ +[gcc]: http://gcc.gnu.org/ +[clang]: http://clang.llvm.org/ + diff --git a/suckless.org/sucks/systemd.md b/suckless.org/sucks/systemd.md @@ -230,3 +230,8 @@ plain file.) ---- Führerbunker, 2015-07-31 +Further Reading +--------------- +* [Without Systemd](http://without-systemd.org/wiki/index.php/Main_Page) +* [Arguments Against Systemd](http://without-systemd.org/wiki/index.php/Arguments_against_systemd) + diff --git a/suckless.org/sucks/web.md b/suckless.org/sucks/web.md @@ -0,0 +1,26 @@ +The Web Sucks +============= +It has enabled the global information exchange, mass surveillance, studies in +social control, allowed revolutions, made a fortune for many billionaires and +in the meanwhile ruined our climate: the web. + +[This is a motherfucking website.](http://motherfuckingwebsite.com/) +[This is a better motherfucking website.](http://bettermotherfuckingwebsite.com/) + +For short: There is an industry which is specialized on extending the resource +usage to display just some characters on your display. Millions of jobs are +based on outputting HTML in an inefficient way. Look at PHP and all the +techniques to extend its "scalability". It is not scalable, it's a +prototyping language. Not to mention all its syntactic irregulatories. +Nowadays classes on classes on classes with getter and setter functions define +buttons which can be stripped down to just a simple character string. The web +is the practical example why corporate software development does not work and +never will. It only ruins our environment, sanity and many brains which could +be used for the better of humanity. + +PHP was used as the primary example for how interpreted languages produce +resource waste. There were optimisations for compiling PHP to C++(!). But this +is just a way to allow the mass of programmer sheep to go on and sleep calm at +night. + + diff --git a/suckless.org/wiki.md b/suckless.org/wiki.md @@ -9,6 +9,20 @@ or git clone http://git.suckless.org/sites +Then edit the wiki as you like. The markdown interpreter that is currently +used on the suckless.org werc instance is +[discount 2.1.3](http://www.pell.portland.or.us/~orc/Code/discount/). + +For adding new files, after you created them, use: + + git add $filename + +When you are finished, commit your changes with: + + git commit -a + +There you enter some meaningful commit message and end the editor. + To push your changes to the queue for the review by the suckless moderators, use: @@ -17,8 +31,8 @@ use: The review of your changes might take one day, due to the different timezones we all live in. -Please make sure to pull for incoming changes before you push your changes, to -minimize problems. +__Please make sure to update for incoming changes using »git pull«, before you +push changes, to minimize merge problems.__ The wiki repository above is world-writable. diff --git a/surf.suckless.org/files/feeds.md b/surf.suckless.org/files/feeds.md @@ -0,0 +1,90 @@ +RSS/Atom feed detection +======================= + +Description +----------- + +This script looks for links to RSS or Atom feeds in the current web page. If it +finds feeds, it places an icon in the corner of the page which toggles showing +a list of the feeds. + +Author +------ + +Charles Lehner <<http://celehner.com>> + +Code +---- + + document.addEventListener('DOMContentLoaded', function fn() { + document.removeEventListener('DOMContentLoaded', fn, true); + + var feeds = [].slice.call(document.querySelectorAll( + "link[href][rel~=alternate][type$=xml]," + + " a[href][rel~=alternate][type$=xml]")) + .map(function (el) { + return { + href: el.href, + title: el.title || document.title, + type: /atom/i.test(el.type) ? 'Atom' : 'RSS' + }; + }); + if (!feeds.length) return; + + var container = document.createElement('div'); + container.style.position = 'fixed'; + container.style.bottom = 0; + container.style.right = 0; + container.style.zIndex = 10000; + document.body.appendChild(container); + + var feedList = document.createElement('div'); + feedList.style.display = 'none'; + feedList.style.backgroundColor = '#ddd'; + feedList.style.border = '1px solid #bbb'; + feedList.style.borderStyle = 'solid solid none'; + feedList.style.padding = '2px 4px'; + container.appendChild(feedList); + + feeds.forEach(function (feed) { + var a = document.createElement('a'); + a.href = feed.href; + a.style.display = 'block'; + a.style.color = 'blue'; + var title = feed.title; + if (title.indexOf(feed.type) == -1) + title += ' (' + feed.type + ')'; + a.appendChild(document.createTextNode(title)); + feedList.appendChild(a); + }); + + var toggleLink = document.createElement('a'); + toggleLink.href = ''; + toggleLink.style.display = 'inline-block'; + toggleLink.style.paddingRight = '3px'; + toggleLink.style.verticalAlign = 'bottom'; + toggleLink.addEventListener("click", toggleFeedList, true); + container.appendChild(toggleLink); + + var img = new Image(); + img.style.padding = '4px'; + img.style.verticalAlign = 'bottom'; + img.src = 'data:image/gif;base64,' + + 'R0lGODlhDAAMAPUzAPJoJvJqKvNtLfNuL/NvMfNwMvNyNPNzNvN0OPN1OfN3O/R4' + + 'PfR5P/R6QPR7QvR+RvR/R/SASfSBS/SDTPWETvWFUPWGUvWJVfWLWfWMWvWNXPaW' + + 'aPaYbPaabfebb/eccfeedPehePemf/ingPiphPiqhviui/ivjfiwjviykPm6nPm+' + + 'ofzh1P3k2f3n3P7u5/7v6P738/749f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + + 'AAAAAAAAAAAAAAAAACH5BAEAADQALAAAAAAMAAwAAAZ6QFqB4YBAJBLKZCEsbCDE' + + 'I2WqQCBms9fqkqRIJg7EZ+WawTxeSAS6AklIMhknwjA6sC/SR/aSKBwSEBcpLzMk' + + 'IjMoBwwTECEoGTAvDi8uBAhKMokmMxwqMwIIFhQsMRoZMyeIFgILFoEMCAcEAgEA' + + 'BDQKRhAOsbICNEEAOw=='; + toggleLink.appendChild(img); + + toggleLink.appendChild(document.createTextNode(feeds.length)); + + function toggleFeedList(e) { + e.preventDefault(); + feedList.style.display = (feedList.style.display == 'none') ? + 'inline-block' : 'none'; + } + }, true); diff --git a/surf.suckless.org/index.md b/surf.suckless.org/index.md @@ -12,6 +12,16 @@ one can point surf to another URI by setting its XProperties. > until I forced myself to use surf for a week. I am now much less distracted > and more focused when browsing the web. dwm + surf <3 +Getting Started +--------------- +Start the browser with + + surf http://your-url + +You can navigate by clicking on links on the displayed page. Hit *Ctrl-g* to enter a new URL. For more commands consult + + man surf + Links ----- * Mailing List: `dev+subscribe@suckless.org` ([Archives](http://lists.suckless.org/dev)) @@ -27,7 +37,6 @@ source code repository or get a copy with the following command: Download -------- * [MIT/X Consortium license](http://git.suckless.org/surf/plain/LICENSE) -* [surf 0.6](http://dl.suckless.org/surf/surf-0.6.tar.gz) (20130210) +* [surf 0.7](http://dl.suckless.org/surf/surf-0.7.tar.gz) (2015-12-19) * See also [dmenu](http://tools.suckless.org/dmenu), [tabbed](http://tools.suckless.org/tabbed) - diff --git a/surf.suckless.org/patches/homepage.md b/surf.suckless.org/patches/homepage.md @@ -17,3 +17,4 @@ Author * Matthew Bauer <[mjbauer95@gmail.com](mailto:mjbauer95@gmail.com)> * Henrique Lengler <[henriqueleng@openmailbox.org](mailto:henriqueleng@openmailbox.org)> +* Ivan Tham <[pickfire@riseup.net](mailto:pickfire@riseup.net)> diff --git a/surf.suckless.org/patches/navigation-history.md b/surf.suckless.org/patches/navigation-history.md @@ -0,0 +1,19 @@ +navigation history +================== + +Description +----------- + +This patch adds the MOD-shift-h keyboard shortcut to open up dmenu with the +recent navigation history of the current surf instance. + +Download +-------- + +* [surf-0.6-navhist.diff](surf-0.6-navhist.diff) (2015-10-18) +* [surf-tip-navhist.diff](surf-tip-navhist.diff) (2015-10-18) + +Author +------ + +* Markus Teich diff --git a/surf.suckless.org/patches/omnibar.md b/surf.suckless.org/patches/omnibar.md @@ -0,0 +1,32 @@ +Omnibar +======= +Run a command each time an URI is loaded. Since the URI may be passed as +argument, this patch along with a proper script allows to manage browsing +history in many convenient ways. + +The omnibar script store all URIs, including ones visited by clicking on links, +and use them to auto-complete when you type on dmenu. The items are sorted by +number of views. + +For [tabbed](http://tools.suckless.org/tabbed/) users, you may also want to add +the following to your tabbed config.h: + + #define GOTO { \ + .v = (char *[]){"/bin/sh", "-c", \ + "~/.surf/omnibar goto $0 $1", winid, "_TABBED_SELECT_TAB", NULL \ + } \ + } + +Now you can use the following key (don't forget to remove the old one): + + { MODKEY, XK_t, spawn, GOTO }, + + +Download +-------- +* [surf-0.7-omnibar.diff](surf-0.7-omnibar.diff) +* [omnibar](https://raw.githubusercontent.com/clamiax/.surf/374e101748093215e8ecbf00a24a764932b60ed7/omnibar) + +Author +------ +* Claudio Alessi <[smoppy@gmail.com](mailto:smoppy@gmail.com)> diff --git a/surf.suckless.org/patches/searchengines.md b/surf.suckless.org/patches/searchengines.md @@ -31,6 +31,9 @@ Download * [surf-0.4-searchengines.diff](surf-0.4-searchengines.diff) (2107) (20091204) * [surf-0.5-searchengines.diff](surf-0.5-searchengines.diff) (1611) (20101028) * [surf-0.6-searchengines.diff](surf-0.6-searchengines.diff) (20130514) +* [surf-0.7-searchengines.diff](surf-0.7-searchengines.diff) (20151219) +* [surf-git-20160127-searchengines.diff](surf-git-20160127-searchengines.diff) +* [surf-0.7-webkit2-searchengines.diff](surf-0.7-webkit2-searchengines.diff) (20160108) Author ------ @@ -38,3 +41,5 @@ Author * Nils Schweinsberg (McManiaC) <[mail@n-sch.de](mailto:mail@n-sch.de)> * Samuel Baldwin (shardz) <[recursive.forest@gmail.com](mailto:recursive.forest@gmail.com)> * Alex Puterbaugh (zombine) <[puterbaugh0@gmail.com](mailto:puterbaugh0@gmail.com)> +* Ivan Tham (pickfire) <[pickfire@riseup.net](mailto:pickfire@riseup.net)> +* Juan Aguilar Santillana (botika) <[aritmeeul@gmail.com](mailto:aritmeeul@gmail.com)> diff --git a/surf.suckless.org/patches/smoothscrolling-via-GTK3.md b/surf.suckless.org/patches/smoothscrolling-via-GTK3.md @@ -9,10 +9,10 @@ Enable smooth scrolling by compiling surf with GTK3 instead of GTK2. Download -------- -* [surf-0.6-smoothscrolling.diff](surf-0.6-smoothscrolling.diff) (9.4K) (20131229) +* [surf-0.6-smoothscrolling.diff](surf-0.6-smoothscrolling.diff) (9.4K) (2013-12-29) +* [surf-0.7-smoothscrolling.diff](surf-0.7-smoothscrolling.diff) (9.5K) (2016-01-19) Author ------ -* Charles Lehner <[http://celehner.com](http://celehner.com)> - +* Charles Lehner <<http://celehner.com>> diff --git a/surf.suckless.org/patches/surf-0.6-dmenu-unicode.diff b/surf.suckless.org/patches/surf-0.6-dmenu-unicode.diff @@ -0,0 +1,26 @@ +diff --git a/config.def.h b/config.def.h +index a221c86..ac35199 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -27,7 +27,7 @@ static Bool hidebackground = FALSE; + #define SETPROP(p, q) { \ + .v = (char *[]){ "/bin/sh", "-c", \ + "prop=\"`xprop -id $2 $0 | cut -d '\"' -f 2 | dmenu`\" &&" \ +- "xprop -id $2 -f $1 8s -set $1 \"$prop\"", \ ++ "xprop -id $2 -f $1 8u -set $1 \"$prop\"", \ + p, q, winid, NULL \ + } \ + } +diff --git a/surf.c b/surf.c +index cebd469..b467bbd 100644 +--- a/surf.c ++++ b/surf.c +@@ -475,7 +475,7 @@ getatom(Client *c, int a) { + unsigned char *p = NULL; + + XGetWindowProperty(dpy, GDK_WINDOW_XID(GTK_WIDGET(c->win)->window), +- atoms[a], 0L, BUFSIZ, False, XA_STRING, ++ atoms[a], 0L, BUFSIZ, False, AnyPropertyType, + &adummy, &idummy, &ldummy, &ldummy, &p); + if(p) + strncpy(buf, (char *)p, LENGTH(buf)-1); diff --git a/surf.suckless.org/patches/surf-0.6-homepage.diff b/surf.suckless.org/patches/surf-0.6-homepage.diff @@ -1,23 +1,26 @@ -diff -u a/config.def.h b/config.def.h ---- a/config.def.h 2014-08-16 02:14:02.536275454 -0300 -+++ b/config.def.h 2014-08-16 02:12:18.784283700 -0300 -@@ -31,6 +31,7 @@ - static Bool hidebackground = FALSE; - static Bool allowgeolocation = TRUE; +diff --git a/config.def.h b/config.def.h +index 93a3d49..41bb067 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -35,6 +35,7 @@ static Bool loadimages = TRUE; + static Bool hidebackground = FALSE; + static Bool allowgeolocation = TRUE; +#define HOMEPAGE "https://www.duckduckgo.com/" #define SETPROP(p, q) { \ .v = (char *[]){ "/bin/sh", "-c", \ - "prop=\"`xprop -id $2 $0 | cut -d '\"' -f 2 | xargs -0 printf %b | dmenu`\" &&" \ -diff -u a/surf.c b/surf.c ---- a/surf.c 2014-08-16 02:14:02.536275454 -0300 -+++ b/surf.c 2014-08-16 02:09:58.216294873 -0300 -@@ -1483,6 +1483,9 @@ + "prop=\"`xprop -id $2 $0 " \ +diff --git a/surf.c b/surf.c +index fdfaab1..7a71bf2 100644 +--- a/surf.c ++++ b/surf.c +@@ -1759,6 +1759,9 @@ main(int argc, char *argv[]) default: usage(); } ARGEND; + #ifdef HOMEPAGE + arg.v = HOMEPAGE; + #endif - if(argc > 0) + if (argc > 0) arg.v = argv[0]; + diff --git a/surf.suckless.org/patches/surf-0.6-navhist.diff b/surf.suckless.org/patches/surf-0.6-navhist.diff @@ -0,0 +1,138 @@ +diff --git a/config.def.h b/config.def.h +index a221c86..9840736 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -32,6 +32,16 @@ static Bool hidebackground = FALSE; + } \ + } + ++#define SELNAV { \ ++ .v = (char *[]){ "/bin/sh", "-c", \ ++ "prop=\"`xprop -id $0 _SURF_HIST" \ ++ " | sed -e 's/^.[^\"]*\"//' -e 's/\"$//' -e 's/\\\\\\n/\\n/g'" \ ++ " | dmenu -i -l 10`\"" \ ++ " && xprop -id $0 -f _SURF_NAV 8s -set _SURF_NAV \"$prop\"", \ ++ winid, NULL \ ++ } \ ++} ++ + /* DOWNLOAD(URI, referer) */ + #define DOWNLOAD(d, r) { \ + .v = (char *[]){ "/bin/sh", "-c", \ +@@ -67,6 +77,7 @@ static Key keys[] = { + + { MODKEY, GDK_l, navigate, { .i = +1 } }, + { MODKEY, GDK_h, navigate, { .i = -1 } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_h, selhist, SELNAV }, + + { MODKEY, GDK_j, scroll_v, { .i = +1 } }, + { MODKEY, GDK_k, scroll_v, { .i = -1 } }, +diff --git a/surf.c b/surf.c +index cebd469..8b6d751 100644 +--- a/surf.c ++++ b/surf.c +@@ -32,7 +32,7 @@ char *argv0; + #define COOKIEJAR_TYPE (cookiejar_get_type ()) + #define COOKIEJAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COOKIEJAR_TYPE, CookieJar)) + +-enum { AtomFind, AtomGo, AtomUri, AtomLast }; ++enum { AtomFind, AtomGo, AtomUri, AtomHist, AtomNav, AtomLast }; + + typedef union Arg Arg; + union Arg { +@@ -137,6 +137,8 @@ static void loadstatuschange(WebKitWebView *view, GParamSpec *pspec, + Client *c); + static void loaduri(Client *c, const Arg *arg); + static void navigate(Client *c, const Arg *arg); ++static void selhist(Client *c, const Arg *arg); ++static void navhist(Client *c, const Arg *arg); + static Client *newclient(void); + static void newwindow(Client *c, const Arg *arg, gboolean noembed); + static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d); +@@ -649,6 +651,59 @@ navigate(Client *c, const Arg *arg) { + webkit_web_view_go_back_or_forward(c->view, steps); + } + ++static void ++selhist(Client *c, const Arg *arg) { ++ WebKitWebBackForwardList *lst; ++ WebKitWebHistoryItem *cur; ++ gint i; ++ gchar *out; ++ gchar *tmp; ++ gchar *line; ++ ++ out = g_strdup(""); ++ ++ if(!(lst = webkit_web_view_get_back_forward_list(c->view))) ++ return; ++ ++ for(i = webkit_web_back_forward_list_get_back_length(lst); i > 0; i--) { ++ if(!(cur = webkit_web_back_forward_list_get_nth_item(lst, -i))) ++ break; ++ line = g_strdup_printf("%d: %s\n", -i, ++ webkit_web_history_item_get_original_uri(cur)); ++ tmp = g_strconcat(out, line, NULL); ++ g_free(out); ++ out = tmp; ++ } ++ ++ if((cur = webkit_web_back_forward_list_get_nth_item(lst, 0))) { ++ line = g_strdup_printf("%d: %s", 0, ++ webkit_web_history_item_get_original_uri(cur)); ++ tmp = g_strconcat(out, line, NULL); ++ g_free(out); ++ out = tmp; ++ } ++ ++ for(i = 1; i <= webkit_web_back_forward_list_get_forward_length(lst); i++) { ++ if(!(cur = webkit_web_back_forward_list_get_nth_item(lst, i))) ++ break; ++ line = g_strdup_printf("\n%d: %s", i, ++ webkit_web_history_item_get_original_uri(cur)); ++ tmp = g_strconcat(out, line, NULL); ++ g_free(out); ++ out = tmp; ++ } ++ ++ setatom(c, AtomHist, out); ++ g_free(out); ++ spawn(c, arg); ++} ++ ++static void ++navhist(Client *c, const Arg *arg) { ++ Arg a = { .i = atoi(arg->v) }; ++ navigate(c, &a); ++} ++ + static Client * + newclient(void) { + Client *c; +@@ -805,6 +860,7 @@ newclient(void) { + + setatom(c, AtomFind, ""); + setatom(c, AtomUri, "about:blank"); ++ setatom(c, AtomHist, ""); + if(hidebackground) + webkit_web_view_set_transparent(c->view, TRUE); + +@@ -923,6 +979,9 @@ processx(GdkXEvent *e, GdkEvent *event, gpointer d) { + arg.v = getatom(c, AtomGo); + loaduri(c, &arg); + return GDK_FILTER_REMOVE; ++ } else if(ev->atom == atoms[AtomNav]) { ++ arg.v = getatom(c, AtomNav); ++ navhist(c, &arg); + } + } + } +@@ -1004,6 +1063,8 @@ setup(void) { + atoms[AtomFind] = XInternAtom(dpy, "_SURF_FIND", False); + atoms[AtomGo] = XInternAtom(dpy, "_SURF_GO", False); + atoms[AtomUri] = XInternAtom(dpy, "_SURF_URI", False); ++ atoms[AtomHist] = XInternAtom(dpy, "_SURF_HIST", False); ++ atoms[AtomNav] = XInternAtom(dpy, "_SURF_NAV", False); + + /* dirs and files */ + cookiefile = buildpath(cookiefile); diff --git a/surf.suckless.org/patches/surf-0.6-searchengines.diff b/surf.suckless.org/patches/surf-0.6-searchengines.diff @@ -1,71 +1,77 @@ diff --git a/config.def.h b/config.def.h -index 8185136..6b5144c 100644 +index 93a3d49..4ac7f15 100644 --- a/config.def.h +++ b/config.def.h -@@ -101,3 +101,10 @@ static Key keys[] = { - { MODKEY|GDK_SHIFT_MASK,GDK_b, togglescrollbars,{ 0 } }, - { MODKEY|GDK_SHIFT_MASK,GDK_g, togglegeolocation, { 0 } }, +@@ -75,6 +75,13 @@ static SiteStyle styles[] = { + { ".*", "default.css" }, }; -+ + ++/* search engines */ +static SearchEngine searchengines[] = { -+ { "g", "http://www.google.de/search?q=%s" }, -+ { "en", "http://dict.cc/?s=%s" }, -+ { "ug", "http://%s.uni-goettingen.de" }, -+ { "dict", "http://www.thefreedictionary.com/%s" }, ++ { "g", "http://www.google.de/search?q=%s" }, ++ { "leo", "http://dict.leo.org/ende?search=%s" }, ++ { "ddg", "https://duckduckgo.com/?q=%s" }, +}; ++ + #define MODKEY GDK_CONTROL_MASK + + /* hotkeys */ diff --git a/surf.c b/surf.c -index da84e1c..7eff5e8 100644 +index fdfaab1..b6ac237 100644 --- a/surf.c +++ b/surf.c -@@ -70,6 +70,11 @@ typedef struct { - +@@ -91,6 +91,12 @@ typedef struct { G_DEFINE_TYPE(CookieJar, cookiejar, SOUP_TYPE_COOKIE_JAR_TEXT) -+typedef struct { -+ char *token; -+ char *uri; + typedef struct { ++ char *token; ++ char *uri; +} SearchEngine; + - static Display *dpy; - static Atom atoms[AtomLast]; - static Client *clients = NULL; -@@ -140,6 +145,7 @@ static void loaduri(Client *c, const Arg *arg); ++ ++typedef struct { + char *regex; + char *style; + regex_t re; +@@ -178,6 +184,7 @@ static void loaduri(Client *c, const Arg *arg); static void navigate(Client *c, const Arg *arg); static Client *newclient(void); static void newwindow(Client *c, const Arg *arg, gboolean noembed); +static gchar *parseuri(const gchar *uri); static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d); - static void populatepopup(WebKitWebView *web, GtkMenu *menu, Client *c); - static void popupactivate(GtkMenuItem *menu, Client *); -@@ -629,8 +635,8 @@ loaduri(Client *c, const Arg *arg) { + static gboolean contextmenu(WebKitWebView *view, GtkWidget *menu, + WebKitHitTestResult *target, gboolean keyboard, +@@ -838,8 +845,7 @@ loaduri(Client *c, const Arg *arg) u = g_strdup_printf("file://%s", rp); free(rp); } else { - u = g_strrstr(uri, "://") ? g_strdup(uri) -- : g_strdup_printf("http://%s", uri); +- : g_strdup_printf("http://%s", uri); + u = parseuri(uri); -+ } - /* prevents endless loop */ -@@ -911,6 +917,20 @@ popupactivate(GtkMenuItem *menu, Client *c) { + setatom(c, AtomUri, uri); +@@ -1172,7 +1178,22 @@ menuactivate(GtkMenuItem *item, Client *c) } } -+gchar * +-void ++static gchar * +parseuri(const gchar *uri) { -+ guint i; ++ guint i; + -+ for (i = 0; i < LENGTH(searchengines); i++) { -+ if (searchengines[i].token == NULL || searchengines[i].uri == NULL || *(uri + strlen(searchengines[i].token)) != ' ') -+ continue; -+ if (g_str_has_prefix(uri, searchengines[i].token)) -+ return g_strdup_printf(searchengines[i].uri, uri + strlen(searchengines[i].token) + 1); -+ } ++ for (i = 0; i < LENGTH(searchengines); i++) { ++ if (searchengines[i].token == NULL || searchengines[i].uri == NULL || \ ++ *(uri + strlen(searchengines[i].token)) != ' ') ++ continue; ++ if (g_str_has_prefix(uri, searchengines[i].token)) ++ return g_strdup_printf(searchengines[i].uri, uri + strlen(searchengines[i].token) + 1); ++ } + -+ return g_strrstr(uri, "://") ? g_strdup(uri) : g_strdup_printf("http://%s", uri); ++ return g_strrstr(uri, "://") ? g_strdup(uri) : g_strdup_printf("http://%s", uri); +} + - static void - pasteuri(GtkClipboard *clipboard, const char *text, gpointer d) { ++static void + pasteuri(GtkClipboard *clipboard, const char *text, gpointer d) + { Arg arg = {.v = text }; diff --git a/surf.suckless.org/patches/surf-0.7-omnibar.diff b/surf.suckless.org/patches/surf-0.7-omnibar.diff @@ -0,0 +1,59 @@ +diff --git a/config.def.h b/config.def.h +index 93a3d49..05d81de 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -65,6 +65,18 @@ static Bool allowgeolocation = TRUE; + } \ + } + ++#define ONLOAD(u) { \ ++ .v = (char *[]){"/bin/sh", "-c", \ ++ "~/.surf/omnibar addhist \"$0\"", u, NULL \ ++ } \ ++} ++ ++#define GOTO { \ ++ .v = (char *[]){"/bin/sh", "-c", \ ++ "~/.surf/omnibar goto \"$0\" \"$1\"", winid, "_SURF_GO", NULL \ ++ } \ ++} ++ + /* styles */ + /* + * The iteration will stop at the first match, beginning at the beginning of +@@ -112,7 +124,7 @@ static Key keys[] = { + { MODKEY, GDK_o, source, { 0 } }, + { MODKEY|GDK_SHIFT_MASK,GDK_o, inspector, { 0 } }, + +- { MODKEY, GDK_g, spawn, SETPROP("_SURF_URI", "_SURF_GO") }, ++ { MODKEY, GDK_g, spawn, GOTO }, + { MODKEY, GDK_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND") }, + { MODKEY, GDK_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND") }, + +diff --git a/surf.c b/surf.c +index f2170a4..c8fdab3 100644 +--- a/surf.c ++++ b/surf.c +@@ -789,11 +789,11 @@ loadstatuschange(WebKitWebView *view, GParamSpec *pspec, Client *c) + WebKitWebDataSource *src; + WebKitNetworkRequest *request; + SoupMessage *msg; +- char *uri; ++ char *uri = geturi(c); ++ Arg arg; + + switch (webkit_web_view_get_load_status (c->view)) { + case WEBKIT_LOAD_COMMITTED: +- uri = geturi(c); + if (strstr(uri, "https://") == uri) { + frame = webkit_web_view_get_main_frame(c->view); + src = webkit_web_frame_get_data_source(frame); +@@ -809,6 +809,8 @@ loadstatuschange(WebKitWebView *view, GParamSpec *pspec, Client *c) + setstyle(c, getstyle(uri)); + break; + case WEBKIT_LOAD_FINISHED: ++ arg = (Arg)ONLOAD(uri); ++ spawn(NULL, &arg); + c->progress = 100; + updatetitle(c); + if (diskcache) { diff --git a/surf.suckless.org/patches/surf-0.7-searchengines.diff b/surf.suckless.org/patches/surf-0.7-searchengines.diff @@ -0,0 +1,57 @@ +diff --git a/surf.c b/surf.c +index f2170a4..8803c64 100644 +--- a/surf.c ++++ b/surf.c +@@ -91,6 +91,12 @@ typedef struct { + G_DEFINE_TYPE(CookieJar, cookiejar, SOUP_TYPE_COOKIE_JAR_TEXT) + + typedef struct { ++ char *token; ++ char *uri; ++} SearchEngine; ++ ++ ++typedef struct { + char *regex; + char *style; + regex_t re; +@@ -178,6 +184,7 @@ static void loaduri(Client *c, const Arg *arg); + static void navigate(Client *c, const Arg *arg); + static Client *newclient(void); + static void newwindow(Client *c, const Arg *arg, gboolean noembed); ++static gchar *parseuri(const gchar *uri); + static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d); + static gboolean contextmenu(WebKitWebView *view, GtkWidget *menu, + WebKitHitTestResult *target, gboolean keyboard, +@@ -838,8 +845,7 @@ loaduri(Client *c, const Arg *arg) + u = g_strdup_printf("file://%s", rp); + free(rp); + } else { +- u = g_strrstr(uri, "://") ? g_strdup(uri) +- : g_strdup_printf("http://%s", uri); ++ u = parseuri(uri); + } + + setatom(c, AtomUri, uri); +@@ -1172,6 +1178,21 @@ menuactivate(GtkMenuItem *item, Client *c) + } + } + ++static gchar * ++parseuri(const gchar *uri) { ++ guint i; ++ ++ for (i = 0; i < LENGTH(searchengines); i++) { ++ if (searchengines[i].token == NULL || searchengines[i].uri == NULL || \ ++ *(uri + strlen(searchengines[i].token)) != ' ') ++ continue; ++ if (g_str_has_prefix(uri, searchengines[i].token)) ++ return g_strdup_printf(searchengines[i].uri, uri + strlen(searchengines[i].token) + 1); ++ } ++ ++ return g_strrstr(uri, "://") ? g_strdup(uri) : g_strdup_printf("http://%s", uri); ++} ++ + void + pasteuri(GtkClipboard *clipboard, const char *text, gpointer d) + { diff --git a/surf.suckless.org/patches/surf-0.7-smoothscrolling.diff b/surf.suckless.org/patches/surf-0.7-smoothscrolling.diff @@ -0,0 +1,238 @@ +diff --git a/config.def.h b/config.def.h +index 93a3d49..fa7935c 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -83,50 +83,51 @@ static SiteStyle styles[] = { + * edit the CLEANMASK() macro. + */ + static Key keys[] = { +- /* modifier keyval function arg Focus */ +- { MODKEY|GDK_SHIFT_MASK,GDK_r, reload, { .b = TRUE } }, +- { MODKEY, GDK_r, reload, { .b = FALSE } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_p, print, { 0 } }, +- +- { MODKEY, GDK_p, clipboard, { .b = TRUE } }, +- { MODKEY, GDK_y, clipboard, { .b = FALSE } }, +- +- { MODKEY|GDK_SHIFT_MASK,GDK_j, zoom, { .i = -1 } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_k, zoom, { .i = +1 } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_q, zoom, { .i = 0 } }, +- { 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_j, scroll_v, { .i = +1 } }, +- { MODKEY, GDK_k, scroll_v, { .i = -1 } }, +- { MODKEY, GDK_b, 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 } }, +- +- { 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_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 } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_n, find, { .b = FALSE } }, +- +- { MODKEY|GDK_SHIFT_MASK,GDK_c, toggle, { .v = "enable-caret-browsing" } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_i, toggle, { .v = "auto-load-images" } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_s, toggle, { .v = "enable-scripts" } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_v, toggle, { .v = "enable-plugins" } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_a, togglecookiepolicy, { 0 } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_m, togglestyle, { 0 } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_b, togglescrollbars, { 0 } }, +- { MODKEY|GDK_SHIFT_MASK,GDK_g, togglegeolocation, { 0 } }, ++ /* modifier keyval function arg Focus */ ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_r, reload, { .b = TRUE } }, ++ { MODKEY, GDK_KEY_r, reload, { .b = FALSE } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_p, print, { 0 } }, ++ ++ { MODKEY, GDK_KEY_p, clipboard, { .b = TRUE } }, ++ { MODKEY, GDK_KEY_y, clipboard, { .b = FALSE } }, ++ ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_j, zoom, { .i = -1 } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_k, zoom, { .i = +1 } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_q, zoom, { .i = 0 } }, ++ { MODKEY, GDK_KEY_minus, zoom, { .i = -1 } }, ++ { MODKEY, GDK_KEY_plus, zoom, { .i = +1 } }, ++ ++ { MODKEY, GDK_KEY_l, navigate, { .i = +1 } }, ++ { MODKEY, GDK_KEY_h, navigate, { .i = -1 } }, ++ ++ { MODKEY, GDK_KEY_j, scroll_v, { .i = +1 } }, ++ { MODKEY, GDK_KEY_k, scroll_v, { .i = -1 } }, ++ { MODKEY, GDK_KEY_b, scroll_v, { .i = -10000 } }, ++ { MODKEY, GDK_KEY_space, scroll_v, { .i = +10000 } }, ++ { MODKEY, GDK_KEY_i, scroll_h, { .i = +1 } }, ++ { MODKEY, GDK_KEY_u, scroll_h, { .i = -1 } }, ++ ++ { 0, GDK_KEY_F11, fullscreen, { 0 } }, ++ { 0, GDK_KEY_Escape, stop, { 0 } }, ++ { MODKEY, GDK_KEY_o, source, { 0 } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_o, inspector, { 0 } }, ++ ++ { MODKEY, GDK_KEY_g, spawn, SETPROP("_SURF_URI", "_SURF_GO") }, ++ { MODKEY, GDK_KEY_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND") }, ++ { MODKEY, GDK_KEY_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND") }, ++ ++ { MODKEY, GDK_KEY_n, find, { .b = TRUE } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_n, find, { .b = FALSE } }, ++ ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_c, toggle, { .v = "enable-caret-browsing" } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_i, toggle, { .v = "auto-load-images" } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_s, toggle, { .v = "enable-scripts" } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_v, toggle, { .v = "enable-plugins" } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_a, togglecookiepolicy, { 0 } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_m, togglestyle, { 0 } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_b, togglescrollbars, { 0 } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_KEY_g, togglegeolocation, { 0 } }, ++ + }; + + /* button definitions */ +diff --git a/config.mk b/config.mk +index 9f85ea4..a070f88 100644 +--- a/config.mk ++++ b/config.mk +@@ -10,8 +10,8 @@ MANPREFIX = ${PREFIX}/share/man + X11INC = /usr/X11R6/include + X11LIB = /usr/X11R6/lib + +-GTKINC = `pkg-config --cflags gtk+-2.0 webkit-1.0` +-GTKLIB = `pkg-config --libs gtk+-2.0 webkit-1.0` ++GTKINC = `pkg-config --cflags gtk+-3.0 webkitgtk-3.0` ++GTKLIB = `pkg-config --libs gtk+-3.0 webkitgtk-3.0` + + # includes and libs + INCS = -I. -I/usr/include -I${X11INC} ${GTKINC} +diff --git a/surf.c b/surf.c +index 108485b..7a708d4 100644 +--- a/surf.c ++++ b/surf.c +@@ -6,6 +6,7 @@ + #include <X11/X.h> + #include <X11/Xatom.h> + #include <gtk/gtk.h> ++#include <gtk/gtkx.h> + #include <gdk/gdkx.h> + #include <gdk/gdk.h> + #include <gdk/gdkkeysyms.h> +@@ -100,7 +101,7 @@ typedef struct { + static Display *dpy; + static Atom atoms[AtomLast]; + static Client *clients = NULL; +-static GdkNativeWindow embed = 0; ++static Window embed = 0; + static gboolean showxid = FALSE; + static char winid[64]; + static gboolean usingproxy = 0; +@@ -627,9 +628,9 @@ getatom(Client *c, int a) + unsigned long ldummy; + unsigned char *p = NULL; + +- XGetWindowProperty(dpy, GDK_WINDOW_XID(GTK_WIDGET(c->win)->window), +- atoms[a], 0L, BUFSIZ, False, XA_STRING, +- &adummy, &idummy, &ldummy, &ldummy, &p); ++ XGetWindowProperty(dpy, GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(c->win))), ++ atoms[a], 0L, BUFSIZ, False, XA_STRING, ++ &adummy, &idummy, &ldummy, &ldummy, &p); + if (p) + strncpy(buf, (char *)p, LENGTH(buf)-1); + else +@@ -873,6 +874,7 @@ newclient(void) + WebKitWebFrame *frame; + GdkGeometry hints = { 1, 1 }; + GdkScreen *screen; ++ GdkWindow *window; + gdouble dpi; + char *ua; + +@@ -902,6 +904,10 @@ newclient(void) + */ + gtk_window_set_role(GTK_WINDOW(c->win), "Surf"); + } ++ ++ gtk_widget_realize(GTK_WIDGET(c->win)); ++ window = gtk_widget_get_window(GTK_WIDGET(c->win)); ++ + gtk_window_set_default_size(GTK_WINDOW(c->win), 800, 600); + g_signal_connect(G_OBJECT(c->win), + "destroy", +@@ -914,10 +920,10 @@ newclient(void) + addaccelgroup(c); + + /* Pane */ +- c->pane = gtk_vpaned_new(); ++ c->pane = gtk_paned_new(GTK_ORIENTATION_VERTICAL); + + /* VBox */ +- c->vbox = gtk_vbox_new(FALSE, 0); ++ c->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_paned_pack1(GTK_PANED(c->pane), c->vbox, TRUE, TRUE); + + /* Webview */ +@@ -999,8 +1005,8 @@ newclient(void) + gtk_widget_show(c->win); + gtk_window_set_geometry_hints(GTK_WINDOW(c->win), NULL, &hints, + GDK_HINT_MIN_SIZE); +- gdk_window_set_events(GTK_WIDGET(c->win)->window, GDK_ALL_EVENTS_MASK); +- gdk_window_add_filter(GTK_WIDGET(c->win)->window, processx, c); ++ gdk_window_set_events(window, GDK_ALL_EVENTS_MASK); ++ gdk_window_add_filter(window, processx, c); + webkit_web_view_set_full_content_zoom(c->view, TRUE); + + runscript(frame); +@@ -1034,7 +1040,7 @@ newclient(void) + * It is equivalent to firefox's "layout.css.devPixelsPerPx" setting. + */ + if (zoomto96dpi) { +- screen = gdk_window_get_screen(GTK_WIDGET(c->win)->window); ++ screen = gdk_window_get_screen(window); + dpi = gdk_screen_get_resolution(screen); + if (dpi != -1) { + g_object_set(G_OBJECT(settings), +@@ -1073,7 +1079,7 @@ newclient(void) + if (showxid) { + gdk_display_sync(gtk_widget_get_display(c->win)); + printf("%u\n", +- (guint)GDK_WINDOW_XID(GTK_WIDGET(c->win)->window)); ++ (guint)GDK_WINDOW_XID(window)); + fflush(NULL); + if (fclose(stdout) != 0) + die("Error closing stdout"); +@@ -1281,7 +1287,7 @@ void + setatom(Client *c, int a, const char *v) + { + XSync(dpy, False); +- XChangeProperty(dpy, GDK_WINDOW_XID(GTK_WIDGET(c->win)->window), ++ XChangeProperty(dpy, GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(c->win))), + atoms[a], XA_STRING, 8, PropModeReplace, + (unsigned char *)v, strlen(v) + 1); + } +@@ -1302,7 +1308,7 @@ setup(void) + die("Can't install SIGHUP handler"); + gtk_init(NULL, NULL); + +- dpy = GDK_DISPLAY(); ++ dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); + + /* atoms */ + atoms[AtomFind] = XInternAtom(dpy, "_SURF_FIND", False); +@@ -1634,7 +1640,7 @@ void + updatewinid(Client *c) + { + snprintf(winid, LENGTH(winid), "%u", +- (int)GDK_WINDOW_XID(GTK_WIDGET(c->win)->window)); ++ (int)GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(c->win)))); + } + + void + diff --git a/surf.suckless.org/patches/surf-0.7-webkit2-searchengines.diff b/surf.suckless.org/patches/surf-0.7-webkit2-searchengines.diff @@ -0,0 +1,63 @@ +diff --git a/surf.c b/surf.c +index 9b4dbb9..bf54d84 100644 +--- a/surf.c ++++ b/surf.c +@@ -92,6 +92,12 @@ typedef struct { + } Button; + + typedef struct { ++ char *token; ++ char *uri; ++} SearchEngine; ++ ++ ++typedef struct { + char *regex; + char *style; + regex_t re; +@@ -124,6 +130,7 @@ static void newwindow(Client *c, const Arg *a, int noembed); + static void spawn(Client *c, const Arg *a); + static void destroyclient(Client *c); + static void cleanup(void); ++static gchar *parseuri(const gchar *uri); + + /* GTK/WebKit */ + static WebKitWebView *newview(Client *c, WebKitWebView *rv); +@@ -350,13 +357,13 @@ loaduri(Client *c, const Arg *a) + if (g_strcmp0(uri, "") == 0) + return; + +- if (g_strrstr(uri, "://") || g_str_has_prefix(uri, "about:")) { ++ if (g_str_has_prefix(uri, "about:")) { + url = g_strdup(uri); + } else if (!stat(uri, &st) && (path = realpath(uri, NULL))) { + url = g_strdup_printf("file://%s", path); + free(path); + } else { +- url = g_strdup_printf("http://%s", uri); ++ url = parseuri(uri); + } + + setatom(c, AtomUri, url); +@@ -1205,6 +1212,21 @@ destroywin(GtkWidget* w, Client *c) + gtk_main_quit(); + } + ++static gchar * ++parseuri(const gchar *uri) { ++ guint i; ++ ++ for (i = 0; i < LENGTH(searchengines); i++) { ++ if (searchengines[i].token == NULL || searchengines[i].uri == NULL || \ ++ *(uri + strlen(searchengines[i].token)) != ' ') ++ continue; ++ if (g_str_has_prefix(uri, searchengines[i].token)) ++ return g_strdup_printf(searchengines[i].uri, uri + strlen(searchengines[i].token) + 1); ++ } ++ ++ return g_strrstr(uri, "://") ? g_strdup(uri) : g_strdup_printf("http://%s", uri); ++} ++ + void + pasteuri(GtkClipboard *clipboard, const char *text, gpointer d) + { diff --git a/surf.suckless.org/patches/surf-git-20160127-searchengines.diff b/surf.suckless.org/patches/surf-git-20160127-searchengines.diff @@ -0,0 +1,74 @@ +diff --git a/config.def.h b/config.def.h +index 93a3d49..df96d15 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -75,6 +75,13 @@ static SiteStyle styles[] = { + { ".*", "default.css" }, + }; + ++/* search engines */ ++static SearchEngine searchengines[] = { ++ { "g", "http://www.google.de/search?q=%s" }, ++ { "leo", "http://dict.leo.org/ende?search=%s" }, ++ { "ddg", "https://duckduckgo.com/?q=%s" }, ++}; ++ + #define MODKEY GDK_CONTROL_MASK + + /* hotkeys */ +diff --git a/surf.c b/surf.c +index 23c49bd..579848d 100644 +--- a/surf.c ++++ b/surf.c +@@ -92,6 +92,11 @@ typedef struct { + G_DEFINE_TYPE(CookieJar, cookiejar, SOUP_TYPE_COOKIE_JAR_TEXT) + + typedef struct { ++ char *token; ++ char *uri; ++} SearchEngine; ++ ++typedef struct { + char *regex; + char *style; + regex_t re; +@@ -179,6 +184,7 @@ static void loaduri(Client *c, const Arg *arg); + static void navigate(Client *c, const Arg *arg); + static Client *newclient(void); + static void newwindow(Client *c, const Arg *arg, gboolean noembed); ++static gchar *parseuri(const gchar *uri); + static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d); + static gboolean contextmenu(WebKitWebView *view, GtkWidget *menu, + WebKitHitTestResult *target, gboolean keyboard, +@@ -840,8 +846,7 @@ loaduri(Client *c, const Arg *arg) + u = g_strdup_printf("file://%s", rp); + free(rp); + } else { +- u = g_strrstr(uri, "://") || g_str_has_prefix(uri, "about:") ? g_strdup(uri) +- : g_strdup_printf("http://%s", uri); ++ u = parseuri(uri); + } + + setatom(c, AtomUri, uri); +@@ -1173,6 +1178,21 @@ menuactivate(GtkMenuItem *item, Client *c) + } + } + ++gchar * ++parseuri(const gchar *uri) { ++ guint i; ++ ++ for (i = 0; i < LENGTH(searchengines); i++) { ++ if (searchengines[i].token == NULL || searchengines[i].uri == NULL ++ || *(uri + strlen(searchengines[i].token)) != ' ') ++ continue; ++ if (g_str_has_prefix(uri, searchengines[i].token)) ++ return g_strdup_printf(searchengines[i].uri, uri + strlen(searchengines[i].token) + 1); ++ } ++ return g_strrstr(uri, "://") || g_str_has_prefix(uri, "about:") ? g_strdup(uri) ++ : g_strdup_printf("http://%s", uri); ++} ++ + void + pasteuri(GtkClipboard *clipboard, const char *text, gpointer d) + { diff --git a/surf.suckless.org/patches/surf-tip-bookmarks.diff b/surf.suckless.org/patches/surf-tip-bookmarks.diff @@ -0,0 +1,41 @@ +diff --git a/config.def.h b/config.def.h +index 1c18827..4de93c3 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -37,9 +37,10 @@ static Bool allowgeolocation = TRUE; + + #define SETPROP(p, q) { \ + .v = (char *[]){ "/bin/sh", "-c", \ +- "prop=\"`xprop -id $2 $0 " \ ++ "prop=\"`(xprop -id $2 $0 " \ + "| sed \"s/^$0(STRING) = \\(\\\\\"\\?\\)\\(.*\\)\\1$/\\2/\" " \ +- "| xargs -0 printf %b | dmenu`\" &&" \ ++ "| xargs -0 printf %b &&" \ ++ "cat ~/.surf/bookmarks)| dmenu`\" &&" \ + "xprop -id $2 -f $1 8s -set $1 \"$prop\"", \ + p, q, winid, NULL \ + } \ +@@ -65,6 +66,15 @@ static Bool allowgeolocation = TRUE; + } \ + } + ++#define BM_ADD { \ ++ .v = (char *[]){ "/bin/sh", "-c", \ ++ "(echo `xprop -id $0 _SURF_URI | cut -d '\"' -f 2` && "\ ++ "cat ~/.surf/bookmarks) | awk '!seen[$0]++' > ~/.surf/bookmarks_new && "\ ++ "mv ~/.surf/bookmarks_new ~/.surf/bookmarks", \ ++ winid, NULL \ ++ } \ ++} ++ + /* styles */ + /* + * The iteration will stop at the first match, beginning at the beginning of +@@ -106,6 +116,7 @@ static Key keys[] = { + { MODKEY, GDK_space, scroll_v, { .i = +10000 } }, + { MODKEY, GDK_i, scroll_h, { .i = +1 } }, + { MODKEY, GDK_u, scroll_h, { .i = -1 } }, ++ { MODKEY, GDK_b, spawn, BM_ADD }, + + { 0, GDK_F11, fullscreen, { 0 } }, + { 0, GDK_Escape, stop, { 0 } }, diff --git a/surf.suckless.org/patches/surf-tip-navhist.diff b/surf.suckless.org/patches/surf-tip-navhist.diff @@ -0,0 +1,138 @@ +diff --git a/config.def.h b/config.def.h +index 5245129..604028f 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -45,6 +45,16 @@ static Bool allowgeolocation = TRUE; + } \ + } + ++#define SELNAV { \ ++ .v = (char *[]){ "/bin/sh", "-c", \ ++ "prop=\"`xprop -id $0 _SURF_HIST" \ ++ " | sed -e 's/^.[^\"]*\"//' -e 's/\"$//' -e 's/\\\\\\n/\\n/g'" \ ++ " | dmenu -i -l 10`\"" \ ++ " && xprop -id $0 -f _SURF_NAV 8s -set _SURF_NAV \"$prop\"", \ ++ winid, NULL \ ++ } \ ++} ++ + /* DOWNLOAD(URI, referer) */ + #define DOWNLOAD(d, r) { \ + .v = (char *[]){ "/bin/sh", "-c", \ +@@ -99,6 +109,7 @@ static Key keys[] = { + + { MODKEY, GDK_l, navigate, { .i = +1 } }, + { MODKEY, GDK_h, navigate, { .i = -1 } }, ++ { MODKEY|GDK_SHIFT_MASK,GDK_h, selhist, SELNAV }, + + { MODKEY, GDK_j, scroll_v, { .i = +1 } }, + { MODKEY, GDK_k, scroll_v, { .i = -1 } }, +diff --git a/surf.c b/surf.c +index 0fae80b..1c09336 100644 +--- a/surf.c ++++ b/surf.c +@@ -36,7 +36,7 @@ char *argv0; + #define COOKIEJAR_TYPE (cookiejar_get_type ()) + #define COOKIEJAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COOKIEJAR_TYPE, CookieJar)) + +-enum { AtomFind, AtomGo, AtomUri, AtomLast }; ++enum { AtomFind, AtomGo, AtomUri, AtomHist, AtomNav, AtomLast }; + enum { + ClkDoc = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT, + ClkLink = WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK, +@@ -177,6 +177,8 @@ static void loadstatuschange(WebKitWebView *view, GParamSpec *pspec, + Client *c); + static void loaduri(Client *c, const Arg *arg); + static void navigate(Client *c, const Arg *arg); ++static void selhist(Client *c, const Arg *arg); ++static void navhist(Client *c, const Arg *arg); + static Client *newclient(void); + static void newwindow(Client *c, const Arg *arg, gboolean noembed); + static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d); +@@ -813,6 +815,59 @@ navigate(Client *c, const Arg *arg) { + webkit_web_view_go_back_or_forward(c->view, steps); + } + ++static void ++selhist(Client *c, const Arg *arg) { ++ WebKitWebBackForwardList *lst; ++ WebKitWebHistoryItem *cur; ++ gint i; ++ gchar *out; ++ gchar *tmp; ++ gchar *line; ++ ++ out = g_strdup(""); ++ ++ if(!(lst = webkit_web_view_get_back_forward_list(c->view))) ++ return; ++ ++ for(i = webkit_web_back_forward_list_get_back_length(lst); i > 0; i--) { ++ if(!(cur = webkit_web_back_forward_list_get_nth_item(lst, -i))) ++ break; ++ line = g_strdup_printf("%d: %s\n", -i, ++ webkit_web_history_item_get_original_uri(cur)); ++ tmp = g_strconcat(out, line, NULL); ++ g_free(out); ++ out = tmp; ++ } ++ ++ if((cur = webkit_web_back_forward_list_get_nth_item(lst, 0))) { ++ line = g_strdup_printf("%d: %s", 0, ++ webkit_web_history_item_get_original_uri(cur)); ++ tmp = g_strconcat(out, line, NULL); ++ g_free(out); ++ out = tmp; ++ } ++ ++ for(i = 1; i <= webkit_web_back_forward_list_get_forward_length(lst); i++) { ++ if(!(cur = webkit_web_back_forward_list_get_nth_item(lst, i))) ++ break; ++ line = g_strdup_printf("\n%d: %s", i, ++ webkit_web_history_item_get_original_uri(cur)); ++ tmp = g_strconcat(out, line, NULL); ++ g_free(out); ++ out = tmp; ++ } ++ ++ setatom(c, AtomHist, out); ++ g_free(out); ++ spawn(c, arg); ++} ++ ++static void ++navhist(Client *c, const Arg *arg) { ++ Arg a = { .i = atoi(arg->v) }; ++ navigate(c, &a); ++} ++ + static Client * + newclient(void) { + Client *c; +@@ -1014,6 +1069,7 @@ newclient(void) { + + setatom(c, AtomFind, ""); + setatom(c, AtomUri, "about:blank"); ++ setatom(c, AtomHist, ""); + if(hidebackground) + webkit_web_view_set_transparent(c->view, TRUE); + +@@ -1153,6 +1209,9 @@ processx(GdkXEvent *e, GdkEvent *event, gpointer d) { + loaduri(c, &arg); + + return GDK_FILTER_REMOVE; ++ } else if(ev->atom == atoms[AtomNav]) { ++ arg.v = getatom(c, AtomNav); ++ navhist(c, &arg); + } + } + } +@@ -1247,6 +1306,8 @@ setup(void) { + atoms[AtomFind] = XInternAtom(dpy, "_SURF_FIND", False); + atoms[AtomGo] = XInternAtom(dpy, "_SURF_GO", False); + atoms[AtomUri] = XInternAtom(dpy, "_SURF_URI", False); ++ atoms[AtomHist] = XInternAtom(dpy, "_SURF_HIST", False); ++ atoms[AtomNav] = XInternAtom(dpy, "_SURF_NAV", False); + + /* dirs and files */ + cookiefile = buildfile(cookiefile); diff --git a/surf.suckless.org/patches/unicode-in-dmenu.md b/surf.suckless.org/patches/unicode-in-dmenu.md @@ -0,0 +1,17 @@ +Unicode in dmenu +================ + +Description +----------- + +This patch adds Unicode support to actions with dmenu: opening URL and finding in page. + +Download +-------- + +* [surf-0.6-dmenu-unicode.diff](surf-0.6-dmenu-unicode.diff) (0.8k) (18 Sep 2015) + +Author +------ + +* Danil Semelenov - `<mail at danil dot mobi>` diff --git a/surf.suckless.org/stylesheets/startpage-dark.css b/surf.suckless.org/stylesheets/startpage-dark.css @@ -1,110 +0,0 @@ -/* License: CC0 Public Domain (creativecommons.org/publicdomain/zero/1.0/) */ -/* Version: 2014-01-28 (userstyles.org/styles/96471) */ -/* AGENT_SHEET */ - - -#main_link > p, #sponsored, #news_message, #footer_links, .tod, -#logo > a > img, #results_header #detail, -#results_content div[style="padding-bottom:24px;"], -/* settings */ .tdtopcurve, .tdbottomcurve, -/* video */ #vsearch_engines .checkbox_img, -/* Google */ #search_form > #enhanced_cont, #enhanced -{ display: none !important; } - -body, div, ul, li, table, tbody, th, tr, td, h2, h3, p, form, dl, dt, dd, cite, code, -.searchbuttonlink, .official_block > span, -/* bottom */ #jumpsbar, #nextnavbar -{ background: none !important; } -a, span, strong { background-color: transparent !important; } - -html, #inner_promo_box { background: #222 !important; } -option, UL[style*="display"], div[style*="display"], blockquote, pre, #privacy, /* JS; tooltip */ #WzTtDiV { background: #181818 !important; } -.official_block { background: #722 !important; color: #ddd !important; border-radius: 3px; } -/* emails */ img[src$="email_black.gif"] { background: #ddd !important; } - -* { color: inherit !important; text-shadow: none !important; border-color: #555 !important; } -html, .active { color: #ccc !important; } -hr { height: 0 !important; border: 0 solid #555 !important; border-width: 1px 0 0 !important; } -a { color: #5af !important; text-decoration: none !important; } -h1, h2, h3, h4, h5, h6, th { color: #9cf !important; } -.result a:visited { color: #7b4 !important; } -a:hover { text-decoration: underline !important; } - -/* found in title of: web, video */ .result > h3 > a > b, #vtable a > b { /* nothing */ } -.result > h3 > a:hover > b { color: inherit !important; } -/* URL of results on: web, image, video */ .url, .normaltext[style*="green"], .video_desc > .normaltext { color: #777 !important; font-style: italic !important; } -/* found in URL */ .url > b, /* found in descriptions */ .desc > b, .normaltext > b, .video_desc > b { color: #f5f !important; font-weight: normal !important; } - -::-moz-selection { background: #148 !important; } -::selection { background: #184880 !important; } - -input[type="submit"], input[type="button"], input[type="file"], input[type="reset"], button -{ color: #fff !important; border: 1px solid #555 !important; background: #111 !important; -padding: 2px 5px !important; -border-radius: 3px !important; box-shadow: none !important; text-shadow: none !important; -background-image: linear-gradient(rgba(255,255,255,0.2),rgba(125,125,125,0.2),rgba(0,0,0,0.3)) !important; } - -input[type="submit"]:hover, input[type="button"]:hover, input[type="file"]:hover, input[type="reset"]:hover, button:hover -{ border-color: currentColor !important; background-color: #000 !important; color: #4be !important; } - -button, input, select, textarea { -moz-appearance: none !important; } -input[type="radio"], input[type="checkbox"] { color: #4be !important; background: #222 !important; border-color: #999 !important; } - -input, select, textarea, input[type="text"] { background: #181818 !important; color: #ccc !important; padding: 2px !important; border: 1px solid #555 !important; box-shadow: none !important; } -input[type] { border-width: 1px !important; border-style: solid !important; } -textarea:hover, input:hover, select:hover, textarea:focus, input:focus, select:focus { border-color: #09f !important; } - -select > button { background-color: transparent !important; border: none !important; } -option:hover, option:focus, option:active, option:checked { background: linear-gradient(#158,#158) !important; } - -#search { margin-bottom: 18px !important; padding: 0 !important; } -#head { margin-bottom: 0 !important; } - -/* Support Center */ -#main .searchboxcontainer { border-width: 1px !important; } -#main .searchquery { height: 29px !important; margin: 0 !important; } -/* Support Center, iq Phone */ .current { border-bottom: 1px solid #555 !important; border-radius: 5px; } -/* SERP */ #tod_wrap, /* iq Phone */ #submit_box { border: 0 !important; } -#results_count_p { color: #777 !important; margin: -8px 0 0 220px !important; } -.sugg { display: inline-block !important; margin-top: 8px !important; } -/* collapse space of "Bookmark this search", but keep the link */ #tip .bookmark { height: 0 !important; border: 0 !important; } - -/* centering - begin */ /* -body { max-width: 900px !important; margin: 0 auto !important; } -#logo, #side_bar, #show_hide > span { left: auto !important } -#video_results td[width="320"] { width: 100px !important; } -#video_results img[src="graphics/spacer.gif"] { display: none !important; } -/* centering - end */ - -input.invisible { padding: 0 !important; border: 0 !important; } -.result { margin: 8px 145px 12px 10px !important; padding: 5px !important; } -#main_link + #search_form { padding: 0 !important; } -/* video */ #vsearch_engines input { visibility: visible !important; } -#office_website b { text-decoration: none !important; } - -img:not(:hover) { opacity: .7; } -#results_content img { opacity: 1; } - -.result #proxy_link { font-size: 0 !important; text-decoration: none !important; } -.result #proxy_link::before { content: "Proxy"; font-size: 13px; } -.result #proxy_link:hover::before { text-decoration: underline !important; } - -#main_link { font: 0px/1.2 monospace !important; margin-bottom: 40px !important; text-decoration: none !important; } -#main_link::before { content: "start"; color: #f55; font-size: 40px !important; } -#main_link::after { content: "page"; color: #09f; font-size: 40px !important; } -tr + tr #main_link::before { content: "ix"; color: #f55; } -tr + tr #main_link::after { content: "quick"; color: #09f; } - -#logo > a { font-size: 30px !important; text-decoration: none !important; } -#logo > a[href^="https://startpage.com/"]::before { content: "start"; color: #f55; } -#logo > a[href^="https://startpage.com/"]::after { content: "page"; color: #09f; } -#logo > a[href^="https://ixquick.com/"] { font: 30px/1.6 monospace; } -#logo > a[href^="https://ixquick.com/"]::before { content: "ix"; color: #f55; } -#logo > a[href^="https://ixquick.com/"]::after { content: "quick"; color: #09f; } - -img[src="s/white/graphics/star.gif"], .fixstar { height: 10px !important; width: 0 !important; padding: 0 5px !important; background: #995 !important; border-radius: 7px !important; border: 2px solid #222 !important; } -.fixstar { margin-right: 4px; } - -#submit[type="image"], #submit1[type="image"] { height: 27px !important; width: 0 !important; padding: 0 14px !important; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAASCAQAAADBVSe6AAABBklEQVQoz23RP0gCYRjH8RtMyKG5RcKhqbZoaBSXpqChSaKhzak4CMcLaojA6EB9vq+5RBCIBi1NEq1hS7TVWK0hKrp1vd3reeId7/J7nw/v8/6zPCsYapsWX3RpYzuJ/8oYSvNyQ48TtSU5jvigU8tMkAverpaCHqS4peMk/EltjWF1NdzA53dsE4vcT5NfO6RtQkOOI5ila0Kdy1nUZ/80oaCeIyvPaPqhvMiPyk+TLDOQzaDJLn32Ji3X9U3r4T3neNJv80JFznlkxGkjGWIRr5qXfSpcc6BWTNU8Qoah3M0eaYw80C+nY5EdPOwoaXQX+ObVfFEElcuvbMSRRhzlxpNn/QHXYQdvX6L97AAAAABJRU5ErkJggg==") center no-repeat, linear-gradient(rgba(255,255,255,0.2),rgba(125,125,125,0.2),rgba(0,0,0,0.3)) !important; } -#submit:hover, #submit1:hover { background-color: #000 !important; } -td > #submit1 { margin-left: 6px !important; } diff --git a/surf.suckless.org/stylesheets/startpage.md b/surf.suckless.org/stylesheets/startpage.md @@ -4,10 +4,14 @@ startpage.com Startpage is a nice searchengine, providing the same results as google, but hiding your identity in the anonymity set of all startpage users. -Dark CSS --------- +No ads css +---------- -This [css](startpage-dark.css) is from -[userstyles.org](https://userstyles.org/styles/96471/startpage-dark) and -licensed under publicdomain. It also hides the ads, which are normally displayed -above the search results. + #bottom-result-container #spon_links { display: none !important; } + #bottom-result-container #sponsored_csa1 { display: none !important; } + #bottom-result-container #sponsored_csa2 { display: none !important; } + +Author +------ + +* Markus Teich diff --git a/tools.suckless.org/dmenu/index.md b/tools.suckless.org/dmenu/index.md @@ -9,7 +9,7 @@ items efficiently. Download -------- -* [dmenu-4.5](http://dl.suckless.org/tools/dmenu-4.5.tar.gz) (20120108) +* [dmenu-4.6](http://dl.suckless.org/tools/dmenu-4.6.tar.gz) (20151109) Mailing list @@ -18,3 +18,9 @@ Mailing list * `dev+subscribe@suckless.org` ([Archives](http://lists.suckless.org/dev/)) ([Old Archives](http://lists.suckless.org/dwm/)) (see [community](http://suckless.org/community/) for details) + +Development +----------- +You can [browse](http://git.suckless.org/dmenu) its source code repository or get a copy using git with the following command: + + git clone http://git.suckless.org/dmenu diff --git a/tools.suckless.org/dmenu/patches/dmenu-4.5-fuzzymatch.diff b/tools.suckless.org/dmenu/patches/dmenu-4.5-fuzzymatch.diff @@ -1,12 +1,8 @@ -Author: Jan Christoph Ebersbach <jceb@e-jc.de> -URL: no url in suckless wiki yet -Add add fuzzy matching to dmenu - -Index: dmenu-patches/dmenu/dmenu.c -=================================================================== ---- dmenu-patches.orig/dmenu/dmenu.c -+++ dmenu-patches/dmenu/dmenu.c -@@ -22,12 +22,14 @@ typedef struct Item Item; +diff --git a/dmenu.c b/dmenu.c +index 4ea95f8..19c5cb6 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -22,6 +22,7 @@ typedef struct Item Item; struct Item { char *text; Item *left, *right; @@ -14,54 +10,10 @@ Index: dmenu-patches/dmenu/dmenu.c }; static void appenditem(Item *item, Item **list, Item **last); - static void calcoffsets(void); - static char *cistrstr(const char *s, const char *sub); - static void drawmenu(void); -+static void fuzzymatch(void); - static void grabkeyboard(void); - static void insert(const char *str, ssize_t n); - static void keypress(XKeyEvent *ev); -@@ -230,7 +232,7 @@ insert(const char *str, ssize_t n) { - if(n > 0) - memcpy(&text[cursor], str, n); - cursor += n; -- match(); -+ fuzzymatch(); +@@ -221,6 +222,86 @@ grabkeyboard(void) { + eprintf("cannot grab keyboard\n"); } - void -@@ -260,7 +262,7 @@ keypress(XKeyEvent *ev) { - - case XK_k: /* delete right */ - text[cursor] = '\0'; -- match(); -+ fuzzymatch(); - break; - case XK_u: /* delete left */ - insert(NULL, 0 - cursor); -@@ -379,7 +381,7 @@ keypress(XKeyEvent *ev) { - return; - strncpy(text, sel->text, sizeof text); - cursor = strlen(text); -- match(); -+ fuzzymatch(); - break; - } - drawmenu(); -@@ -578,7 +580,7 @@ setup(void) { - } - promptw = prompt ? textw(dc, prompt) : 0; - inputw = MIN(inputw, mw/3); -- match(); -+ fuzzymatch(); - - /* create menu window */ - swa.override_redirect = True; -Index: dmenu-patches/dmenu/fuzzymatch.c -=================================================================== ---- /dev/null -+++ dmenu-patches/dmenu/fuzzymatch.c -@@ -0,0 +1,79 @@ +int +compare_distance(const void *a, const void *b) { + Item const *da = *(Item **) a; @@ -141,3 +93,43 @@ Index: dmenu-patches/dmenu/fuzzymatch.c + curr = sel = matches; + calcoffsets(); +} ++ + void + insert(const char *str, ssize_t n) { + if(strlen(text) + n > sizeof text - 1) +@@ -230,7 +311,7 @@ insert(const char *str, ssize_t n) { + if(n > 0) + memcpy(&text[cursor], str, n); + cursor += n; +- match(); ++ fuzzymatch(); + } + + void +@@ -260,7 +341,7 @@ keypress(XKeyEvent *ev) { + + case XK_k: /* delete right */ + text[cursor] = '\0'; +- match(); ++ fuzzymatch(); + break; + case XK_u: /* delete left */ + insert(NULL, 0 - cursor); +@@ -379,7 +460,7 @@ keypress(XKeyEvent *ev) { + return; + strncpy(text, sel->text, sizeof text); + cursor = strlen(text); +- match(); ++ fuzzymatch(); + break; + } + drawmenu(); +@@ -578,7 +659,7 @@ setup(void) { + } + promptw = prompt ? textw(dc, prompt) : 0; + inputw = MIN(inputw, mw/3); +- match(); ++ fuzzymatch(); + + /* create menu window */ + swa.override_redirect = True; diff --git a/tools.suckless.org/dmenu/patches/dmenu-4.5-hide-single-newline.diff b/tools.suckless.org/dmenu/patches/dmenu-4.5-hide-single-newline.diff @@ -0,0 +1,12 @@ +diff --git a/dmenu.c b/dmenu.c +index 4ea95f8..4b76da5 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -482,6 +482,7 @@ readstdin(void) { + } + if(items) + items[i].text = NULL; ++ if (i == 1 && items[0].text[0] == '\0') items = realloc(items, 0); + inputw = maxstr ? textw(dc, maxstr) : 0; + lines = MIN(lines, i); + } diff --git a/tools.suckless.org/dmenu/patches/dmenu-4.5-xft-improved.diff b/tools.suckless.org/dmenu/patches/dmenu-4.5-xft-improved.diff @@ -0,0 +1,425 @@ +diff --git a/config.mk b/config.mk +index 92a5e63..9cff5db 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=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +diff --git a/dmenu.1 b/dmenu.1 +index 0784cd9..f29ca36 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -53,7 +53,7 @@ dmenu lists items vertically, with the given number of lines. + 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" (an xft font) + .TP + .BI \-nb " color" + defines the normal background color. +diff --git a/dmenu.c b/dmenu.c +index 4ea95f8..b4549ef 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 "monospace-9" /* xft example: "Monospace-11" */ + + typedef struct Item Item; + struct Item { +@@ -26,6 +27,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); +@@ -50,10 +52,12 @@ static const char *normfgcolor = "#bbbbbb"; + static const char *selbgcolor = "#005577"; + static const char *selfgcolor = "#eeeeee"; + static unsigned int lines = 0; +-static unsigned long normcol[ColLast]; +-static unsigned long selcol[ColLast]; ++static ColorSet *normcol; ++static ColorSet *selcol; + static Atom clip, utf8; + static Bool topbar = True; ++static Bool running = True; ++static int ret = 0; + static DC *dc; + static Item *items = NULL; + static Item *matches, *matchend; +@@ -104,7 +108,9 @@ 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); + + if(fast) { + grabkeyboard(); +@@ -117,7 +123,8 @@ main(int argc, char *argv[]) { + setup(); + run(); + +- return 1; /* unreachable */ ++ cleanup(); ++ return ret; + } + + void +@@ -160,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; +@@ -167,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) { + dc->w = promptw; +@@ -177,8 +193,9 @@ drawmenu(void) { + /* draw input field */ + dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw; + drawtext(dc, text, normcol); ++ dc->x += 2; + 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 */ +@@ -321,7 +338,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; +@@ -359,7 +377,8 @@ keypress(XKeyEvent *ev) { + case XK_Return: + case XK_KP_Enter: + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); +- exit(EXIT_SUCCESS); ++ ret = EXIT_SUCCESS; ++ running = False; + case XK_Right: + if(text[cursor] != '\0') { + cursor = nextrune(+1); +@@ -490,7 +509,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) { +@@ -524,11 +543,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); +- + clip = XInternAtom(dc->dpy, "CLIPBOARD", False); + utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); + +@@ -582,7 +596,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..81b991c 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) ++ if(dc->font.xfont) + XFreeFont(dc->dpy, dc->font.xfont); +- if(dc->canvas) ++ 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.descent = MAX(dc->font.descent, xfonts[i]->descent); + 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.xOff; ++ } 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); diff --git a/tools.suckless.org/dmenu/patches/dmenu-4.6-line-height.diff b/tools.suckless.org/dmenu/patches/dmenu-4.6-line-height.diff @@ -0,0 +1,99 @@ +diff --git a/config.def.h b/config.def.h +index a9122f7..6d936b7 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,3 +15,6 @@ static const char *outbgcolor = "#00ffff"; + static const char *outfgcolor = "#000000"; + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ + static unsigned int lines = 0; ++ ++static unsigned int lineheight = 0; /* -lh option; minimum height of a menu line */ ++ +diff --git a/dmenu.1 b/dmenu.1 +index d3ab805..9fe4434 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -51,6 +51,9 @@ dmenu matches menu items case insensitively. + .BI \-l " lines" + dmenu lists items vertically, with the given number of lines. + .TP ++.BI \-lh " height" ++dmenu uses a menu line of at least 'height' pixels tall, but no less than 8. ++.TP + .BI \-m " monitor" + dmenu is displayed on the monitor number supplied. Monitor numbers are starting + from 0. +diff --git a/dmenu.c b/dmenu.c +index a07f8e3..25832a7 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -119,7 +119,7 @@ drawmenu(void) + { + int curpos; + struct item *item; +- int x = 0, y = 0, h = bh, w; ++ int x = 0, y = 0, fh = drw->fonts[0]->h, w; + + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, 1, 1, 1); +@@ -134,16 +134,16 @@ drawmenu(void) + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, text, 0); + +- if ((curpos = TEXTNW(text, cursor) + bh / 2 - 2) < w) { ++ if ((curpos = TEXTNW(text, cursor) + fh / 2 - 2) < w) { + drw_setscheme(drw, &scheme[SchemeNorm]); +- drw_rect(drw, x + curpos + 2, 2, 1, bh - 4, 1, 1, 0); ++ drw_rect(drw, x + curpos + 2, 2 + (bh-fh)/2, 1, fh - 4, 1, 1, 0); + } + + if (lines > 0) { + /* draw vertical list */ + w = mw - x; + for (item = curr; item != next; item = item->right) { +- y += h; ++ y += bh; + if (item == sel) + drw_setscheme(drw, &scheme[SchemeSel]); + else if (item->out) +@@ -544,6 +544,7 @@ setup(void) + + /* calculate menu geometry */ + bh = drw->fonts[0]->h + 2; ++ bh = MAX(bh,lineheight); /* make a menu line AT LEAST 'lineheight' tall */ + lines = MAX(lines, 0); + mh = (lines + 1) * bh; + #ifdef XINERAMA +@@ -608,7 +609,7 @@ setup(void) + static void + usage(void) + { +- fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" ++ fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-lh height] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr); + exit(1); + } +@@ -641,6 +642,10 @@ main(int argc, char *argv[]) + prompt = argv[++i]; + else if (!strcmp(argv[i], "-fn")) /* font or font set */ + fonts[0] = argv[++i]; ++ else if(!strcmp(argv[i], "-lh")) { /* minimum height of one menu line */ ++ lineheight = atoi(argv[++i]); ++ lineheight = MAX(lineheight,8); /* reasonable default in case of value too small/negative */ ++ } + else if (!strcmp(argv[i], "-nb")) /* normal background color */ + normbgcolor = argv[++i]; + else if (!strcmp(argv[i], "-nf")) /* normal foreground color */ +diff --git a/drw.c b/drw.c +index 80e3c39..f4a741f 100644 +--- a/drw.c ++++ b/drw.c +@@ -291,7 +291,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex + if (render) { + th = curfont->ascent + curfont->descent; + ty = y + (h / 2) - (th / 2) + curfont->ascent; +- tx = x + (h / 2); ++ tx = x + (drw->fonts[0]->h / 2); + XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); + } + x += tex.w; diff --git a/tools.suckless.org/dmenu/patches/dmenu-4.6-mouse-support-msel.diff b/tools.suckless.org/dmenu/patches/dmenu-4.6-mouse-support-msel.diff @@ -0,0 +1,154 @@ +diff --git a/dmenu.c b/dmenu.c +index a07f8e3..1de62c1 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -277,6 +277,129 @@ nextrune(int inc) + return n; + } + ++void ++buttonpress(XEvent *e) ++{ ++ struct item *item; ++ XButtonPressedEvent *ev = &e->xbutton; ++ int xpos, ypos, wpos, hpos; ++ ++ if(ev->window != win) ++ return; ++ ++ /* right-click: exit */ ++ if(ev->button == Button3) ++ exit(EXIT_FAILURE); ++ ++ xpos = 0; ++ ypos = 0; ++ hpos = bh; ++ ++ if(prompt && *prompt) { ++ wpos = promptw; ++ xpos = wpos; ++ } ++ /* input field */ ++ wpos = (lines > 0 || !matches) ? mw - xpos : inputw; ++ ++ /* left-click on input: clear input, ++ * NOTE: if there is no left-arrow the space for < is reserved so ++ * add that to the input width */ ++ if(ev->button == Button1 && ++ ((lines <= 0 && ev->x >= 0 && ev->x <= xpos + wpos + ++ ((!prev || !curr->left) ? TEXTW("<") : 0)) || ++ (lines > 0 && ev->y >= ypos && ev->y <= ypos + hpos))) { ++ insert(NULL, 0 - cursor); ++ drawmenu(); ++ return; ++ } ++ /* middle-mouse click: paste selection */ ++ if(ev->button == Button2) { ++ XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, ++ utf8, utf8, win, CurrentTime); ++ drawmenu(); ++ return; ++ } ++ /* scroll up */ ++ if(ev->button == Button4 && prev) { ++ sel = curr = prev; ++ calcoffsets(); ++ drawmenu(); ++ return; ++ } ++ /* scroll down */ ++ if(ev->button == Button5 && next) { ++ sel = curr = next; ++ calcoffsets(); ++ drawmenu(); ++ return; ++ } ++ if(ev->button != Button1) ++ return; ++ if(ev->state & ~ControlMask) ++ return; ++ if(lines > 0) { ++ /* vertical list: (ctrl-)left-click on item */ ++ wpos = mw - xpos; ++ for(item = curr; item != next; item = item->right) { ++ ypos += hpos; ++ if(ev->y >= ypos && ev->y <= (ypos + hpos)) { ++ puts(item->text); ++ sel=item; ++ if (!(ev->state & ControlMask)) { ++ cleanup(); ++ exit(EXIT_SUCCESS); ++ } ++ if (sel) { ++ sel->out = 1; ++ drawmenu(); ++ } ++ return; ++ } ++ } ++ } ++ else if(matches) { ++ /* left-click on left arrow */ ++ xpos += inputw; ++ wpos = TEXTW("<"); ++ if(prev && curr->left) { ++ if(ev->x >= xpos && ev->x <= xpos + wpos) { ++ sel = curr = prev; ++ calcoffsets(); ++ drawmenu(); ++ return; ++ } ++ } ++ /* horizontal list: (ctrl-)left-click on item */ ++ for(item = curr; item != next; item = item->right) { ++ xpos += wpos; ++ wpos = MIN(TEXTW(item->text), mw - xpos - TEXTW(">")); ++ if(ev->x >= xpos && ev->x <= (xpos + wpos)) { ++ puts(item->text); ++ sel=item; ++ if (!(ev->state & ControlMask)) { ++ cleanup(); ++ exit(EXIT_SUCCESS); ++ } ++ if (sel) { ++ sel->out = 1; ++ drawmenu(); ++ } ++ return; ++ } ++ } ++ /* left-click on right arrow */ ++ wpos = TEXTW(">"); ++ xpos = mw - wpos; ++ if(next && ev->x >= xpos && ev->x <= xpos + wpos) { ++ sel = curr = next; ++ calcoffsets(); ++ drawmenu(); ++ return; ++ } ++ } ++} ++ + static void + keypress(XKeyEvent *ev) + { +@@ -502,6 +625,9 @@ run(void) + if (ev.xexpose.count == 0) + drw_map(drw, win, 0, 0, mw, mh); + break; ++ case ButtonPress: ++ buttonpress(&ev); ++ break; + case KeyPress: + keypress(&ev.xkey); + break; +@@ -589,7 +715,8 @@ setup(void) + /* create menu window */ + swa.override_redirect = True; + swa.background_pixel = scheme[SchemeNorm].bg->pix; +- swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; ++ swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | ++ ButtonPressMask; + win = XCreateWindow(dpy, root, x, y, mw, mh, 0, + DefaultDepth(dpy, screen), CopyFromParent, + DefaultVisual(dpy, screen), diff --git a/tools.suckless.org/dmenu/patches/dmenu-4.6-vertfull.diff b/tools.suckless.org/dmenu/patches/dmenu-4.6-vertfull.diff @@ -0,0 +1,20 @@ +diff -wu a/dmenu.c b/dmenu.c +--- a/dmenu.c 2015-11-08 23:42:21.000000000 +0100 ++++ b/dmenu.c 2015-11-10 18:13:43.937450512 +0100 +@@ -141,7 +141,6 @@ + + if (lines > 0) { + /* draw vertical list */ +- w = mw - x; + for (item = curr; item != next; item = item->right) { + y += h; + if (item == sel) +@@ -151,7 +150,7 @@ + else + drw_setscheme(drw, &scheme[SchemeNorm]); + +- drw_text(drw, x, y, w, bh, item->text, 0); ++ drw_text(drw, 0, y, mw, bh, item->text, 0); + } + } else if (matches) { + /* draw horizontal list */ diff --git a/tools.suckless.org/dmenu/patches/dmenu-4.6-xyw.diff b/tools.suckless.org/dmenu/patches/dmenu-4.6-xyw.diff @@ -0,0 +1,87 @@ +diff --git a/dmenu.1 b/dmenu.1 +index d3ab805..5301910 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -51,6 +51,24 @@ dmenu matches menu items case insensitively. + .BI \-l " lines" + dmenu lists items vertically, with the given number of lines. + .TP ++.BI \-x " xoffset" ++dmenu is placed at this offset measured from the left side of the monitor. ++Can be negative. ++If option ++.B \-m ++is present, the measurement will use the given monitor. ++.TP ++.BI \-y " yoffset" ++dmenu is placed at this offset measured from the top of the monitor. If the ++.B \-b ++option is used, the offset is measured from the bottom. Can be negative. ++If option ++.B \-m ++is present, the measurement will use the given monitor. ++.TP ++.BI \-w " width" ++sets the width of the dmenu window. ++.TP + .BI \-m " monitor" + dmenu is displayed on the monitor number supplied. Monitor numbers are starting + from 0. +diff --git a/dmenu.c b/dmenu.c +index a07f8e3..9e0c51c 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -37,6 +37,9 @@ struct item { + static char text[BUFSIZ] = ""; + static int bh, mw, mh; + static int sw, sh; /* X display screen geometry width, height */ ++static int dmx = 0; /* put dmenu at this x offset */ ++static int dmy = 0; /* put dmenu at this y offset (measured from the bottom if topbar is 0) */ ++static unsigned int dmw = 0; /* make dmenu this wide */ + static int inputw, promptw; + static size_t cursor; + static struct item *items = NULL; +@@ -571,16 +574,16 @@ setup(void) + if (INTERSECT(x, y, 1, 1, info[i])) + break; + +- x = info[i].x_org; +- y = info[i].y_org + (topbar ? 0 : info[i].height - mh); +- mw = info[i].width; ++ x = info[i].x_org + dmx; ++ y = info[i].y_org + (topbar ? dmy : info[i].height - mh - dmy); ++ mw = (dmw>0 ? dmw : info[i].width); + XFree(info); + } else + #endif + { +- x = 0; +- y = topbar ? 0 : sh - mh; +- mw = sw; ++ x = dmx; ++ y = topbar ? dmy : sh - mh - dmy; ++ mw = (dmw>0 ? dmw : sw); + } + promptw = (prompt && *prompt) ? TEXTW(prompt) : 0; + inputw = MIN(inputw, mw/3); +@@ -609,6 +612,7 @@ static void + usage(void) + { + fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" ++ " [-x xoffset] [-y yoffset] [-w width]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr); + exit(1); + } +@@ -635,6 +639,12 @@ main(int argc, char *argv[]) + /* these options take one argument */ + else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ + lines = atoi(argv[++i]); ++ else if (!strcmp(argv[i], "-x")) /* window x offset */ ++ dmx = atoi(argv[++i]); ++ else if (!strcmp(argv[i], "-y")) /* window y offset (from bottom up if -b) */ ++ dmy = atoi(argv[++i]); ++ else if (!strcmp(argv[i], "-w")) /* make dmenu this wide */ ++ dmw = atoi(argv[++i]); + else if (!strcmp(argv[i], "-m")) + mon = atoi(argv[++i]); + else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */ diff --git a/tools.suckless.org/dmenu/patches/dmenu-default-height.png b/tools.suckless.org/dmenu/patches/dmenu-default-height.png Binary files differ. diff --git a/tools.suckless.org/dmenu/patches/dmenu-git-20151020-fuzzymatch.diff b/tools.suckless.org/dmenu/patches/dmenu-git-20151020-fuzzymatch.diff @@ -0,0 +1,135 @@ +diff --git a/dmenu.c b/dmenu.c +index 4f22ffe..c2fc3ee 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -33,6 +33,7 @@ struct item { + char *text; + struct item *left, *right; + bool out; ++ int distance; + }; + + static char text[BUFSIZ] = ""; +@@ -254,6 +255,86 @@ match(void) + calcoffsets(); + } + ++int ++compare_distance(const void *a, const void *b) ++{ ++ struct item *da = *(struct item **) a; ++ struct item *db = *(struct item **) b; ++ ++ if (!db) ++ return 1; ++ if (!da) ++ return -1; ++ ++ return da->distance - db->distance; ++} ++ ++void ++fuzzymatch(void) ++{ ++ /* bang - we have so much memory */ ++ struct item *it; ++ struct item **fuzzymatches = NULL; ++ char c; ++ int number_of_matches = 0, i, pidx, sidx, eidx; ++ int text_len = strlen(text), itext_len; ++ ++ matches = matchend = NULL; ++ ++ /* walk through all items */ ++ for (it = items; it && it->text; it++) { ++ if (text_len) { ++ itext_len = strlen(it->text); ++ pidx = 0; ++ sidx = eidx = -1; ++ /* walk through item text */ ++ for (i = 0; i < itext_len && (c = it->text[i]); i++) { ++ /* fuzzy match pattern */ ++ if (text[pidx] == c) { ++ if(sidx == -1) ++ sidx = i; ++ pidx++; ++ if (pidx == text_len) { ++ eidx = i; ++ break; ++ } ++ } ++ } ++ /* build list of matches */ ++ if (eidx != -1) { ++ /* compute distance */ ++ /* factor in 30% of sidx and distance between eidx and total ++ * text length .. let's see how it works */ ++ it->distance = eidx - sidx + (itext_len - eidx + sidx) / 3; ++ appenditem(it, &matches, &matchend); ++ number_of_matches++; ++ } ++ } else { ++ appenditem(it, &matches, &matchend); ++ } ++ } ++ ++ if (number_of_matches) { ++ /* initialize array with matches */ ++ if (!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(struct item*)))) ++ die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item*)); ++ for (i = 0, it = matches; it && i < number_of_matches; i++, it = it->right) { ++ fuzzymatches[i] = it; ++ } ++ /* sort matches according to distance */ ++ qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance); ++ /* rebuild list of matches */ ++ matches = matchend = NULL; ++ for (i = 0, it = fuzzymatches[i]; i < number_of_matches && it && \ ++ it->text; i++, it = fuzzymatches[i]) { ++ appenditem(it, &matches, &matchend); ++ } ++ free(fuzzymatches); ++ } ++ curr = sel = matches; ++ calcoffsets(); ++} ++ + static void + insert(const char *str, ssize_t n) + { +@@ -264,7 +345,7 @@ insert(const char *str, ssize_t n) + if (n > 0) + memcpy(&text[cursor], str, n); + cursor += n; +- match(); ++ fuzzymatch(); + } + + static size_t +@@ -309,7 +390,7 @@ keypress(XKeyEvent *ev) + + case XK_k: /* delete right */ + text[cursor] = '\0'; +- match(); ++ fuzzymatch(); + break; + case XK_u: /* delete left */ + insert(NULL, 0 - cursor); +@@ -443,7 +524,7 @@ keypress(XKeyEvent *ev) + strncpy(text, sel->text, sizeof text - 1); + text[sizeof text - 1] = '\0'; + cursor = strlen(text); +- match(); ++ fuzzymatch(); + break; + } + drawmenu(); +@@ -585,7 +666,7 @@ setup(void) + } + promptw = (prompt && *prompt) ? TEXTW(prompt) : 0; + inputw = MIN(inputw, mw/3); +- match(); ++ fuzzymatch(); + + /* create menu window */ + swa.override_redirect = True; diff --git a/tools.suckless.org/dmenu/patches/dmenu-git-20160111-hide-single-newline.diff b/tools.suckless.org/dmenu/patches/dmenu-git-20160111-hide-single-newline.diff @@ -0,0 +1,12 @@ +diff --git a/dmenu.c b/dmenu.c +index e0c2f80..ef25442 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -487,6 +487,7 @@ readstdin(void) + } + if (items) + items[i].text = NULL; ++ if (i == 1 && items[0].text[0] == '\0') items = realloc(items, 0); + inputw = maxstr ? TEXTW(maxstr) : 0; + lines = MIN(lines, i); + } diff --git a/tools.suckless.org/dmenu/patches/dmenu-git-fuzzymatch.diff b/tools.suckless.org/dmenu/patches/dmenu-git-fuzzymatch.diff @@ -1,143 +0,0 @@ -Author: Jan Christoph Ebersbach <jceb@e-jc.de> -URL: http://tools.suckless.org/dmenu/patches/fuzzymatch -Add add fuzzy matching to dmenu - -Index: dmenu-patches/dmenu/dmenu.c -=================================================================== ---- dmenu-patches.orig/dmenu/dmenu.c -+++ dmenu-patches/dmenu/dmenu.c -@@ -23,12 +23,14 @@ struct Item { - char *text; - Item *left, *right; - Bool out; -+ int distance; - }; - - static void appenditem(Item *item, Item **list, Item **last); - static void calcoffsets(void); - static char *cistrstr(const char *s, const char *sub); - static void drawmenu(void); -+static void fuzzymatch(void); - static void grabkeyboard(void); - static void insert(const char *str, ssize_t n); - static void keypress(XKeyEvent *ev); -@@ -231,7 +233,7 @@ insert(const char *str, ssize_t n) { - if(n > 0) - memcpy(&text[cursor], str, n); - cursor += n; -- match(); -+ fuzzymatch(); - } - - void -@@ -264,7 +266,7 @@ keypress(XKeyEvent *ev) { - - case XK_k: /* delete right */ - text[cursor] = '\0'; -- match(); -+ fuzzymatch(); - break; - case XK_u: /* delete left */ - insert(NULL, 0 - cursor); -@@ -393,7 +395,7 @@ keypress(XKeyEvent *ev) { - strncpy(text, sel->text, sizeof text - 1); - text[sizeof text - 1] = '\0'; - cursor = strlen(text); -- match(); -+ fuzzymatch(); - break; - } - drawmenu(); -@@ -597,7 +599,7 @@ setup(void) { - } - promptw = (prompt && *prompt) ? textw(dc, prompt) : 0; - inputw = MIN(inputw, mw/3); -- match(); -+ fuzzymatch(); - - /* create menu window */ - swa.override_redirect = True; -Index: dmenu-patches/dmenu/fuzzymatch.c -=================================================================== ---- /dev/null -+++ dmenu-patches/dmenu/fuzzymatch.c -@@ -0,0 +1,79 @@ -+int -+compare_distance(const void *a, const void *b) { -+ Item const *da = *(Item **) a; -+ Item const *db = *(Item **) b; -+ if(!db) -+ return 1; -+ if(!da) -+ return -1; -+ return da->distance - db->distance; -+} -+ -+void -+fuzzymatch(void) { -+ /* bang - we have so much memory */ -+ Item *item; -+ Item **fuzzymatches = NULL; -+ char c; -+ int number_of_matches = 0, i, pidx, sidx, eidx; -+ int text_len = strlen(text), itext_len; -+ -+ matches = matchend = NULL; -+ -+ /* suppress compiler warning for unused match function */ -+ if(0) -+ match(); -+ -+ /* walk through all items */ -+ for(item = items; item && item->text; item++) { -+ if(text_len) { -+ itext_len = strlen(item->text); -+ pidx = 0; -+ sidx = eidx = -1; -+ /* walk through item text */ -+ for(i = 0; i < itext_len && (c = item->text[i]); i++) { -+ /* fuzzy match pattern */ -+ if(text[pidx] == c) { -+ if(sidx == -1) -+ sidx = i; -+ pidx++; -+ if(pidx == text_len) { -+ eidx = i; -+ break; -+ } -+ } -+ } -+ /* build list of matches */ -+ if(eidx != -1) { -+ /* compute distance */ -+ /* factor in 30% of sidx and distance between eidx and total -+ * text length .. let's see how it works */ -+ item->distance = eidx - sidx + (itext_len - eidx + sidx) / 3; -+ appenditem(item, &matches, &matchend); -+ number_of_matches++; -+ } -+ } -+ else -+ appenditem(item, &matches, &matchend); -+ } -+ -+ if(number_of_matches) { -+ /* initialize array with matches */ -+ if(!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(Item*)))) -+ eprintf("cannot realloc %u bytes:", number_of_matches * sizeof(Item*)); -+ for(i = 0, item = matches; item && i < number_of_matches; i++, item = item->right) { -+ fuzzymatches[i] = item; -+ } -+ /* sort matches according to distance */ -+ qsort(fuzzymatches, number_of_matches, sizeof(Item*), compare_distance); -+ /* rebuild list of matches */ -+ matches = matchend = NULL; -+ for(i = 0, item = fuzzymatches[i]; i < number_of_matches && item && \ -+ item->text; i++, item = fuzzymatches[i]) { -+ appenditem(item, &matches, &matchend); -+ } -+ free(fuzzymatches); -+ } -+ curr = sel = matches; -+ calcoffsets(); -+} diff --git a/tools.suckless.org/dmenu/patches/dmenu-instant.diff b/tools.suckless.org/dmenu/patches/dmenu-instant.diff @@ -0,0 +1,38 @@ +diff --git a/config.def.h b/config.def.h +index 4e5e3e7..22ef78b 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -4,6 +4,8 @@ + /* Default settings; can be overrided by command line. */ + + static Bool topbar = True; /* -b option; if False, dmenu appears at bottom */ ++static Bool instant = False; /* -n option; if True, dmenu ends immediately */ ++ /* on a distinct match */ + /* -fn option overrides fonts[0]; default X11 font or font set */ + static const char *fonts[] = { + "monospace:size=10" +diff --git a/dmenu.c b/dmenu.c +index f0bc176..a357692 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -93,6 +93,8 @@ main(int argc, char *argv[]) { + fstrncmp = strncasecmp; + fstrstr = cistrstr; + } ++ else if(!strcmp(argv[i], "-n")) /* instant match */ ++ instant = !instant; + else if(i+1 == argc) + usage(); + /* these options take one argument */ +@@ -511,6 +513,11 @@ match(void) { + matchend = substrend; + } + curr = sel = matches; ++ if(instant && matches && matches==matchend && !lsubstr) { ++ puts(matches->text); ++ cleanup(); ++ exit(0); ++ } + calcoffsets(); + } + diff --git a/tools.suckless.org/dmenu/patches/dmenu-line-height.png b/tools.suckless.org/dmenu/patches/dmenu-line-height.png Binary files differ. diff --git a/tools.suckless.org/dmenu/patches/fuzzymatch.md b/tools.suckless.org/dmenu/patches/fuzzymatch.md @@ -1,26 +1,20 @@ -Fuzzy matching support -====================== +fuzzymatch +========== Description ----------- -This patch adds support for fuzzy matching to dmenu. It allows you to type -non-consecutive portions of the string you want to match. - -Usage ------ - -* Apply patch and include `fuzzymatch.c` in `config.h`. - -`#include fuzzymatch.c` +This patch adds support for fuzzy matching to dmenu, allowing users to type +non-consecutive portions of the string to be matched. Download -------- -* [dmenu git](dmenu-git-fuzzymatch.diff) applies cleanly against 13a529ce63364544bdc851dfd5d3aa2ef8740914 -* [dmenu 4.5](dmenu-4.5-fuzzymatch.diff) +* [dmenu-4.5-fuzzymatch.diff](dmenu-4.5-fuzzymatch.diff) +* [dmenu-git-20151020-fuzzymatch.diff](dmenu-git-20151020-fuzzymatch.diff) -History +Authors ------ -Created by [Jan Christoph Ebersbach](https://github.com/jceb/dmenu-patches). +* Jan Christoph Ebersbach - jceb@e-jc.de +* Laslo Hunhold - dev@frign.de (dmenu-4.5, dmenu-git-20151020 ports) diff --git a/tools.suckless.org/dmenu/patches/hide-single-newline.md b/tools.suckless.org/dmenu/patches/hide-single-newline.md @@ -0,0 +1,19 @@ +Hide single newline +=================== + +Description +----------- + +When you pass the single newline (for example, using `echo | dmenu`) dmenu displays one empty menu item. You can see this effect in surf with "go to url" and "find in page" menus. This patch hides this sad, lonely item. + +Download +-------- + +* [dmenu-4.5-hide-single-newline.diff](dmenu-4.5-hide-single-newline.diff) (0.1k) (18 Sep 2015) +* [dmenu-git-20160111-hide-single-newline.diff](dmenu-git-20160111-hide-single-newline.diff) + +Authors +------- + +* Danil Semelenov - `<mail at danil dot mobi>` +* Klemens Nanni <[kl3@posteo.org](mailto:kl3@posteo.org)> (20160111 version) diff --git a/tools.suckless.org/dmenu/patches/history.md b/tools.suckless.org/dmenu/patches/history.md @@ -22,3 +22,11 @@ Author ------ * Peter John Hartman (wart_) <[http://antiopus.trilidun.org/durandus/](http://antiopus.trilidun.org/durandus/)> + +Note +---- + +As an alternative to the patch above, the following script is meant to replace +`dmenu_run` : it handles the command history in a similar way as the patch and +can be used with an unpatched dmenu 4.6. +[dmenu_run_history](http://tools.suckless.org/dmenu/scripts/dmenu_run_with_command_history) diff --git a/tools.suckless.org/dmenu/patches/instant.md b/tools.suckless.org/dmenu/patches/instant.md @@ -0,0 +1,12 @@ +Instant Mode +============ + +Adds an flag which will cause dmenu to select an item immediately if theres one matching option left. + +Download +-------- +* [dmenu-instant.diff](dmenu-instant.diff) + +Author +------ +* Michael Stummvoll (stummi)<suckless@stummi.org> diff --git a/tools.suckless.org/dmenu/patches/line-height.md b/tools.suckless.org/dmenu/patches/line-height.md @@ -0,0 +1,36 @@ +Line height +=========== + +The patch adds a '-lh' option, which sets the minimum height of a dmenu line. +This helps integrate dmenu with other UI elements that require a particular +vertical size. + +Example: + +By default, dmenu calculates its height as the height of the font used plus 2. +So when opening dmenu over a panel bar that is 24 pixels high, it would look +like this: + +->[![Screenshot dmenu default height](dmenu-default-height.png)](dmenu-default-height.png)<- + +Despite both the panel and dmenu using the same font (a Terminus 12), dmenu is +shorter and the panel is visible from under the dmenu bar. The appearance can +be even more distracting when using similar colors for background and +selections. + +With the option added by this patch, dmenu can be launched with a '-lh 24', +thus completely covering the panel, as shown below: + +->[![Screenshot dmenu with line height patch](dmenu-line-height.png)](dmenu-line-height.png)<- + +The line height value is also used when dmenu is used in 'vertical' mode ('-l' option). + +The patch applies cleanly against 4.6 (32f2564dbbbf5aeafb7190a3d35066142f34448f). + +Download +-------- +* [dmenu-4.6-line-height.diff](dmenu-4.6-line-height.diff) + +Author +------ +* Xarchus diff --git a/tools.suckless.org/dmenu/patches/mouse-support-msel.md b/tools.suckless.org/dmenu/patches/mouse-support-msel.md @@ -0,0 +1,19 @@ +Mouse support with multisel +=========================== + +This provides the basic mouse support described in the 'mouse support' patch, +but against 4.6 (32f2564dbbbf5aeafb7190a3d35066142f34448f). + +In addition, multisel is supported via Ctrl-leftclick. +(i.e. Ctrl-leftclick does for mouse operation what Ctrl-Return does for +keyboard, as described in the 'multisel' patch; however, the 'multisel' patch +itself is no longer needed in 4.6 because its functionality has been previously +merged in and now it's part of the master) + +Download +-------- +* [dmenu-4.6-mouse-support-msel.diff](dmenu-4.6-mouse-support-msel.diff) + +Author +------ +* Xarchus diff --git a/tools.suckless.org/dmenu/patches/vertfull.md b/tools.suckless.org/dmenu/patches/vertfull.md @@ -0,0 +1,11 @@ +Vertical full width +=================== +Prevents dmenu from indenting items at the same level as the prompt length. + +Download +-------- +* [dmenu-4.6-vertfull.diff](dmenu-4.6-vertfull.diff) + +Author +------ +* Claudio Alessi - <smoppy@gmail.com> diff --git a/tools.suckless.org/dmenu/patches/xft.md b/tools.suckless.org/dmenu/patches/xft.md @@ -20,6 +20,7 @@ Download * [dmenu git](dmenu-git-xft.diff) applies cleanly against 13a529ce63364544bdc851dfd5d3aa2ef8740914 * [dmenu 4.5](dmenu-4.5-xft.diff) * [dmenu 4.5 for debian](dmenu-4.5-xft-debian.diff) +* [dmenu 4.5 (improved)](dmenu-4.5-xft-improved.diff) * [dmenu 4.4.1](dmenu-4.4.1-xft.diff) History diff --git a/tools.suckless.org/dmenu/patches/xmms-like_pattern_matching.md b/tools.suckless.org/dmenu/patches/xmms-like_pattern_matching.md @@ -30,5 +30,5 @@ Download xmms (legacy) * [dmenu-4.1.1-xmms.diff](dmenu-4.1.1-xmms.diff) -* [dmenu_xmms.diff](dmenu_xmms.diff) (for **dmenu_3.9** - the original patch submitted by Julien Steinhauser <[julien.steinhauser@orange.fr](mailto:julien.steinhauser@orange.fr)>, taken from [https://bbs.archlinux.org/viewtopic.php?pid=429090#p429090](fresch's patch)) +* [dmenu_xmms.diff](dmenu_xmms.diff) (for **dmenu_3.9** - the original patch submitted by Julien Steinhauser <[julien.steinhauser@orange.fr](mailto:julien.steinhauser@orange.fr)>, taken from [fresch's patch](https://bbs.archlinux.org/viewtopic.php?pid=429090#p429090)) diff --git a/tools.suckless.org/dmenu/patches/xyw.md b/tools.suckless.org/dmenu/patches/xyw.md @@ -0,0 +1,19 @@ +Position and width +================== + +The patch adds options for setting window position and width. + +* The '-x' and '-y' options set the window position on the target monitor (0 if one is not supplied with '-m') +* If option '-b' is used, the y offset is computed from the bottom +* The '-x' and '-y' accept negative values +* The '-w' option sets the window width + +Download +-------- +* [dmenu-4.6-xyw.diff](dmenu-4.6-xyw.diff) + +Author +------ +* Xarchus + + diff --git a/tools.suckless.org/dmenu/scripts/dmenu_run_with_command_history/dmenu_run_history b/tools.suckless.org/dmenu/scripts/dmenu_run_with_command_history/dmenu_run_history @@ -0,0 +1,50 @@ +#!/bin/sh + +cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"} +if [ -d "$cachedir" ]; then + cache=$cachedir/dmenu_run + historyfile=$cachedir/dmenu_history +else # if no xdg dir, fall back to dotfiles in ~ + cache=$HOME/.dmenu_cache + historyfile=$HOME/.dmenu_history +fi + +IFS=: +if stest -dqr -n "$cache" $PATH; then + stest -flx $PATH | sort -u > "$cache" +fi +unset IFS + +awk -v histfile=$historyfile ' + BEGIN { + while( (getline < histfile) > 0 ) { + sub("^[0-9]+\t","") + print + x[$0]=1 + } + } !x[$0]++ ' "$cache" \ + | dmenu "$@" \ + | awk -v histfile=$historyfile ' + BEGIN { + FS=OFS="\t" + while ( (getline < histfile) > 0 ) { + count=$1 + sub("^[0-9]+\t","") + fname=$0 + history[fname]=count + } + close(histfile) + } + + { + history[$0]++ + print + } + + END { + if(!NR) exit + for (f in history) + print history[f],f | "sort -t '\t' -k1rn >" histfile + } + ' \ + | while read cmd; do ${SHELL:-"/bin/sh"} -c "$cmd" & done diff --git a/tools.suckless.org/dmenu/scripts/dmenu_run_with_command_history/index.md b/tools.suckless.org/dmenu/scripts/dmenu_run_with_command_history/index.md @@ -0,0 +1,23 @@ +dmenu_run with command history +============================== + +A self-contained alternative to dmenu_run which also handles history. + +History is saved in a file in `$XDG_CACHE_HOME`, with fallback to a dot +file in `$HOME`. Change as necessary. + +In addition to the above, dmenu_run_history will launch each entry +immediately on `Ctrl-Return` (multiselect). + +The script can be used with the 4.6 version of dmenu. + +Download +======== + +[dmenu_run_history](dmenu_run_history) (20151217) + +Authors +======= + +* Xarchus +* Silvan Jegen (initial idea, code contributor, feedback) diff --git a/tools.suckless.org/dmenu/scripts/index.md b/tools.suckless.org/dmenu/scripts/index.md @@ -6,8 +6,10 @@ dmenu's user, feel free to add your own scripts, or comment existents. Download -------- +* [clipmenu](https://github.com/cdown/clipmenu): Clipboard management using dmenu * [passmenu](http://git.zx2c4.com/password-store/tree/contrib/dmenu) : get password from pass. +* [passmenu2](passmenu2): "pass" browser, vertical display and recursive "pass" folder support * [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) @@ -18,3 +20,7 @@ Download [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. +* [browse](https://github.com/clamiax/scripts/blob/master/src/browse): + little files navigator +* [dmenu_run_history](http://tools.suckless.org/dmenu/scripts/dmenu_run_with_command_history) : + dmenu_run alternative with command history diff --git a/tools.suckless.org/dmenu/scripts/passmenu2 b/tools.suckless.org/dmenu/scripts/passmenu2 @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +shopt -s nullglob globstar + +typeit=0 +if [[ $1 == "--type" ]]; then + typeit=1 + shift +fi + + +STARTDIR=${PASSWORD_STORE_DIR-~/.password-store} +BASEDIR=$STARTDIR +DONE=0 +LEVEL=0 +PREVSELECTION="" +SELECTION="" + +while [ "$DONE" -eq 0 ] ; do + password_files=( "$STARTDIR"/* ) + password_files=( "${password_files[@]#"$STARTDIR"/}" ) + password_files=( "${password_files[@]%.gpg}" ) + + if [ "$LEVEL" -ne 0 ] ; then + password_files=(".." "${password_files[@]}") + fi + entry=$(printf '%s\n' "${password_files[@]}" | dmenu "$@" -fn "-*-terminus-*-*-*-24-*-*-*-*-*-*-*" -nb "#00ff00" -nf "#000000" -l 15) + + echo "entry: $entry" + if [ -z $entry ] ; then + DONE=1 + exit + fi + + if [ "$entry" != ".." ] ; then + PREVSELECTION=$SELECTION + SELECTION="$SELECTION/$entry" + + # check if another dir + if [ -d "$STARTDIR/$entry" ] ; then + STARTDIR="$STARTDIR/$entry" + LEVEL=$((LEVEL+1)) + else + # not a directory so it must be a real password entry + + if [[ $typeit -eq 0 ]]; then + pass show -c "$SELECTION" 2>/dev/null + else + xdotool - <<<"type --clearmodifiers -- $(pass show "$SELECTION" | head -n 1)" + fi + DONE=1 + fi + + else + LEVEL=$((LEVEL-1)) + SELECTION=$PREVSELECTION + STARTDIR="$BASEDIR/$SELECTION" + fi +done + diff --git a/tools.suckless.org/farbfeld/farbfeld.svg b/tools.suckless.org/farbfeld/farbfeld.svg @@ -0,0 +1,5 @@ +<?xml version="1.0"?> +<!-- Copyright (c) 2016, Laslo Hunhold <dev@frign.de> --> +<svg xmlns="http://www.w3.org/2000/svg" width="178" height="40"> +<path d="m 0,0 0,40 5.7143,0 0,-17.14287 5.71428,0 0,-5.71429 -5.71428,0 0,-11.42858 11.42858,0 0,-5.71429 -17.14288,0 z m 22.85716,0 0,40 5.71429,0 0,-17.14287 5.7143,0 0,17.14287 5.71428,0 0,-40 -17.14287,0 z m 22.85716,0 0,40 5.7143,0 0,-17.14287 5.71429,0 0,-5.71429 -5.71429,0 0,-11.42858 5.71429,0 0,-5.71429 -11.42859,0 z m 11.42859,5.71429 0,11.42858 5.71428,0 0,-11.42858 -5.71428,0 z m 0,17.14287 0,17.14287 5.71428,0 0,-17.14287 -5.71428,0 z m 11.42857,-22.85716 0,40 11.42859,0 0,-5.7143 -5.71428,0 0,-11.42857 5.71428,0 0,-5.71429 -5.71428,0 0,-11.42858 5.71428,0 0,-5.71429 -11.42859,0 z m 11.42859,5.71429 0,11.42858 5.71429,0 0,-11.42858 -5.71429,0 z m 0,17.14287 0,11.42857 5.71429,0 0,-11.42857 -5.71429,0 z m 11.42859,-22.85716 0,40 5.71429,0 0,-17.14287 5.71428,0 0,-5.71429 -5.71428,0 0,-11.42858 11.42858,0 0,-5.71429 -17.14287,0 z m 22.85715,0 0,40 17.14287,0 0,-5.7143 -11.42858,0 0,-11.42857 5.7143,0 0,-5.71429 -5.7143,0 0,-11.42858 11.42858,0 0,-5.71429 -17.14287,0 z m 22.85717,0 0,40 17.14287,0 0,-5.7143 -11.42859,0 0,-34.28573 -5.71428,0 z m 22.85715,0 0,40 11.42859,0 0,-5.7143 -5.7143,0 0,-28.57144 5.7143,0 0,-5.71429 -11.42859,0 z m 11.42859,5.71429 0,28.57144 5.71428,0 0,-28.57144 -5.71428,0 z m -142.85727,0 5.7143,0 0,11.42858 -5.7143,0 0,-11.42858 z" style="fill:#222" /> +</svg> diff --git a/tools.suckless.org/farbfeld/index.md b/tools.suckless.org/farbfeld/index.md @@ -0,0 +1,186 @@ +![farbfeld](farbfeld.svg) + +farbfeld is a lossless image format which is easy to parse, pipe and +compress. +It has the following format: + +| Bytes | Description | +|--------|---------------------------------------------------------| +| 8 | "farbfeld" magic value | +| 4 | 32-Bit BE unsigned integer (width) | +| 4 | 32-Bit BE unsigned integer (height) | +| [2222] | 4â‹…16-Bit BE unsigned integers [RGBA] / pixel, row-major | + +The RGB-data should be sRGB for best interoperability and not +alpha-premultiplied. + +Examples +-------- + +Convert image.png to a farbfeld, run it through a filter and write the +result to image-filtered.png: + + $ png2ff < image.png | filter | ff2png > image-filtered.png + +[invert.c](invert.c) is an example for such a filter which inverts +the colors. Notice that there are no dependencies on external libraries. +A hypothetical farbfeld-library would hardly exceed invert.c's size. + + +Store a png as a compressed farbfeld: + + $ png2ff < image.png | bzip2 > image.ff.bz2 + +Access a compressed farbfeld as a png: + + $ bunzip2 < image.ff.bz2 | ff2png {> image.png, | feh -, ...} + +Handle arbitrary image data using 2ff(1), which falls +back to imagemagick's convert(1) for unknown image types: + + $ 2ff < image | filter | ff2png > image-filtered.png + +Refer to the manpages for more information. farbfeld(5) is a good start. + +FAQ +--- + +### Why yet another image format? + +Current image formats have integrated compression, +making it complicated to read the image data. +One is forced to use complex libraries like libpng, +libjpeg, libjpeg-turbo, giflib and others, read the +documentation and write a lot of boilerplate in order +to get started. + +Farbfeld leaves this behind and is designed to be as +simple as possible, leaving the task of compression +to external tools. +The simple design, which was the primary objective, +implicitly leads to the very good compression +characteristics, as it often happens when you go with +the UNIX philosophy. +Reading farbfeld images doesn't require any special +libraries. The tools are just a toolbox +to make it easy to convert between common image formats +and farbfeld. + +### How does it work? + +In Farbfeld, pattern resolution is not done while +converting, but while compressing the image. +For example, farbfeld always stores the alpha-channel, +even if the image doesn't have alpha-variation. +This may sound like a big waste at first, but as +soon as you compress an image of this kind, the +compression-algorithm (e.g. bz2) recognizes the +pattern that every 48 bits the 16 bits store the +same information. +And the compression-algorithms get better and better +at this. + +Same applies to the idea of having 16 bits per channel. +It sounds excessive, but if you for instance only have +a greyscale image, the R, G and B channels will store +the same value, which is recognized by the compression +algorithm easily. + +This effectively leads to filesizes you'd normally only +reach with paletted images, and in some cases bz2 even +beats png's compression, for instance when you're dealing +with grayscale data, line drawings, decals and even +photographs. + +### Why use 16-Bits-per-channel all the time? Isn't this a total waste? + +Not when you take compression into account. To make this +clearer, assume a paletted image with 5 colors and no +transparency. So the data is only a set of regular chunks +(color1, ..., color5) in a certain order. +Compression algorithms have been designed to recognize those +chunks and can even look at how these chunks interact. + +Local tests have shown that farbfeld easily beats paletted +PNG-images. Try for yourself and look at the bzipped results! +There is no need for special grayscale, palette, RGB, 1-, 2-, +4-, 8-, 16-Bit subformats. +Just use 16-Bit RGBA all the time and let compression take +care of the rest. + +### Which compression should I use? + +bzip2 is recommended, which is widely available (anybody has it) +and gives good results. As time will move forward and new +algorithms hit the market, this recommendation might be rethought. + +### What about NetPBM? + +NetPBM is considered to be the most simple format around, +however, there's much room for improvement. +In fact, it doesn't help that the format is subdivided into +Portable BitMaps, Portable GrayMaps and Portable PixMaps. +It's not helpful when a manpage can't give a simple overview +of a format in a few sentences. + +NetPBM's big vice is that it has originally been developed +to be hand-written and passed around as plain text. A binary +format exists, but still handling optional comments +in the header, base 10 ASCII width and height values, +arbitrary whitespace inside the data and out-of-band +image size and color depth is too painful for the sane user. + +Judging from the usage of the format considering how long +it's been around, it's no surprise it never really took off. +Additionally, functionality like alpha channels and 16-Bit +color depth can only be achieved via extensions. +Due to it being a textual format it also lacks the desired +compression characteristics. + +The question you have to ask yourself is: Can I read in a +format without consulting the manpages? If your answer is +yes, then the format is simple enough. +In this regard, NetPBM can be considered to be a failed format. + +Dependencies +------------ + +* [libpng](http://www.libpng.org/pub/png/libpng.html) - for png conversions +* [libjpeg-turbo](http://libjpeg-turbo.virtualgl.org/) - for jpg conversions + +Development +----------- + +You can [browse](http://git.suckless.org/farbfeld) its source code repository +or get a copy using the following command: + + git clone http://git.suckless.org/farbfeld + +Download +-------- + +* [farbfeld-1](http://dl.suckless.org/farbfeld/farbfeld-1.tar.gz) (2016-01-06) + +Also make sure to check your package manager. The following distributions +provide packages: + +* Gentoo (Portage) +* Arch Linux (AUR) +* Void Linux + +Implementations +--------------- + +* [lel](http://git.2f30.org/lel) farbfeld image viewer +* [sent](http://tools.suckless.org/sent/) presentation tool +* [Go encoder/decoder](https://github.com/hullerob/go.farbfeld) +* [resize](https://github.com/ender672/farbfeld-resize) image filter +* [gamut](https://github.com/erik/gamut) image filter collection + +Author +------ + +* Laslo Hunhold (dev@frign.de) + +Please contact me when you find information that could be added to this +page. diff --git a/tools.suckless.org/farbfeld/invert.c b/tools.suckless.org/farbfeld/invert.c @@ -0,0 +1,68 @@ +/* + * Copy me if you can. + * by FRIGN + */ +#include <arpa/inet.h> + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int +main(int argc, char *argv[]) +{ + uint32_t width, height, i, j, k; + uint16_t rgba[4]; + uint8_t hdr[strlen("farbfeld") + 2 * sizeof(uint32_t)]; + + if (argc > 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + return 1; + } + + if (fread(hdr, 1, sizeof(hdr), stdin) != sizeof(hdr)) { + fprintf(stderr, "incomplete header\n"); + return 1; + } + if (memcmp("farbfeld", hdr, strlen("farbfeld"))) { + fprintf(stderr, "invalid magic\n"); + return 1; + } + width = ntohl(*((uint32_t *)(hdr + 8))); + height = ntohl(*((uint32_t *)(hdr + 12))); + + if (fwrite(hdr, 1, sizeof(hdr), stdout) != sizeof(hdr)) { + fprintf(stderr, "write error\n"); + return 1; + } + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + if (fread(rgba, sizeof(uint16_t), 4, + stdin) != 4) { + fprintf(stderr, "unexpected EOF\n"); + return 1; + } + for (k = 0; k < 4; k++) { + rgba[k] = ntohs(rgba[k]); + } + + /* invert colors */ + rgba[0] = 65535 - rgba[0]; + rgba[1] = 65535 - rgba[1]; + rgba[2] = 65535 - rgba[2]; + + for (k = 0; k < 4; k++) { + rgba[k] = htons(rgba[k]); + } + if (fwrite(rgba, sizeof(uint16_t), 4, + stdout) != 4) { + fprintf(stderr, "write error\n"); + return 1; + } + } + } + + return 0; +} diff --git a/tools.suckless.org/lsx.md b/tools.suckless.org/lsx.md @@ -1,11 +0,0 @@ -lsx -=== -List executables in a directory tree. It just does this, nothing else. - -Download --------- -* [lsx-0.1](http://dl.suckless.org/tools/lsx-0.1.tar.gz) (20061013) - -Bugs ----- -No support for to detect symlink loops. diff --git a/tools.suckless.org/sent/index.md b/tools.suckless.org/sent/index.md @@ -0,0 +1,101 @@ +sent +==== + +Simple plaintext presentation tool. + +->[![Screenshot of sent](sent-bullets-s.png)](sent-bullets.png)<- + +sent does not need latex, libreoffice or any other fancy file format, it uses +plaintext files to describe the slides and can include images via +[farbfeld](http://git.2f30.org/farbfeld/about/). Every paragraph represents a +slide in the presentation. Especially for presentations using the [Takahashi +method](https://en.wikipedia.org/wiki/Takahashi_method) this is very nice and +allows you to write down the presentation for a quick lightning talk within a +few minutes. + +The presentation is displayed in a simple X11 window colored black on white for +maximum contrast even if the sun shines directly onto the projected image. The +content of each slide is automatically scaled to fit the window so you don't +have to worry about alignment. Instead you can really concentrate on the +content. + +Dependencies +------------ + +* Xlib for building +* farbfeld tools to use images in the presentations (if you don't want to use + farbfeld, [sent-0.2](http://dl.suckless.org/tools/sent-0.2.tar.gz) was the + last version with png support, but may lack fixes and further improvements + since its release) + +Demo +---- + +To get a little demo, just type + + make && ./sent example + +You can navigate with the arrow keys and quit with `q`. + +(Non-)Features +-------------- + +* A presentation is just a simple text file +* Each paragraph represents one slide +* Content is automatically scaled to fit the screen +* UTF-8 is supported +* Images can be displayed (no text on the same slide), farbfeld required +* Just around 1000 lines of C. +* No different font styles (bold, italic, underline) +* No fancy layout options (different font sizes, different colors, …) +* No animations +* No support for automatic layouting paragraphs +* No export function. If you really need one, just use a shell script with + `xdotool` and your favorite screenshot application. +* Slides with exuberant amount of lines or characters produce rendering glitches + intentionally to prevent you from holding bad presentations + +Usage +----- + +Edit config.h to fit your needs then build again. + + sent FILE + +If FILE equals `-`, stdin will be read. Produce image slides by prepending a +`@` in front of the filename as a single paragraph. Lines starting with `#` will +be ignored. A `\` at the beginning of the line escapes `@` and `#`. A +presentation file could look like this: + + sent + + @nyan.png + + depends on + - Xlib + - farbfeld + + sent FILENAME + one slide per paragraph + # This is a comment and will not be part of the presentation + \# This and the next line start with backslashes + + \@FILE.png + + thanks / questions? + +A deeper example can be found in [this +file](http://git.suckless.org/sent/tree/example) from the repository root. + +Development +----------- + +You can [browse](http://git.suckless.org/sent) its source code repository +or get a copy using the following command: + + git clone http://git.suckless.org/sent + +Download +-------- + +* [sent-0.2](http://dl.suckless.org/tools/sent-0.2.tar.gz) (20151125) diff --git a/tools.suckless.org/sent/patches/index.md b/tools.suckless.org/sent/patches/index.md @@ -0,0 +1,29 @@ +Patches +======= + +diff generation +--------------- +For git users: + + cd sent-directory + git diff > sent-X.Y-yourpatchname.diff + +For tarballs: + + cd modified-sent-directory/.. + diff -up original-sent-directory modified-sent-directory > sent-X.Y-yourpatchname.diff + +where `X.Y` is a sent tag name or version number. + + +patch application +----------------- +For git users: + + cd sent-directory + git apply path/to/patch.diff + +For tarballs: + + cd sent-directory + patch -p1 < path/to/patch.diff diff --git a/tools.suckless.org/sent/patches/toggle-mouse-cursor.diff b/tools.suckless.org/sent/patches/toggle-mouse-cursor.diff @@ -0,0 +1,61 @@ +diff --git a/config.def.h b/config.def.h +index 6ecc267..96acbe1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -39,4 +39,5 @@ static Shortcut shortcuts[] = { + { XK_Up, advance, {.i = -1} }, + { XK_Next, advance, {.i = +1} }, + { XK_Prior, advance, {.i = -1} }, ++ { XK_x, toggle_cursor, {0} }, + }; +diff --git a/sent.c b/sent.c +index 4e2e810..a14c49b 100644 +--- a/sent.c ++++ b/sent.c +@@ -13,6 +13,7 @@ + #include <X11/Xlib.h> + #include <X11/Xutil.h> + #include <X11/Xft/Xft.h> ++#include <X11/cursorfont.h> + + #include "arg.h" + #include "drw.h" +@@ -92,6 +93,7 @@ static void eprintf(const char *, ...); + static void die(const char *, ...); + static void load(FILE *fp); + static void advance(const Arg *arg); ++static void toggle_cursor(const Arg *arg); + static void quit(const Arg *arg); + static void resize(int width, int height); + static void run(); +@@ -476,6 +478,30 @@ void advance(const Arg *arg) + } + } + ++void toggle_cursor(const Arg *arg) ++{ ++ Cursor cursor; ++ XColor color; ++ Pixmap bitmapNoData; ++ char noData[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; ++ static int cursor_visible = 1; ++ ++ memset(&color, 0, sizeof(color)); ++ ++ ++ if (cursor_visible) { ++ bitmapNoData = XCreateBitmapFromData(xw.dpy, xw.win, noData, 8, 8); ++ cursor = XCreatePixmapCursor(xw.dpy, bitmapNoData, ++ bitmapNoData, &color, &color, 0, 0); ++ XFreePixmap(xw.dpy, bitmapNoData); ++ } else { ++ cursor = XCreateFontCursor(xw.dpy, XC_left_ptr); ++ } ++ XDefineCursor(xw.dpy, xw.win, cursor); ++ XFreeCursor(xw.dpy, cursor); ++ cursor_visible ^= 1; ++} ++ + void quit(const Arg *arg) + { + running = 0; diff --git a/tools.suckless.org/sent/patches/toggle_cursor.md b/tools.suckless.org/sent/patches/toggle_cursor.md @@ -0,0 +1,18 @@ +Toggle Mouse Cursor +=================== + +Description +----------- + +The patch introduces a shortcut that toggles the mouse cursor. +Enjoy! + +Download +-------- + +* [toggle-mouse-cursor.diff](toggle-mouse-cursor.diff) (1623) (20151117) + +Author +------ + +* Alex Kozadaev (snobb) diff --git a/tools.suckless.org/sent/sent-bullets-s.png b/tools.suckless.org/sent/sent-bullets-s.png Binary files differ. diff --git a/tools.suckless.org/sent/sent-bullets.png b/tools.suckless.org/sent/sent-bullets.png Binary files differ. diff --git a/tools.suckless.org/sic/patches/lineprint.md b/tools.suckless.org/sic/patches/lineprint.md @@ -0,0 +1,24 @@ +Print the current inserting line +================================ +This patch allow to store and reprint the current inserting line. This is done +by appending a suffix character to the input. The line is (obviously) not sent. + +In a nutshell: + + :ni\ + :nick baz\ + :nick bazqux + clamiax : 2015-10-09 18:15 >< NICK (): bazqux + +This is useful, for example, when receiving data from the server in the middle +of a sentence you're writing. + +Note: the patch also changes the config.def.h file. + +Download +-------- +* [sic-1.3-lineprint.diff](sic-1.3-lineprint.diff) (1,3K) (20151009) + +Author +------ +* Claudio Alessi <[smoppy@gmail.com](mailto:smoppy@gmail.com)> diff --git a/tools.suckless.org/sic/patches/sic-1.3-lineprint.diff b/tools.suckless.org/sic/patches/sic-1.3-lineprint.diff @@ -0,0 +1,53 @@ +diff --git a/config.def.h b/config.def.h +index 6d720e9..a1308e6 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -12,3 +12,6 @@ + + /* Parting message used when none is specified with ":l ..." command. */ + #define DEFAULT_PARTING_MESSAGE "sic - 250 LOC are too much!" ++ ++/* Suffix character used to print the current inserting command */ ++#define LINEPRINT_SUFFIX_CHAR '\\' +diff --git a/sic.c b/sic.c +index 8a0301b..6401414 100644 +--- a/sic.c ++++ b/sic.c +@@ -18,6 +18,7 @@ static char *password; + static char nick[32]; + static char bufin[4096]; + static char bufout[4096]; ++static char bufln[4096]; + static char channel[256]; + static time_t trespond; + static FILE *srv; +@@ -60,11 +61,29 @@ privmsg(char *channel, char *msg) { + + static void + parsein(char *s) { ++ int i, off; + char c, *p; + + if(s[0] == '\0') + return; + skip(s, '\n'); ++ ++ /* input reprint */ ++ i = strlen(s) - 1; ++ off = (*bufln ? strlen(bufln) : 0); ++ if(s[i] == LINEPRINT_SUFFIX_CHAR) { ++ s[i] = '\0'; ++ if(i) ++ snprintf(&bufln[off], (sizeof bufln - off), "%s", s); ++ printf("%s", bufln); ++ return; ++ } ++ else if(*bufln) { ++ snprintf(&bufln[off], sizeof bufln, "%s", s); ++ strlcpy(s, bufln, 4096); ++ *bufln = '\0'; ++ } ++ + if(s[0] != COMMAND_PREFIX_CHARACTER) { + privmsg(channel, s); + return; diff --git a/tools.suckless.org/sic/patches/sic.1 b/tools.suckless.org/sic/patches/sic.1 @@ -1,57 +0,0 @@ -.TH SIC 1 sic-VERSION -.SH NAME -sic \- simple irc client -.SH SYNOPSIS -.B sic -.RB [ \-h -.IR host ] -.RB [ \-p -.IR port ] -.RB [ \-n -.IR nick ] -.RB [ \-k -.IR pass ] -.RB [ \-v ] -.SH DESCRIPTION -.B sic -is an extremely fast, small and simple irc client. It reads commands from -standard input and prints all server output to standard output. It also -multiplexes all channel traffic into one output. That way you don't have to -switch different channel buffers. So that's actually a feature. -.SH OPTIONS -.TP -.BI \-h " host" -Overrides the default host (irc.oftc.net) -.TP -.BI \-p " port" -Overrides the default port (6667) -.TP -.BI \-n " nick" -Override the default nick ($USER) -.TP -.BI \-k " pass" -Specifies the PASS connection password -.TP -.B \-v -Prints version information to stderr, then exits -.SH COMMANDS -.TP -.BI :h " commands" -Will hide any specified commands (JOIN/PART/etc.) -.TP -.BI :j " #channel" -Join a channel -.TP -.BI :l " #channel" -Leave a channel -.TP -.BI :m " #channel/user message" -Send a message to channel or user -.TP -.BI :s " #channel/user" -Set default channel or user -.TP -.BI : command -Any line beginning with -.B : -is sent as a command diff --git a/tools.suckless.org/slock/index.md b/tools.suckless.org/slock/index.md @@ -14,7 +14,7 @@ or get a copy using the following command: Download -------- -* [slock-1.2](http://dl.suckless.org/tools/slock-1.2.tar.gz) (20141222) +* [slock-1.3](http://dl.suckless.org/tools/slock-1.3.tar.gz) (20160212) Xautolock --------- diff --git a/tools.suckless.org/slock/patches/capscolor.md b/tools.suckless.org/slock/patches/capscolor.md @@ -8,12 +8,16 @@ Introduces an additional color to indicate the state of Caps Lock. Not compatible with the [failcolor](./failcolor) patch. Written against HEAD at a31b919, but should apply to 1.2. +Version 20160130 is written against current HEAD at 9dfe0ce. + Download -------- * [slock-capscolor.diff](slock-capscolor.diff) +* [slock-20160130-capscolor.diff](slock-20160130-capscolor.diff) -Author ------- +Authors +------- * Andrew Hills <[ahills@ednos.net](mailto:ahills@ednos.net)> +* Klemens Nanni <[kl3@posteo.org](mailto:kl3@posteo.org)> (20160130 version) diff --git a/tools.suckless.org/slock/patches/slock-20160130-capscolor.diff b/tools.suckless.org/slock/patches/slock-20160130-capscolor.diff @@ -0,0 +1,72 @@ +diff --git a/config.def.h b/config.def.h +index fca0ae0..6673e54 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -2,5 +2,6 @@ static const char *colorname[NUMCOLS] = { + "black", /* after initialization */ + "#005577", /* during input */ + "#CC3333", /* failed/cleared the input */ ++ "red", /* CapsLock on */ + }; + static const Bool failonclear = True; +diff --git a/slock.c b/slock.c +index df2d3c6..8c1a791 100644 +--- a/slock.c ++++ b/slock.c +@@ -17,6 +17,7 @@ + #include <X11/keysym.h> + #include <X11/Xlib.h> + #include <X11/Xutil.h> ++#include <X11/XKBlib.h> + + #if HAVE_BSD_AUTH + #include <login_cap.h> +@@ -27,6 +28,7 @@ enum { + INIT, + INPUT, + FAILED, ++ CAPS, + NUMCOLS + }; + +@@ -127,15 +129,19 @@ readpw(Display *dpy, const char *pws) + #endif + { + char buf[32], passwd[256]; +- int num, screen; +- unsigned int len, color; ++ int num, screen, caps; ++ unsigned int len, color, indicators; + KeySym ksym; + XEvent ev; + static int oldc = INIT; + + len = 0; ++ caps = 0; + running = True; + ++ if (!XkbGetIndicatorState(dpy, XkbUseCoreKbd, &indicators)) ++ caps = indicators & 1; ++ + /* As "slock" stands for "Simple X display locker", the DPMS settings + * had been removed and you can set it with "xset" or some other + * utility. This way the user can easily set a customized DPMS +@@ -177,6 +183,9 @@ readpw(Display *dpy, const char *pws) + if (len) + --len; + break; ++ case XK_Caps_Lock: ++ caps = !caps; ++ break; + default: + if (num && !iscntrl((int)buf[0]) && (len + num < sizeof(passwd))) { + memcpy(passwd + len, buf, num); +@@ -184,7 +193,7 @@ readpw(Display *dpy, const char *pws) + } + break; + } +- color = len ? INPUT : (failure || failonclear ? FAILED : INIT); ++ color = len ? (caps ? CAPS : INPUT) : (failure || failonclear ? FAILED : INIT); + if (running && oldc != color) { + for (screen = 0; screen < nscreens; screen++) { + XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[color]); diff --git a/tools.suckless.org/ssid.md b/tools.suckless.org/ssid.md @@ -1,7 +0,0 @@ -ssid -==== -Simple setsid replacement, nothing special about it except it being really simple. - -Download --------- -* [ssid-0.1](http://dl.suckless.org/tools/ssid-0.1.tar.gz) (20061013) diff --git a/tools.suckless.org/tabbed/patches/clientnumber.md b/tools.suckless.org/tabbed/patches/clientnumber.md @@ -1,12 +1,13 @@ Client number -======== +============= With this patch, tabbed prints the position number of the client before the window title. Download -------- -* [tabbed-0.6-clientnumber.diff](tabbed-0.6-clientnumber.diff) +* [tabbed-clientnumber-20160103-eb0ff62.patch](tabbed-clientnumber-20160103-eb0ff62.patch) + (works with 0.6). Author ------ -* Quentin Rameau <quinq@quinq.eu.org> +* Quentin Rameau <quinq@fifth.space> diff --git a/tools.suckless.org/tabbed/patches/keycode.md b/tools.suckless.org/tabbed/patches/keycode.md @@ -1,12 +1,13 @@ Keycode -======== +======= With this patch, handling key input is done with keycodes instead of keysyms. -This way, input is keyboard layout independant (adapt config.h to your keyboard using for exemple xev). +This way, input is keyboard layout independant (adapt config.h to your keyboard using for example xev). Download -------- * [tabbed-0.6-keycode.diff](tabbed-0.6-keycode.diff) +* [tabbed-keycode-20160103-eb0ff62.patch](tabbed-keycode-20160103-eb0ff62.patch) Author ------ -* Quentin Rameau <quinq@quinq.eu.org> +* Quentin Rameau <quinq@fifth.space> diff --git a/tools.suckless.org/tabbed/patches/tabbed-0.6-clientnumber.diff b/tools.suckless.org/tabbed/patches/tabbed-0.6-clientnumber.diff @@ -1,36 +0,0 @@ -diff --git a/config.mk b/config.mk -index 5279711..b0c212c 100644 ---- a/config.mk -+++ b/config.mk -@@ -12,7 +12,7 @@ INCS = -I. -I/usr/include - LIBS = -L/usr/lib -lc -lX11 - - # flags --CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -+CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_GNU_SOURCE - CFLAGS = -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} - LDFLAGS = -s ${LIBS} - -diff --git a/tabbed.c b/tabbed.c -index b2adf29..19b5bbb 100644 ---- a/tabbed.c -+++ b/tabbed.c -@@ -308,6 +308,7 @@ drawbar(void) { - unsigned long *col; - int c, fc, width, n = 0; - char *name = NULL; -+ char *tabtitle = NULL; - - if(nclients == 0) { - dc.x = 0; -@@ -353,7 +354,9 @@ drawbar(void) { - } else { - col = dc.norm; - } -- drawtext(clients[c]->name, col); -+ asprintf(&tabtitle, "%d: %s", c + 1, clients[c]->name); -+ drawtext(tabtitle, col); -+ free(tabtitle); - dc.x += dc.w; - clients[c]->tabx = dc.x; - } diff --git a/tools.suckless.org/tabbed/patches/tabbed-0.6-xft.diff b/tools.suckless.org/tabbed/patches/tabbed-0.6-xft.diff @@ -0,0 +1,233 @@ +diff --git a/config.def.h b/config.def.h +index ceda9f7..bc7cfe2 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -1,7 +1,7 @@ + /* See LICENSE file for copyright and license details. */ + + /* appearance */ +-static const char font[] = "-*-*-medium-*-*-*-14-*-*-*-*-*-*-*"; ++static const char font[] = "monospace-9"; + static const char* normbgcolor = "#222222"; + static const char* normfgcolor = "#cccccc"; + static const char* selbgcolor = "#555555"; +diff --git a/config.mk b/config.mk +index 5279711..037f9d7 100644 +--- a/config.mk ++++ b/config.mk +@@ -8,8 +8,8 @@ PREFIX = /usr/local + MANPREFIX = ${PREFIX}/share/man + + # includes and libs +-INCS = -I. -I/usr/include +-LIBS = -L/usr/lib -lc -lX11 ++INCS = -I. -I/usr/include -I/usr/include/freetype2 ++LIBS = -L/usr/lib -lc -lX11 -lfontconfig -lXft + + # flags + CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE +diff --git a/tabbed.c b/tabbed.c +index d30206b..d08348c 100644 +--- a/tabbed.c ++++ b/tabbed.c +@@ -15,6 +15,7 @@ + #include <X11/Xproto.h> + #include <X11/Xutil.h> + #include <X11/XKBlib.h> ++#include <X11/Xft/Xft.h> + + #include "arg.h" + +@@ -64,16 +65,15 @@ typedef struct { + + typedef struct { + int x, y, w, h; +- unsigned long norm[ColLast]; +- unsigned long sel[ColLast]; ++ XftColor norm[ColLast]; ++ XftColor sel[ColLast]; + Drawable drawable; + GC gc; + struct { + int ascent; + int descent; + int height; +- XFontSet set; +- XFontStruct *xfont; ++ XftFont *xfont; + } font; + } DC; /* draw context */ + +@@ -95,7 +95,7 @@ static void createnotify(const XEvent *e); + static void destroynotify(const XEvent *e); + static void die(const char *errstr, ...); + static void drawbar(void); +-static void drawtext(const char *text, unsigned long col[ColLast]); ++static void drawtext(const char *text, XftColor col[ColLast]); + static void *emallocz(size_t size); + static void *erealloc(void *o, size_t size); + static void expose(const XEvent *e); +@@ -105,7 +105,7 @@ static void focusonce(const Arg *arg); + static void fullscreen(const Arg *arg); + static char* getatom(int a); + static int getclient(Window w); +-static unsigned long getcolor(const char *colstr); ++static XftColor getcolor(const char *colstr); + static int getfirsttab(void); + static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void initfont(const char *fontstr); +@@ -219,12 +219,6 @@ cleanup(void) { + free(clients); + clients = NULL; + +- if(dc.font.set) { +- XFreeFontSet(dpy, dc.font.set); +- } else { +- XFreeFont(dpy, dc.font.xfont); +- } +- + XFreePixmap(dpy, dc.drawable); + XFreeGC(dpy, dc.gc); + XDestroyWindow(dpy, win); +@@ -305,7 +299,7 @@ die(const char *errstr, ...) { + + void + drawbar(void) { +- unsigned long *col; ++ XftColor *col; + int c, fc, width, n = 0; + char *name = NULL; + +@@ -362,12 +356,13 @@ drawbar(void) { + } + + void +-drawtext(const char *text, unsigned long col[ColLast]) { ++drawtext(const char *text, XftColor col[ColLast]) { + int i, x, y, h, len, olen; + char buf[256]; ++ XftDraw *d; + XRectangle r = { dc.x, dc.y, dc.w, dc.h }; + +- XSetForeground(dpy, dc.gc, col[ColBG]); ++ XSetForeground(dpy, dc.gc, col[ColBG].pixel); + XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); + if(!text) + return; +@@ -388,13 +383,10 @@ drawtext(const char *text, unsigned long col[ColLast]) { + for(i = len; i && i > len - 3; buf[--i] = '.'); + } + +- XSetForeground(dpy, dc.gc, col[ColFG]); +- if(dc.font.set) { +- XmbDrawString(dpy, dc.drawable, dc.font.set, +- dc.gc, x, y, buf, len); +- } else { +- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); +- } ++ d = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen)); ++ ++ XftDrawStringUtf8(d, &col[ColFG], dc.font.xfont, x, y, (XftChar8 *) buf, len); ++ XftDrawDestroy(d); + } + + void * +@@ -524,15 +516,14 @@ getclient(Window w) { + return -1; + } + +-unsigned long ++XftColor + getcolor(const char *colstr) { +- Colormap cmap = DefaultColormap(dpy, screen); +- XColor color; ++ XftColor color; + +- if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) ++ if(!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), colstr, &color)) + die("tabbed: cannot allocate color '%s'\n", colstr); + +- return color.pixel; ++ return color; + } + + int +@@ -585,41 +576,12 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size) { + + void + initfont(const char *fontstr) { +- char *def, **missing, **font_names; +- int i, n; +- XFontStruct **xfonts; +- +- missing = NULL; +- if(dc.font.set) +- XFreeFontSet(dpy, dc.font.set); +- +- dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); +- if(missing) { +- while(n--) +- fprintf(stderr, "tabbed: missing fontset: %s\n", missing[n]); +- XFreeStringList(missing); +- } ++ if(!(dc.font.xfont = XftFontOpenName(dpy, screen, fontstr)) ++ && !(dc.font.xfont = XftFontOpenName(dpy, screen, "fixed"))) ++ die("error, cannot load font: '%s'\n", fontstr); + +- if(dc.font.set) { +- dc.font.ascent = dc.font.descent = 0; +- n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); +- for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { +- dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); +- dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent); +- xfonts++; +- } +- } else { +- if(dc.font.xfont) +- XFreeFont(dpy, dc.font.xfont); +- dc.font.xfont = NULL; +- if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) +- && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) { +- die("tabbed: cannot load font: '%s'\n", fontstr); +- } +- +- dc.font.ascent = dc.font.xfont->ascent; +- dc.font.descent = dc.font.xfont->descent; +- } ++ dc.font.ascent = dc.font.xfont->ascent; ++ dc.font.descent = dc.font.xfont->descent; + dc.font.height = dc.font.ascent + dc.font.descent; + } + +@@ -972,11 +934,9 @@ setup(void) { + dc.drawable = XCreatePixmap(dpy, root, ww, wh, + DefaultDepth(dpy, screen)); + dc.gc = XCreateGC(dpy, root, 0, 0); +- if(!dc.font.set) +- XSetFont(dpy, dc.gc, dc.font.xfont->fid); + + win = XCreateSimpleWindow(dpy, root, wx, wy, ww, wh, 0, +- dc.norm[ColFG], dc.norm[ColBG]); ++ dc.norm[ColFG].pixel, dc.norm[ColBG].pixel); + XMapRaised(dpy, win); + XSelectInput(dpy, win, SubstructureNotifyMask|FocusChangeMask| + ButtonPressMask|ExposureMask|KeyPressMask|PropertyChangeMask| +@@ -1040,15 +1000,9 @@ spawn(const Arg *arg) { + + int + textnw(const char *text, unsigned int len) { +- XRectangle r; +- +- if(dc.font.set) { +- XmbTextExtents(dc.font.set, text, len, NULL, &r); +- +- return r.width; +- } +- +- return XTextWidth(dc.font.xfont, text, len); ++ XGlyphInfo ext; ++ XftTextExtentsUtf8(dpy, dc.font.xfont, (XftChar8 *) text, len, &ext); ++ return ext.xOff; + } + + void diff --git a/tools.suckless.org/tabbed/patches/tabbed-clientnumber-20160103-eb0ff62.patch b/tools.suckless.org/tabbed/patches/tabbed-clientnumber-20160103-eb0ff62.patch @@ -0,0 +1,23 @@ +diff --git a/tabbed.c b/tabbed.c +index 5f035c0..b118050 100644 +--- a/tabbed.c ++++ b/tabbed.c +@@ -317,6 +317,7 @@ drawbar(void) + unsigned long *col; + int c, cc, fc, width; + char *name = NULL; ++ char tabtitle[258]; /* drawtext buffer + one char + '\0' */ + + if (nclients == 0) { + dc.x = 0; +@@ -358,7 +359,9 @@ drawbar(void) + } else { + col = clients[c]->urgent ? dc.urg : dc.norm; + } +- drawtext(clients[c]->name, col); ++ snprintf(tabtitle, sizeof(tabtitle), "%d: %s", ++ c + 1, clients[c]->name); ++ drawtext(tabtitle, col); + dc.x += dc.w; + clients[c]->tabx = dc.x; + } diff --git a/tools.suckless.org/tabbed/patches/tabbed-keycode-20160103-eb0ff62.patch b/tools.suckless.org/tabbed/patches/tabbed-keycode-20160103-eb0ff62.patch @@ -0,0 +1,110 @@ +diff --git a/config.def.h b/config.def.h +index 587ce73..7d7e67f 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -35,31 +35,32 @@ static Bool npisrelative = False; + #define MODKEY ControlMask + static Key keys[] = { + /* modifier key function argument */ +- { MODKEY|ShiftMask, XK_Return, focusonce, { 0 } }, +- { MODKEY|ShiftMask, XK_Return, spawn, { 0 } }, +- { MODKEY, XK_t, spawn, SETPROP("_TABBED_SELECT_TAB") }, ++ { MODKEY|ShiftMask, 36, focusonce, { 0 } }, ++ { MODKEY|ShiftMask, 36, spawn, { 0 } }, ++ { MODKEY, 28, spawn, SETPROP("_TABBED_SELECT_TAB") }, + +- { MODKEY|ShiftMask, XK_l, rotate, { .i = +1 } }, +- { MODKEY|ShiftMask, XK_h, rotate, { .i = -1 } }, +- { MODKEY|ShiftMask, XK_j, movetab, { .i = -1 } }, +- { MODKEY|ShiftMask, XK_k, movetab, { .i = +1 } }, +- { MODKEY, XK_Tab, rotate, { .i = 0 } }, ++ { MODKEY|ShiftMask, 46, rotate, { .i = +1 } }, ++ { MODKEY|ShiftMask, 43, rotate, { .i = -1 } }, ++ { MODKEY|ShiftMask, 44, movetab, { .i = -1 } }, ++ { MODKEY|ShiftMask, 45, movetab, { .i = +1 } }, ++ { MODKEY, 23, rotate, { .i = 0 } }, + +- { MODKEY, XK_1, move, { .i = 0 } }, +- { MODKEY, XK_2, move, { .i = 1 } }, +- { MODKEY, XK_3, move, { .i = 2 } }, +- { MODKEY, XK_4, move, { .i = 3 } }, +- { MODKEY, XK_5, move, { .i = 4 } }, +- { MODKEY, XK_6, move, { .i = 5 } }, +- { MODKEY, XK_7, move, { .i = 6 } }, +- { MODKEY, XK_8, move, { .i = 7 } }, +- { MODKEY, XK_9, move, { .i = 8 } }, +- { MODKEY, XK_0, move, { .i = 9 } }, + +- { MODKEY, XK_q, killclient, { 0 } }, ++ { MODKEY, 10, move, { .i = 0 } }, ++ { MODKEY, 11, move, { .i = 1 } }, ++ { MODKEY, 12, move, { .i = 2 } }, ++ { MODKEY, 13, move, { .i = 3 } }, ++ { MODKEY, 14, move, { .i = 4 } }, ++ { MODKEY, 15, move, { .i = 5 } }, ++ { MODKEY, 16, move, { .i = 6 } }, ++ { MODKEY, 17, move, { .i = 7 } }, ++ { MODKEY, 18, move, { .i = 8 } }, ++ { MODKEY, 19, move, { .i = 9 } }, + +- { MODKEY, XK_u, focusurgent, { 0 } }, +- { MODKEY|ShiftMask, XK_u, toggle, { .v = (void*) &urgentswitch } }, ++ { MODKEY, 24, killclient, { 0 } }, + +- { 0, XK_F11, fullscreen, { 0 } }, ++ { MODKEY, 30, focusurgent, { .v = NULL } }, ++ { MODKEY|ShiftMask, 30, toggle, { .v = (void*) &urgentswitch } }, ++ ++ { 0, 95, fullscreen, { 0 } }, + }; +diff --git a/tabbed.c b/tabbed.c +index 5f035c0..c5ed4a3 100644 +--- a/tabbed.c ++++ b/tabbed.c +@@ -57,7 +57,7 @@ typedef union { + + typedef struct { + unsigned int mod; +- KeySym keysym; ++ KeyCode keycode; + void (*func)(const Arg *); + const Arg arg; + } Key; +@@ -680,11 +680,9 @@ keypress(const XEvent *e) + { + const XKeyEvent *ev = &e->xkey; + unsigned int i; +- KeySym keysym; + +- keysym = XkbKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0, 0); + for (i = 0; i < LENGTH(keys); i++) { +- if (keysym == keys[i].keysym && ++ if (ev->keycode == keys[i].keycode && + CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) && + keys[i].func) + keys[i].func(&(keys[i].arg)); +@@ -721,7 +719,6 @@ manage(Window w) + int i, j, nextpos; + unsigned int modifiers[] = { 0, LockMask, numlockmask, + numlockmask | LockMask }; +- KeyCode code; + Client *c; + XEvent e; + +@@ -732,12 +729,10 @@ manage(Window w) + XSync(dpy, False); + + for (i = 0; i < LENGTH(keys); i++) { +- if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) { +- for (j = 0; j < LENGTH(modifiers); j++) { +- XGrabKey(dpy, code, keys[i].mod | +- modifiers[j], w, True, +- GrabModeAsync, GrabModeAsync); +- } ++ for (j = 0; j < LENGTH(modifiers); ++j) { ++ XGrabKey(dpy, keys[i].keycode, ++ keys[i].mod | modifiers[j], w, ++ True, GrabModeAsync, GrabModeAsync); + } + } + diff --git a/tools.suckless.org/tabbed/patches/xft.md b/tools.suckless.org/tabbed/patches/xft.md @@ -0,0 +1,18 @@ +xft +=== + +Description +----------- + +This patch implements Xft. This allows users to utilize the UTF8 character set. + +Download +-------- + +* [tabbed-0.6-xft.diff](tabbed-0.6-xft.diff) (6.5k) (10 Sep 2015) + + +Author +------ + +* Danil Semelenov - `<mail at danil dot mobi>` diff --git a/tools.suckless.org/lsw.md b/tools.suckless.org/x/lsw.md diff --git a/tools.suckless.org/sprop.md b/tools.suckless.org/x/sprop.md diff --git a/tools.suckless.org/sselp.md b/tools.suckless.org/x/sselp.md diff --git a/tools.suckless.org/svkbd.md b/tools.suckless.org/x/svkbd.md diff --git a/tools.suckless.org/swarp.md b/tools.suckless.org/x/swarp.md diff --git a/tools.suckless.org/wmname.md b/tools.suckless.org/x/wmname.md diff --git a/tools.suckless.org/xssstate.md b/tools.suckless.org/x/xssstate.md