Compare commits
5 commits
433e9d2eb4
...
ce3a0db5bf
| Author | SHA1 | Date | |
|---|---|---|---|
| ce3a0db5bf | |||
| c736ea8b01 | |||
| 6e3577087b | |||
| ee7e036c7f | |||
| be5e55f4a8 |
17 changed files with 1746 additions and 71 deletions
|
|
@ -4,6 +4,7 @@
|
|||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int gappx = 5; /* gaps between windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
|
|
@ -27,9 +28,11 @@ 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, -1, -1 },
|
||||
{ "St", NULL, NULL, 0, 0, 1, 0, -1 },
|
||||
{ NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
|
|
@ -62,6 +65,12 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
|
|||
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||
static const char *termcmd[] = { "st", NULL };
|
||||
|
||||
/* commands spawned when clicking statusbar, the mouse button pressed is exported as BUTTON */
|
||||
static const StatusCmd statuscmds[] = {
|
||||
{ "notify-send Mouse$BUTTON", 1 },
|
||||
};
|
||||
static const char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL };
|
||||
|
||||
static const Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
|
|
@ -100,6 +109,7 @@ static const Key keys[] = {
|
|||
TAGKEYS( XK_8, 7)
|
||||
TAGKEYS( XK_9, 8)
|
||||
{ MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||
{ MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} },
|
||||
};
|
||||
|
||||
/* button definitions */
|
||||
|
|
@ -109,7 +119,9 @@ static const Button buttons[] = {
|
|||
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||
{ ClkStatusText, 0, Button1, spawn, {.v = statuscmd } },
|
||||
{ ClkStatusText, 0, Button2, spawn, {.v = statuscmd } },
|
||||
{ ClkStatusText, 0, Button3, spawn, {.v = statuscmd } },
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
|
|
|
|||
62
dwm/config.h
62
dwm/config.h
|
|
@ -6,6 +6,7 @@
|
|||
static const unsigned int borderpx = 2; /* border pixel of windows */
|
||||
static const unsigned int gappx = 4; /* gaps between windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = { "Fira Code:size=11:antialias=true:autohint=true" };
|
||||
|
|
@ -32,8 +33,18 @@ 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 },
|
||||
/* Las ventanas que flotan por una regla se abren centradas.
|
||||
* swallow: lo que se abre desde una terminal (isterminal) la sustituye
|
||||
* hasta que se cierra; noswallow = 1 lo evita para esa ventana. */
|
||||
/* class instance title tags mask isfloating isterminal noswallow monitor */
|
||||
{ "st-256color", NULL, NULL, 0, 0, 1, 0, -1 },
|
||||
{ "st-float", NULL, NULL, 0, 1, 0, 1, -1 }, /* st -c st-float (p. ej. nmtui) */
|
||||
{ "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
|
||||
{ NULL, "pavucontrol", NULL, 0, 1, 0, 0, -1 },
|
||||
{ NULL, "blueman-manager", NULL, 0, 1, 0, 0, -1 },
|
||||
{ "Firefox", "Places", NULL, 0, 1, 0, 0, -1 }, /* biblioteca/descargas */
|
||||
{ "Firefox", "Toolkit", NULL, 0, 1, 0, 0, -1 }, /* picture-in-picture */
|
||||
{ NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
|
|
@ -70,10 +81,42 @@ static const char *lockcmd[] = { "slock", NULL };
|
|||
|
||||
/* Audio: tras cada cambio se avisa a slstatus (SIGUSR1) para que refresque la barra al momento */
|
||||
#define STATUSREFRESH "; pkill -USR1 -x slstatus"
|
||||
#define VOLUP SHCMD("wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+" STATUSREFRESH)
|
||||
#define VOLDOWN SHCMD("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-" STATUSREFRESH)
|
||||
#define VOLMUTE SHCMD("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle" STATUSREFRESH)
|
||||
#define MICMUTE SHCMD("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle" STATUSREFRESH)
|
||||
#define VOLUPCMD "wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+" STATUSREFRESH
|
||||
#define VOLDOWNCMD "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-" STATUSREFRESH
|
||||
#define VOLMUTECMD "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle" STATUSREFRESH
|
||||
#define MICMUTECMD "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle" STATUSREFRESH
|
||||
#define VOLUP SHCMD(VOLUPCMD)
|
||||
#define VOLDOWN SHCMD(VOLDOWNCMD)
|
||||
#define VOLMUTE SHCMD(VOLMUTECMD)
|
||||
#define MICMUTE SHCMD(MICMUTECMD)
|
||||
|
||||
/*
|
||||
* Clics en la barra (parche statuscmd). El número es el byte que rodea cada
|
||||
* zona en el config.h de slstatus; el botón pulsado llega en $BUTTON
|
||||
* (1 izquierdo, 2 central, 3 derecho, 4/5 rueda arriba/abajo).
|
||||
*/
|
||||
static const StatusCmd statuscmds[] = {
|
||||
/* red: izquierdo conectarse a una red, derecho el menú completo de nmtui */
|
||||
{ "case $BUTTON in "
|
||||
"1) st -c st-float -g 90x30 -e nmtui connect ;; "
|
||||
"3) st -c st-float -g 90x30 -e nmtui ;; "
|
||||
"esac", 1 },
|
||||
/* volumen: izquierdo pavucontrol, central silenciar, derecho micro, rueda subir/bajar */
|
||||
{ "case $BUTTON in "
|
||||
"1) pavucontrol ;; "
|
||||
"2) " VOLMUTECMD " ;; "
|
||||
"3) " MICMUTECMD " ;; "
|
||||
"4) " VOLUPCMD " ;; "
|
||||
"5) " VOLDOWNCMD " ;; "
|
||||
"esac", 2 },
|
||||
/* bluetooth: izquierdo blueman, derecho encender/apagar el adaptador */
|
||||
{ "case $BUTTON in "
|
||||
"1) blueman-manager ;; "
|
||||
"3) if bluetoothctl show | grep -q 'Powered: yes'; "
|
||||
"then bluetoothctl power off; else bluetoothctl power on; fi >/dev/null" STATUSREFRESH " ;; "
|
||||
"esac", 3 },
|
||||
};
|
||||
static const char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL };
|
||||
|
||||
/* Capturas: se guardan en ~/Imágenes/Capturas y se copian al portapapeles */
|
||||
#define SCREENSHOT(opts) SHCMD( \
|
||||
|
|
@ -123,6 +166,7 @@ static const Key keys[] = {
|
|||
TAGKEYS( XK_8, 7)
|
||||
TAGKEYS( XK_9, 8)
|
||||
{ MODKEY|ShiftMask, XK_m, quit, {0} },
|
||||
{ MODKEY|ShiftMask, XK_r, quit, {1} }, /* reiniciar dwm sin cerrar ventanas */
|
||||
|
||||
/* audio */
|
||||
{ 0, XF86XK_AudioRaiseVolume, spawn, VOLUP },
|
||||
|
|
@ -143,7 +187,11 @@ static const Button buttons[] = {
|
|||
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||
{ ClkStatusText, 0, Button1, spawn, {.v = statuscmd } },
|
||||
{ ClkStatusText, 0, Button2, spawn, {.v = statuscmd } },
|
||||
{ ClkStatusText, 0, Button3, spawn, {.v = statuscmd } },
|
||||
{ ClkStatusText, 0, Button4, spawn, {.v = statuscmd } },
|
||||
{ ClkStatusText, 0, Button5, spawn, {.v = statuscmd } },
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
|
|
|
|||
|
|
@ -20,10 +20,11 @@ FREETYPEINC = /usr/include/freetype2
|
|||
# OpenBSD (uncomment)
|
||||
#FREETYPEINC = ${X11INC}/freetype2
|
||||
#MANPREFIX = ${PREFIX}/man
|
||||
#KVMLIB = -lkvm
|
||||
|
||||
# includes and libs
|
||||
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
|
||||
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB}
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,9 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
|
|||
DefaultColormap(drw->dpy, drw->screen),
|
||||
clrname, dest))
|
||||
die("error, cannot allocate color '%s'", clrname);
|
||||
|
||||
/* alfa opaco: si no, el borde de las ventanas ARGB (st con alpha) sale transparente */
|
||||
dest->pixel |= 0xffU << 24;
|
||||
}
|
||||
|
||||
/* Create color schemes. */
|
||||
|
|
|
|||
10
dwm/dwm.1
10
dwm/dwm.1
|
|
@ -142,6 +142,9 @@ Add/remove all windows with nth tag to/from the view.
|
|||
.TP
|
||||
.B Mod1\-Shift\-q
|
||||
Quit dwm.
|
||||
.TP
|
||||
.B Mod1\-Control\-Shift\-q
|
||||
Restart dwm.
|
||||
.SS Mouse commands
|
||||
.TP
|
||||
.B Mod1\-Button1
|
||||
|
|
@ -155,6 +158,13 @@ Resize focused window while dragging. Tiled windows will be toggled to the float
|
|||
.SH CUSTOMIZATION
|
||||
dwm is customized by creating a custom config.h and (re)compiling the source
|
||||
code. This keeps it fast, secure and simple.
|
||||
.SH SIGNALS
|
||||
.TP
|
||||
.B SIGHUP - 1
|
||||
Restart the dwm process.
|
||||
.TP
|
||||
.B SIGTERM - 15
|
||||
Cleanly terminate the dwm process.
|
||||
.SH SEE ALSO
|
||||
.BR dmenu (1),
|
||||
.BR st (1)
|
||||
|
|
|
|||
387
dwm/dwm.c
387
dwm/dwm.c
|
|
@ -40,6 +40,12 @@
|
|||
#include <X11/extensions/Xinerama.h>
|
||||
#endif /* XINERAMA */
|
||||
#include <X11/Xft/Xft.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <xcb/res.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <sys/sysctl.h>
|
||||
#include <kvm.h>
|
||||
#endif /* __OpenBSD */
|
||||
|
||||
#include "drw.h"
|
||||
#include "util.h"
|
||||
|
|
@ -61,7 +67,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
|||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
NetWMWindowTypeDialog, NetClientList, NetClientInfo, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
|
|
@ -91,9 +97,11 @@ struct Client {
|
|||
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
|
||||
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,9 +146,16 @@ typedef struct {
|
|||
const char *title;
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
int isterminal;
|
||||
int noswallow;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
typedef struct {
|
||||
const char *cmd;
|
||||
int id;
|
||||
} StatusCmd;
|
||||
|
||||
/* function declarations */
|
||||
static void applyrules(Client *c);
|
||||
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
|
||||
|
|
@ -198,6 +213,7 @@ static void scan(void);
|
|||
static int sendevent(Client *c, Atom proto);
|
||||
static void sendmon(Client *c, Monitor *m);
|
||||
static void setclientstate(Client *c, long state);
|
||||
static void setclienttagprop(Client *c);
|
||||
static void setfocus(Client *c);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setgaps(const Arg *arg);
|
||||
|
|
@ -206,6 +222,8 @@ static void setmfact(const Arg *arg);
|
|||
static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sighup(int unused);
|
||||
static void sigterm(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
|
|
@ -235,9 +253,18 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
|||
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
static pid_t getparentprocess(pid_t p);
|
||||
static int isdescprocess(pid_t p, pid_t c);
|
||||
static Client *swallowingclient(Window w);
|
||||
static Client *termforwin(const Client *c);
|
||||
static pid_t winpid(Window w);
|
||||
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
static char stext[256];
|
||||
static int statusw;
|
||||
static int statuscmdn;
|
||||
static char lastbutton[] = "-";
|
||||
static int screen;
|
||||
static int sw, sh; /* X display screen geometry width, height */
|
||||
static int bh; /* bar height */
|
||||
|
|
@ -261,6 +288,7 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
|||
[UnmapNotify] = unmapnotify
|
||||
};
|
||||
static Atom wmatom[WMLast], netatom[NetLast];
|
||||
static int restart = 0;
|
||||
static int running = 1;
|
||||
static Cur *cursor[CurLast];
|
||||
static Clr **scheme;
|
||||
|
|
@ -269,6 +297,8 @@ static Drw *drw;
|
|||
static Monitor *mons, *selmon;
|
||||
static Window root, wmcheckwin;
|
||||
|
||||
static xcb_connection_t *xcon;
|
||||
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
|
|
@ -298,6 +328,8 @@ applyrules(Client *c)
|
|||
&& (!r->class || strstr(class, r->class))
|
||||
&& (!r->instance || strstr(instance, r->instance)))
|
||||
{
|
||||
c->isterminal = r->isterminal;
|
||||
c->noswallow = r->noswallow;
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
|
|
@ -416,6 +448,53 @@ attachstack(Client *c)
|
|||
c->mon->stack = c;
|
||||
}
|
||||
|
||||
void
|
||||
swallow(Client *p, Client *c)
|
||||
{
|
||||
|
||||
if (c->noswallow > 0 || c->isterminal)
|
||||
return;
|
||||
if (c->noswallow < 0 && !swallowfloating && c->isfloating)
|
||||
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);
|
||||
XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
|
||||
arrange(p->mon);
|
||||
configure(p);
|
||||
updateclientlist();
|
||||
}
|
||||
|
||||
void
|
||||
unswallow(Client *c)
|
||||
{
|
||||
c->win = c->swallowing->win;
|
||||
|
||||
free(c->swallowing);
|
||||
c->swallowing = NULL;
|
||||
|
||||
/* unfullscreen the client */
|
||||
setfullscreen(c, 0);
|
||||
updatetitle(c);
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
|
||||
setclientstate(c, NormalState);
|
||||
focus(NULL);
|
||||
arrange(c->mon);
|
||||
}
|
||||
|
||||
void
|
||||
buttonpress(XEvent *e)
|
||||
{
|
||||
|
|
@ -442,9 +521,28 @@ buttonpress(XEvent *e)
|
|||
arg.ui = 1 << i;
|
||||
} else if (ev->x < x + TEXTW(selmon->ltsymbol))
|
||||
click = ClkLtSymbol;
|
||||
else if (ev->x > selmon->ww - (int)TEXTW(stext) + lrpad - 2)
|
||||
else if (ev->x > selmon->ww - statusw) {
|
||||
char *text, *s, ch;
|
||||
*lastbutton = '0' + ev->button;
|
||||
|
||||
x = selmon->ww - statusw;
|
||||
click = ClkStatusText;
|
||||
else
|
||||
|
||||
statuscmdn = 0;
|
||||
for (text = s = stext; *s && x <= ev->x; s++) {
|
||||
if ((unsigned char)(*s) < ' ') {
|
||||
ch = *s;
|
||||
*s = '\0';
|
||||
x += TEXTW(text) - lrpad;
|
||||
*s = ch;
|
||||
text = s + 1;
|
||||
if (x >= ev->x)
|
||||
break;
|
||||
/* el mismo byte al final cierra la sección clicable */
|
||||
statuscmdn = (statuscmdn == ch) ? 0 : ch;
|
||||
}
|
||||
}
|
||||
} else
|
||||
click = ClkWinTitle;
|
||||
} else if ((c = wintoclient(ev->window))) {
|
||||
focus(c);
|
||||
|
|
@ -657,6 +755,9 @@ destroynotify(XEvent *e)
|
|||
|
||||
if ((c = wintoclient(ev->window)))
|
||||
unmanage(c, 1);
|
||||
|
||||
else if ((c = swallowingclient(ev->window)))
|
||||
unmanage(c->swallowing, 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -711,9 +812,24 @@ drawbar(Monitor *m)
|
|||
|
||||
/* draw status first so it can be overdrawn by tags later */
|
||||
if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
char *text, *s, ch;
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
|
||||
drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
|
||||
|
||||
x = 0;
|
||||
for (text = s = stext; *s; s++) {
|
||||
if ((unsigned char)(*s) < ' ') {
|
||||
ch = *s;
|
||||
*s = '\0';
|
||||
tw = TEXTW(text) - lrpad;
|
||||
drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
|
||||
x += tw;
|
||||
*s = ch;
|
||||
text = s + 1;
|
||||
}
|
||||
}
|
||||
tw = TEXTW(text) - lrpad + 2;
|
||||
drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
|
||||
tw = statusw;
|
||||
}
|
||||
|
||||
for (c = m->clients; c; c = c->next) {
|
||||
|
|
@ -1034,12 +1150,13 @@ killclient(const Arg *arg)
|
|||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
Client *c, *t = NULL;
|
||||
Client *c, *t = NULL, *term = NULL;
|
||||
Window trans = None;
|
||||
XWindowChanges wc;
|
||||
|
||||
c = ecalloc(1, sizeof(Client));
|
||||
c->win = w;
|
||||
c->pid = winpid(w);
|
||||
/* geometry */
|
||||
c->x = c->oldx = wa->x;
|
||||
c->y = c->oldy = wa->y;
|
||||
|
|
@ -1054,6 +1171,12 @@ manage(Window w, XWindowAttributes *wa)
|
|||
} else {
|
||||
c->mon = selmon;
|
||||
applyrules(c);
|
||||
/* las ventanas que flotan por una regla se abren centradas */
|
||||
if (c->isfloating) {
|
||||
c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
|
||||
c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
|
||||
}
|
||||
term = termforwin(c);
|
||||
}
|
||||
|
||||
if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
|
||||
|
|
@ -1071,6 +1194,26 @@ manage(Window w, XWindowAttributes *wa)
|
|||
updatewindowtype(c);
|
||||
updatesizehints(c);
|
||||
updatewmhints(c);
|
||||
{
|
||||
int format;
|
||||
unsigned long *data = NULL, n = 0, extra;
|
||||
Monitor *m;
|
||||
Atom atom;
|
||||
if (XGetWindowProperty(dpy, c->win, netatom[NetClientInfo], 0L, 2L, False, XA_CARDINAL,
|
||||
&atom, &format, &n, &extra, (unsigned char **)&data) == Success && n == 2 && (*data & TAGMASK)) {
|
||||
c->tags = *data & TAGMASK;
|
||||
for (m = mons; m; m = m->next) {
|
||||
if (m->num == *(data+1)) {
|
||||
c->mon = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data)
|
||||
XFree(data);
|
||||
}
|
||||
setclienttagprop(c);
|
||||
|
||||
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
|
||||
grabbuttons(c, 0);
|
||||
if (!c->isfloating)
|
||||
|
|
@ -1088,6 +1231,8 @@ manage(Window w, XWindowAttributes *wa)
|
|||
c->mon->sel = c;
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
if (term)
|
||||
swallow(term, c);
|
||||
focus(NULL);
|
||||
}
|
||||
|
||||
|
|
@ -1261,6 +1406,7 @@ propertynotify(XEvent *e)
|
|||
void
|
||||
quit(const Arg *arg)
|
||||
{
|
||||
if(arg->i) restart = 1;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
|
|
@ -1432,6 +1578,7 @@ sendmon(Client *c, Monitor *m)
|
|||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
attach(c);
|
||||
attachstack(c);
|
||||
setclienttagprop(c);
|
||||
if (c->isfullscreen)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
focus(NULL);
|
||||
|
|
@ -1566,6 +1713,9 @@ setup(void)
|
|||
/* clean up any zombies (inherited from .xinitrc etc) immediately */
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0);
|
||||
|
||||
signal(SIGHUP, sighup);
|
||||
signal(SIGTERM, sigterm);
|
||||
|
||||
/* init screen */
|
||||
screen = DefaultScreen(dpy);
|
||||
sw = DisplayWidth(dpy, screen);
|
||||
|
|
@ -1592,6 +1742,7 @@ setup(void)
|
|||
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);
|
||||
netatom[NetClientInfo] = XInternAtom(dpy, "_NET_CLIENT_INFO", False);
|
||||
/* init cursors */
|
||||
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
||||
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
||||
|
|
@ -1615,6 +1766,7 @@ setup(void)
|
|||
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
|
||||
PropModeReplace, (unsigned char *) netatom, NetLast);
|
||||
XDeleteProperty(dpy, root, netatom[NetClientList]);
|
||||
XDeleteProperty(dpy, root, netatom[NetClientInfo]);
|
||||
/* select events */
|
||||
wa.cursor = cursor[CurNormal]->cursor;
|
||||
wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
|
||||
|
|
@ -1657,6 +1809,20 @@ showhide(Client *c)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
sighup(int unused)
|
||||
{
|
||||
Arg a = {.i = 1};
|
||||
quit(&a);
|
||||
}
|
||||
|
||||
void
|
||||
sigterm(int unused)
|
||||
{
|
||||
Arg a = {.i = 0};
|
||||
quit(&a);
|
||||
}
|
||||
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
|
|
@ -1667,6 +1833,17 @@ spawn(const Arg *arg)
|
|||
if (fork() == 0) {
|
||||
if (dpy)
|
||||
close(ConnectionNumber(dpy));
|
||||
if (arg->v == statuscmd) {
|
||||
for (int i = 0; i < LENGTH(statuscmds); i++) {
|
||||
if (statuscmdn == statuscmds[i].id) {
|
||||
statuscmd[2] = statuscmds[i].cmd;
|
||||
setenv("BUTTON", lastbutton, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!statuscmd[2])
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
setsid();
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
|
@ -1679,11 +1856,22 @@ spawn(const Arg *arg)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
setclienttagprop(Client *c)
|
||||
{
|
||||
long data[] = { (long) c->tags, (long) c->mon->num };
|
||||
XChangeProperty(dpy, c->win, netatom[NetClientInfo], XA_CARDINAL, 32,
|
||||
PropModeReplace, (unsigned char *) data, 2);
|
||||
}
|
||||
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
Client *c;
|
||||
if (selmon->sel && arg->ui & TAGMASK) {
|
||||
c = selmon->sel;
|
||||
selmon->sel->tags = arg->ui & TAGMASK;
|
||||
setclienttagprop(c);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
|
@ -1758,6 +1946,7 @@ toggletag(const Arg *arg)
|
|||
newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
|
||||
if (newtags) {
|
||||
selmon->sel->tags = newtags;
|
||||
setclienttagprop(selmon->sel);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
|
@ -1794,6 +1983,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;
|
||||
}
|
||||
|
||||
detach(c);
|
||||
detachstack(c);
|
||||
if (!destroyed) {
|
||||
|
|
@ -1809,9 +2012,12 @@ unmanage(Client *c, int destroyed)
|
|||
XUngrabServer(dpy);
|
||||
}
|
||||
free(c);
|
||||
focus(NULL);
|
||||
updateclientlist();
|
||||
arrange(m);
|
||||
|
||||
if (!s) {
|
||||
arrange(m);
|
||||
focus(NULL);
|
||||
updateclientlist();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2018,8 +2224,23 @@ updatesizehints(Client *c)
|
|||
void
|
||||
updatestatus(void)
|
||||
{
|
||||
if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
|
||||
if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) {
|
||||
strcpy(stext, "dwm-"VERSION);
|
||||
statusw = TEXTW(stext) - lrpad + 2;
|
||||
} else {
|
||||
char *text, *s, ch;
|
||||
statusw = 0;
|
||||
for (text = s = stext; *s; s++) {
|
||||
if ((unsigned char)(*s) < ' ') {
|
||||
ch = *s;
|
||||
*s = '\0';
|
||||
statusw += TEXTW(text) - lrpad;
|
||||
*s = ch;
|
||||
text = s + 1;
|
||||
}
|
||||
}
|
||||
statusw += TEXTW(text) - lrpad + 2;
|
||||
}
|
||||
drawbar(selmon);
|
||||
}
|
||||
|
||||
|
|
@ -2075,6 +2296,136 @@ view(const Arg *arg)
|
|||
arrange(selmon);
|
||||
}
|
||||
|
||||
pid_t
|
||||
winpid(Window w)
|
||||
{
|
||||
|
||||
pid_t result = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
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);
|
||||
|
||||
if (result == (pid_t)-1)
|
||||
result = 0;
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
Atom type;
|
||||
int format;
|
||||
unsigned long len, bytes;
|
||||
unsigned char *prop;
|
||||
pid_t ret;
|
||||
|
||||
if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
|
||||
return 0;
|
||||
|
||||
ret = *(pid_t*)prop;
|
||||
XFree(prop);
|
||||
result = ret;
|
||||
|
||||
#endif /* __OpenBSD__ */
|
||||
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__*/
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
int n;
|
||||
kvm_t *kd;
|
||||
struct kinfo_proc *kp;
|
||||
|
||||
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
if (!kd)
|
||||
return 0;
|
||||
|
||||
kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
|
||||
v = kp->p_ppid;
|
||||
#endif /* __OpenBSD__ */
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -2164,14 +2515,26 @@ main(int argc, char *argv[])
|
|||
fputs("warning: no locale support\n", stderr);
|
||||
if (!(dpy = XOpenDisplay(NULL)))
|
||||
die("dwm: cannot open display");
|
||||
if (!(xcon = XGetXCBConnection(dpy)))
|
||||
die("dwm: cannot get xcb connection\n");
|
||||
checkotherwm();
|
||||
setup();
|
||||
#ifdef __OpenBSD__
|
||||
if (pledge("stdio rpath proc exec", NULL) == -1)
|
||||
if (pledge("stdio rpath proc exec ps", NULL) == -1)
|
||||
die("pledge");
|
||||
#endif /* __OpenBSD__ */
|
||||
scan();
|
||||
run();
|
||||
if (restart) {
|
||||
/* volver a mostrar las terminales tragadas (swallow); si no, el dwm
|
||||
* nuevo no las ve y se quedan ocultas para siempre */
|
||||
for (Monitor *m = mons; m; m = m->next)
|
||||
for (Client *c = m->clients; c; c = c->next)
|
||||
if (c->swallowing)
|
||||
XMapWindow(dpy, c->swallowing->win);
|
||||
XSync(dpy, False);
|
||||
execvp(argv[0], argv);
|
||||
}
|
||||
cleanup();
|
||||
XCloseDisplay(dpy);
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
118
dwm/patches/dwm-preserveonrestart-6.3.diff
Normal file
118
dwm/patches/dwm-preserveonrestart-6.3.diff
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
From 713fa8650f5a20006451ebcccf57a4512e83bae8 Mon Sep 17 00:00:00 2001
|
||||
From: Arda Atci <arda@phytech.io>
|
||||
Date: Wed, 18 May 2022 17:23:16 +0300
|
||||
Subject: [PATCH] preserve clients on old tags when renewing dwm
|
||||
|
||||
By default, when dwm is recompiled-restarted all clients will
|
||||
lose it's current tag and collapse to first tag. This patch preserves
|
||||
clients on old tags, however note that layout order is not preserved.
|
||||
|
||||
---
|
||||
dwm.c | 38 +++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 37 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..a12e0bd 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -62,7 +62,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
+ NetWMWindowTypeDialog, NetClientList, NetClientInfo, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
@@ -198,6 +198,7 @@ static void scan(void);
|
||||
static int sendevent(Client *c, Atom proto);
|
||||
static void sendmon(Client *c, Monitor *m);
|
||||
static void setclientstate(Client *c, long state);
|
||||
+static void setclienttagprop(Client *c);
|
||||
static void setfocus(Client *c);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
@@ -1060,6 +1061,26 @@ manage(Window w, XWindowAttributes *wa)
|
||||
updatewindowtype(c);
|
||||
updatesizehints(c);
|
||||
updatewmhints(c);
|
||||
+ {
|
||||
+ int format;
|
||||
+ unsigned long *data, n, extra;
|
||||
+ Monitor *m;
|
||||
+ Atom atom;
|
||||
+ if (XGetWindowProperty(dpy, c->win, netatom[NetClientInfo], 0L, 2L, False, XA_CARDINAL,
|
||||
+ &atom, &format, &n, &extra, (unsigned char **)&data) == Success && n == 2) {
|
||||
+ c->tags = *data;
|
||||
+ for (m = mons; m; m = m->next) {
|
||||
+ if (m->num == *(data+1)) {
|
||||
+ c->mon = m;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (n > 0)
|
||||
+ XFree(data);
|
||||
+ }
|
||||
+ setclienttagprop(c);
|
||||
+
|
||||
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
|
||||
grabbuttons(c, 0);
|
||||
if (!c->isfloating)
|
||||
@@ -1423,6 +1444,7 @@ sendmon(Client *c, Monitor *m)
|
||||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
attach(c);
|
||||
attachstack(c);
|
||||
+ setclienttagprop(c);
|
||||
focus(NULL);
|
||||
arrange(NULL);
|
||||
}
|
||||
@@ -1566,6 +1588,7 @@ setup(void)
|
||||
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);
|
||||
+ netatom[NetClientInfo] = XInternAtom(dpy, "_NET_CLIENT_INFO", False);
|
||||
/* init cursors */
|
||||
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
||||
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
||||
@@ -1589,6 +1612,7 @@ setup(void)
|
||||
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
|
||||
PropModeReplace, (unsigned char *) netatom, NetLast);
|
||||
XDeleteProperty(dpy, root, netatom[NetClientList]);
|
||||
+ XDeleteProperty(dpy, root, netatom[NetClientInfo]);
|
||||
/* select events */
|
||||
wa.cursor = cursor[CurNormal]->cursor;
|
||||
wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
|
||||
@@ -1656,11 +1680,22 @@ spawn(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+setclienttagprop(Client *c)
|
||||
+{
|
||||
+ long data[] = { (long) c->tags, (long) c->mon->num };
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetClientInfo], XA_CARDINAL, 32,
|
||||
+ PropModeReplace, (unsigned char *) data, 2);
|
||||
+}
|
||||
+
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
+ Client *c;
|
||||
if (selmon->sel && arg->ui & TAGMASK) {
|
||||
+ c = selmon->sel;
|
||||
selmon->sel->tags = arg->ui & TAGMASK;
|
||||
+ setclienttagprop(c);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
@@ -1735,6 +1770,7 @@ toggletag(const Arg *arg)
|
||||
newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
|
||||
if (newtags) {
|
||||
selmon->sel->tags = newtags;
|
||||
+ setclienttagprop(selmon->sel);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
--
|
||||
2.36.1
|
||||
139
dwm/patches/dwm-restartsig-20180523-6.2.diff
Normal file
139
dwm/patches/dwm-restartsig-20180523-6.2.diff
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
From 2991f37f0aaf44b9f9b11e7893ff0af8eb88f649 Mon Sep 17 00:00:00 2001
|
||||
From: Christopher Drelich <cd@cdrakka.com>
|
||||
Date: Wed, 23 May 2018 22:50:38 -0400
|
||||
Subject: [PATCH] Modifies quit to handle restarts and adds SIGHUP and SIGTERM
|
||||
handlers.
|
||||
|
||||
Modified quit() to restart if it receives arg .i = 1
|
||||
MOD+CTRL+SHIFT+Q was added to confid.def.h to do just that.
|
||||
|
||||
Signal handlers were handled for SIGHUP and SIGTERM.
|
||||
If dwm receives these signals it calls quit() with
|
||||
arg .i = to 1 or 0, respectively.
|
||||
|
||||
To restart dwm:
|
||||
MOD+CTRL+SHIFT+Q
|
||||
or
|
||||
kill -HUP dwmpid
|
||||
|
||||
To quit dwm cleanly:
|
||||
MOD+SHIFT+Q
|
||||
or
|
||||
kill -TERM dwmpid
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwm.1 | 10 ++++++++++
|
||||
dwm.c | 22 ++++++++++++++++++++++
|
||||
3 files changed, 33 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a9ac303..e559429 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -94,6 +94,7 @@ static Key keys[] = {
|
||||
TAGKEYS( XK_8, 7)
|
||||
TAGKEYS( XK_9, 8)
|
||||
{ MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||
+ { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} },
|
||||
};
|
||||
|
||||
/* button definitions */
|
||||
diff --git a/dwm.1 b/dwm.1
|
||||
index 13b3729..36a331c 100644
|
||||
--- a/dwm.1
|
||||
+++ b/dwm.1
|
||||
@@ -142,6 +142,9 @@ Add/remove all windows with nth tag to/from the view.
|
||||
.TP
|
||||
.B Mod1\-Shift\-q
|
||||
Quit dwm.
|
||||
+.TP
|
||||
+.B Mod1\-Control\-Shift\-q
|
||||
+Restart dwm.
|
||||
.SS Mouse commands
|
||||
.TP
|
||||
.B Mod1\-Button1
|
||||
@@ -155,6 +158,13 @@ Resize focused window while dragging. Tiled windows will be toggled to the float
|
||||
.SH CUSTOMIZATION
|
||||
dwm is customized by creating a custom config.h and (re)compiling the source
|
||||
code. This keeps it fast, secure and simple.
|
||||
+.SH SIGNALS
|
||||
+.TP
|
||||
+.B SIGHUP - 1
|
||||
+Restart the dwm process.
|
||||
+.TP
|
||||
+.B SIGTERM - 15
|
||||
+Cleanly terminate the dwm process.
|
||||
.SH SEE ALSO
|
||||
.BR dmenu (1),
|
||||
.BR st (1)
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index bb95e26..286eecd 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -205,6 +205,8 @@ static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
+static void sighup(int unused);
|
||||
+static void sigterm(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
@@ -260,6 +262,7 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[UnmapNotify] = unmapnotify
|
||||
};
|
||||
static Atom wmatom[WMLast], netatom[NetLast];
|
||||
+static int restart = 0;
|
||||
static int running = 1;
|
||||
static Cur *cursor[CurLast];
|
||||
static Clr **scheme;
|
||||
@@ -1248,6 +1251,7 @@ propertynotify(XEvent *e)
|
||||
void
|
||||
quit(const Arg *arg)
|
||||
{
|
||||
+ if(arg->i) restart = 1;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
@@ -1536,6 +1540,9 @@ setup(void)
|
||||
/* clean up any zombies immediately */
|
||||
sigchld(0);
|
||||
|
||||
+ signal(SIGHUP, sighup);
|
||||
+ signal(SIGTERM, sigterm);
|
||||
+
|
||||
/* init screen */
|
||||
screen = DefaultScreen(dpy);
|
||||
sw = DisplayWidth(dpy, screen);
|
||||
@@ -1637,6 +1644,20 @@ sigchld(int unused)
|
||||
}
|
||||
|
||||
void
|
||||
+sighup(int unused)
|
||||
+{
|
||||
+ Arg a = {.i = 1};
|
||||
+ quit(&a);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+sigterm(int unused)
|
||||
+{
|
||||
+ Arg a = {.i = 0};
|
||||
+ quit(&a);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
if (arg->v == dmenucmd)
|
||||
@@ -2139,6 +2160,7 @@ main(int argc, char *argv[])
|
||||
setup();
|
||||
scan();
|
||||
run();
|
||||
+ if(restart) execvp(argv[0], argv);
|
||||
cleanup();
|
||||
XCloseDisplay(dpy);
|
||||
return EXIT_SUCCESS;
|
||||
--
|
||||
2.7.4
|
||||
|
||||
167
dwm/patches/dwm-statuscmd-nosignal-20210402-67d76bd.diff
Normal file
167
dwm/patches/dwm-statuscmd-nosignal-20210402-67d76bd.diff
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
From 02c4a28dd7f3a88eef3a4e533ace35f79cf09d57 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Bylinka <daniel.bylinka@gmail.com>
|
||||
Date: Fri, 2 Apr 2021 19:34:38 +0200
|
||||
Subject: [PATCH] [statuscmd] Run shell commands based on mouse location and
|
||||
button
|
||||
|
||||
---
|
||||
config.def.h | 10 ++++++-
|
||||
dwm.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 81 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 1c0b587..8f88366 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -59,6 +59,12 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
|
||||
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||
static const char *termcmd[] = { "st", NULL };
|
||||
|
||||
+/* commands spawned when clicking statusbar, the mouse button pressed is exported as BUTTON */
|
||||
+static const StatusCmd statuscmds[] = {
|
||||
+ { "notify-send Mouse$BUTTON", 1 },
|
||||
+};
|
||||
+static const char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL };
|
||||
+
|
||||
static Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
@@ -103,7 +109,9 @@ static Button buttons[] = {
|
||||
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||
- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||
+ { ClkStatusText, 0, Button1, spawn, {.v = statuscmd } },
|
||||
+ { ClkStatusText, 0, Button2, spawn, {.v = statuscmd } },
|
||||
+ { ClkStatusText, 0, Button3, spawn, {.v = statuscmd } },
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index b0b3466..eb478a5 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -141,6 +141,11 @@ typedef struct {
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
+typedef struct {
|
||||
+ const char *cmd;
|
||||
+ int id;
|
||||
+} StatusCmd;
|
||||
+
|
||||
/* function declarations */
|
||||
static void applyrules(Client *c);
|
||||
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
|
||||
@@ -238,6 +243,9 @@ static void zoom(const Arg *arg);
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
static char stext[256];
|
||||
+static int statusw;
|
||||
+static int statuscmdn;
|
||||
+static char lastbutton[] = "-";
|
||||
static int screen;
|
||||
static int sw, sh; /* X display screen geometry width, height */
|
||||
static int bh, blw = 0; /* bar geometry */
|
||||
@@ -440,8 +448,27 @@ buttonpress(XEvent *e)
|
||||
arg.ui = 1 << i;
|
||||
} else if (ev->x < x + blw)
|
||||
click = ClkLtSymbol;
|
||||
- else if (ev->x > selmon->ww - (int)TEXTW(stext))
|
||||
+ else if (ev->x > selmon->ww - statusw) {
|
||||
+ char *text, *s, ch;
|
||||
+ *lastbutton = '0' + ev->button;
|
||||
+
|
||||
+ x = selmon->ww - statusw;
|
||||
click = ClkStatusText;
|
||||
+
|
||||
+ statuscmdn = 0;
|
||||
+ for (text = s = stext; *s && x <= ev->x; s++) {
|
||||
+ if ((unsigned char)(*s) < ' ') {
|
||||
+ ch = *s;
|
||||
+ *s = '\0';
|
||||
+ x += TEXTW(text) - lrpad;
|
||||
+ *s = ch;
|
||||
+ text = s + 1;
|
||||
+ if (x >= ev->x)
|
||||
+ break;
|
||||
+ statuscmdn = ch;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
else
|
||||
click = ClkWinTitle;
|
||||
} else if ((c = wintoclient(ev->window))) {
|
||||
@@ -704,9 +731,24 @@ drawbar(Monitor *m)
|
||||
|
||||
/* draw status first so it can be overdrawn by tags later */
|
||||
if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
+ char *text, *s, ch;
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
|
||||
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
|
||||
+
|
||||
+ x = 0;
|
||||
+ for (text = s = stext; *s; s++) {
|
||||
+ if ((unsigned char)(*s) < ' ') {
|
||||
+ ch = *s;
|
||||
+ *s = '\0';
|
||||
+ tw = TEXTW(text) - lrpad;
|
||||
+ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
|
||||
+ x += tw;
|
||||
+ *s = ch;
|
||||
+ text = s + 1;
|
||||
+ }
|
||||
+ }
|
||||
+ tw = TEXTW(text) - lrpad + 2;
|
||||
+ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
|
||||
+ tw = statusw;
|
||||
}
|
||||
|
||||
for (c = m->clients; c; c = c->next) {
|
||||
@@ -1645,6 +1687,17 @@ spawn(const Arg *arg)
|
||||
if (fork() == 0) {
|
||||
if (dpy)
|
||||
close(ConnectionNumber(dpy));
|
||||
+ if (arg->v == statuscmd) {
|
||||
+ for (int i = 0; i < LENGTH(statuscmds); i++) {
|
||||
+ if (statuscmdn == statuscmds[i].id) {
|
||||
+ statuscmd[2] = statuscmds[i].cmd;
|
||||
+ setenv("BUTTON", lastbutton, 1);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!statuscmd[2])
|
||||
+ exit(EXIT_SUCCESS);
|
||||
+ }
|
||||
setsid();
|
||||
execvp(((char **)arg->v)[0], (char **)arg->v);
|
||||
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
|
||||
@@ -1990,8 +2043,23 @@ updatesizehints(Client *c)
|
||||
void
|
||||
updatestatus(void)
|
||||
{
|
||||
- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
|
||||
+ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) {
|
||||
strcpy(stext, "dwm-"VERSION);
|
||||
+ statusw = TEXTW(stext) - lrpad + 2;
|
||||
+ } else {
|
||||
+ char *text, *s, ch;
|
||||
+ statusw = 0;
|
||||
+ for (text = s = stext; *s; s++) {
|
||||
+ if ((unsigned char)(*s) < ' ') {
|
||||
+ ch = *s;
|
||||
+ *s = '\0';
|
||||
+ statusw += TEXTW(text) - lrpad;
|
||||
+ *s = ch;
|
||||
+ text = s + 1;
|
||||
+ }
|
||||
+ }
|
||||
+ statusw += TEXTW(text) - lrpad + 2;
|
||||
+ }
|
||||
drawbar(selmon);
|
||||
}
|
||||
|
||||
--
|
||||
2.31.0
|
||||
|
||||
412
dwm/patches/dwm-swallow-6.3.diff
Normal file
412
dwm/patches/dwm-swallow-6.3.diff
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
From 0cf9a007511f7dfd7dd94171b172562ebac9b6d5 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Schwindl <schwindl@posteo.de>
|
||||
Date: Sat, 10 Sep 2022 12:51:09 +0200
|
||||
Subject: [PATCH] 6.3 swallow patch
|
||||
|
||||
---
|
||||
config.def.h | 9 +-
|
||||
config.mk | 3 +-
|
||||
dwm.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
3 files changed, 237 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 061ad662f82a..0b2b8ffd30d5 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -3,6 +3,7 @@
|
||||
/* appearance */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
+static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
@@ -26,9 +27,11 @@ 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, -1, -1 },
|
||||
+ { "St", NULL, NULL, 0, 0, 1, 0, -1 },
|
||||
+ { NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/config.mk b/config.mk
|
||||
index 81c493ef4aff..52d1ebf30bec 100644
|
||||
--- a/config.mk
|
||||
+++ b/config.mk
|
||||
@@ -20,10 +20,11 @@ FREETYPEINC = /usr/include/freetype2
|
||||
# OpenBSD (uncomment)
|
||||
#FREETYPEINC = ${X11INC}/freetype2
|
||||
#MANPREFIX = ${PREFIX}/man
|
||||
+#KVMLIB = -lkvm
|
||||
|
||||
# includes and libs
|
||||
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
|
||||
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB}
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index e5efb6a22806..e68294b6b679 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -40,6 +40,12 @@
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif /* XINERAMA */
|
||||
#include <X11/Xft/Xft.h>
|
||||
+#include <X11/Xlib-xcb.h>
|
||||
+#include <xcb/res.h>
|
||||
+#ifdef __OpenBSD__
|
||||
+#include <sys/sysctl.h>
|
||||
+#include <kvm.h>
|
||||
+#endif /* __OpenBSD */
|
||||
|
||||
#include "drw.h"
|
||||
#include "util.h"
|
||||
@@ -92,9 +98,11 @@ struct Client {
|
||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
|
||||
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 +146,8 @@ typedef struct {
|
||||
const char *title;
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
+ int isterminal;
|
||||
+ int noswallow;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -235,6 +245,12 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
||||
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
+static pid_t getparentprocess(pid_t p);
|
||||
+static int isdescprocess(pid_t p, pid_t c);
|
||||
+static Client *swallowingclient(Window w);
|
||||
+static Client *termforwin(const Client *c);
|
||||
+static pid_t winpid(Window w);
|
||||
+
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
static char stext[256];
|
||||
@@ -269,6 +285,8 @@ static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
static Window root, wmcheckwin;
|
||||
|
||||
+static xcb_connection_t *xcon;
|
||||
+
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
@@ -298,6 +316,8 @@ applyrules(Client *c)
|
||||
&& (!r->class || strstr(class, r->class))
|
||||
&& (!r->instance || strstr(instance, r->instance)))
|
||||
{
|
||||
+ c->isterminal = r->isterminal;
|
||||
+ c->noswallow = r->noswallow;
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
@@ -416,6 +436,53 @@ attachstack(Client *c)
|
||||
c->mon->stack = c;
|
||||
}
|
||||
|
||||
+void
|
||||
+swallow(Client *p, Client *c)
|
||||
+{
|
||||
+
|
||||
+ if (c->noswallow || c->isterminal)
|
||||
+ return;
|
||||
+ if (c->noswallow && !swallowfloating && c->isfloating)
|
||||
+ 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);
|
||||
+ XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
|
||||
+ arrange(p->mon);
|
||||
+ configure(p);
|
||||
+ updateclientlist();
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+unswallow(Client *c)
|
||||
+{
|
||||
+ c->win = c->swallowing->win;
|
||||
+
|
||||
+ free(c->swallowing);
|
||||
+ c->swallowing = NULL;
|
||||
+
|
||||
+ /* unfullscreen the client */
|
||||
+ setfullscreen(c, 0);
|
||||
+ updatetitle(c);
|
||||
+ arrange(c->mon);
|
||||
+ XMapWindow(dpy, c->win);
|
||||
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
|
||||
+ setclientstate(c, NormalState);
|
||||
+ focus(NULL);
|
||||
+ arrange(c->mon);
|
||||
+}
|
||||
+
|
||||
void
|
||||
buttonpress(XEvent *e)
|
||||
{
|
||||
@@ -656,6 +723,9 @@ destroynotify(XEvent *e)
|
||||
|
||||
if ((c = wintoclient(ev->window)))
|
||||
unmanage(c, 1);
|
||||
+
|
||||
+ else if ((c = swallowingclient(ev->window)))
|
||||
+ unmanage(c->swallowing, 1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1022,12 +1092,13 @@ killclient(const Arg *arg)
|
||||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
- Client *c, *t = NULL;
|
||||
+ Client *c, *t = NULL, *term = NULL;
|
||||
Window trans = None;
|
||||
XWindowChanges wc;
|
||||
|
||||
c = ecalloc(1, sizeof(Client));
|
||||
c->win = w;
|
||||
+ c->pid = winpid(w);
|
||||
/* geometry */
|
||||
c->x = c->oldx = wa->x;
|
||||
c->y = c->oldy = wa->y;
|
||||
@@ -1042,6 +1113,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
} else {
|
||||
c->mon = selmon;
|
||||
applyrules(c);
|
||||
+ term = termforwin(c);
|
||||
}
|
||||
|
||||
if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
|
||||
@@ -1076,6 +1148,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 +1837,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;
|
||||
+ }
|
||||
+
|
||||
detach(c);
|
||||
detachstack(c);
|
||||
if (!destroyed) {
|
||||
@@ -1778,9 +1866,12 @@ unmanage(Client *c, int destroyed)
|
||||
XUngrabServer(dpy);
|
||||
}
|
||||
free(c);
|
||||
- focus(NULL);
|
||||
- updateclientlist();
|
||||
- arrange(m);
|
||||
+
|
||||
+ if (!s) {
|
||||
+ arrange(m);
|
||||
+ focus(NULL);
|
||||
+ updateclientlist();
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2044,6 +2135,136 @@ view(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+pid_t
|
||||
+winpid(Window w)
|
||||
+{
|
||||
+
|
||||
+ pid_t result = 0;
|
||||
+
|
||||
+#ifdef __linux__
|
||||
+ 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);
|
||||
+
|
||||
+ if (result == (pid_t)-1)
|
||||
+ result = 0;
|
||||
+
|
||||
+#endif /* __linux__ */
|
||||
+
|
||||
+#ifdef __OpenBSD__
|
||||
+ Atom type;
|
||||
+ int format;
|
||||
+ unsigned long len, bytes;
|
||||
+ unsigned char *prop;
|
||||
+ pid_t ret;
|
||||
+
|
||||
+ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = *(pid_t*)prop;
|
||||
+ XFree(prop);
|
||||
+ result = ret;
|
||||
+
|
||||
+#endif /* __OpenBSD__ */
|
||||
+ 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__*/
|
||||
+
|
||||
+#ifdef __OpenBSD__
|
||||
+ int n;
|
||||
+ kvm_t *kd;
|
||||
+ struct kinfo_proc *kp;
|
||||
+
|
||||
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
+ if (!kd)
|
||||
+ return 0;
|
||||
+
|
||||
+ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
|
||||
+ v = kp->p_ppid;
|
||||
+#endif /* __OpenBSD__ */
|
||||
+
|
||||
+ 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)
|
||||
{
|
||||
@@ -2133,10 +2354,12 @@ main(int argc, char *argv[])
|
||||
fputs("warning: no locale support\n", stderr);
|
||||
if (!(dpy = XOpenDisplay(NULL)))
|
||||
die("dwm: cannot open display");
|
||||
+ if (!(xcon = XGetXCBConnection(dpy)))
|
||||
+ die("dwm: cannot get xcb connection\n");
|
||||
checkotherwm();
|
||||
setup();
|
||||
#ifdef __OpenBSD__
|
||||
- if (pledge("stdio rpath proc exec", NULL) == -1)
|
||||
+ if (pledge("stdio rpath proc exec ps", NULL) == -1)
|
||||
die("pledge");
|
||||
#endif /* __OpenBSD__ */
|
||||
scan();
|
||||
--
|
||||
2.37.2
|
||||
|
||||
11
sistema/etc/elogind/logind.conf.d/10-acpid.conf
Normal file
11
sistema/etc/elogind/logind.conf.d/10-acpid.conf
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# acpid ya se encarga de la tapa y del botón de suspender (llama a zzz) y del
|
||||
# botón de encendido. Si elogind también reacciona, el portátil se suspende
|
||||
# dos veces: al abrir la tapa se enciende, se vuelve a suspender y luego
|
||||
# arranca. Así solo lo gestiona acpid.
|
||||
[Login]
|
||||
HandlePowerKey=ignore
|
||||
HandleSuspendKey=ignore
|
||||
HandleHibernateKey=ignore
|
||||
HandleLidSwitch=ignore
|
||||
HandleLidSwitchExternalPower=ignore
|
||||
HandleLidSwitchDocked=ignore
|
||||
22
sistema/etc/zzz.d/suspend/10-slock
Executable file
22
sistema/etc/zzz.d/suspend/10-slock
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
# Bloquear con slock ANTES de suspender, para que al volver no se vea el
|
||||
# escritorio. zzz ejecuta este hook como root; slock se lanza como el
|
||||
# usuario de la sesión de dwm, con su DISPLAY y XAUTHORITY.
|
||||
|
||||
pgrep -x slock >/dev/null && exit 0
|
||||
|
||||
pid=$(pgrep -xo dwm) || exit 0
|
||||
user=$(getent passwd "$(stat -c %u "/proc/$pid")" | cut -d: -f1)
|
||||
env=$(tr '\0' '\n' <"/proc/$pid/environ" | grep -E '^(DISPLAY|XAUTHORITY)=')
|
||||
[ -n "$user" ] && [ -n "$env" ] || exit 0
|
||||
|
||||
env $env setsid chpst -u "$user" /usr/local/bin/slock >/dev/null 2>&1 &
|
||||
|
||||
# Esperar a que slock arranque y tape la pantalla (máximo 2 s) antes de
|
||||
# dejar que zzz siga con la suspensión.
|
||||
i=0
|
||||
while ! pgrep -x slock >/dev/null && [ "$i" -lt 20 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
sleep 0.5
|
||||
|
|
@ -8,5 +8,21 @@ static const char *colorname[NUMCOLS] = {
|
|||
[FAILED] = "#CC3333", /* wrong password */
|
||||
};
|
||||
|
||||
/* lock screen */
|
||||
static const char *bgcolor = "black";
|
||||
static const char *fgcolor = "#eeeeee";
|
||||
static const char *dimcolor = "#888888";
|
||||
|
||||
static const char *clockfont = "monospace:bold:pixelsize=160";
|
||||
static const char *datefont = "monospace:pixelsize=34";
|
||||
static const char *textfont = "monospace:pixelsize=22";
|
||||
static const char *iconfont = "Symbols Nerd Font Mono:pixelsize=24";
|
||||
|
||||
static const int barheight = 10; /* height of the bottom bar */
|
||||
static const unsigned int maxdots = 24; /* max dots shown while typing */
|
||||
|
||||
static const char *battery = "BAT0"; /* /sys/class/power_supply/... */
|
||||
static const int batterylow = 20; /* percent shown as low */
|
||||
|
||||
/* treat a cleared input like a wrong password (color) */
|
||||
static const int failonclear = 1;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,28 @@
|
|||
static const char *user = "nobody";
|
||||
static const char *group = "nogroup";
|
||||
|
||||
/* colores de la barra inferior según el estado */
|
||||
static const char *colorname[NUMCOLS] = {
|
||||
[INIT] = "#2d353b", /* after initialization (fondo Everforest) */
|
||||
[INIT] = "#475258", /* after initialization (gris Everforest) */
|
||||
[INPUT] = "#a7c080", /* during input (verde acento) */
|
||||
[FAILED] = "#e67e80", /* wrong password (rojo Everforest) */
|
||||
};
|
||||
|
||||
/* pantalla de bloqueo (paleta Everforest) */
|
||||
static const char *bgcolor = "#2d353b"; /* fondo */
|
||||
static const char *fgcolor = "#d3c6aa"; /* reloj y texto */
|
||||
static const char *dimcolor = "#859289"; /* fecha y avisos */
|
||||
|
||||
static const char *clockfont = "Fira Code:style=Bold:pixelsize=160:antialias=true";
|
||||
static const char *datefont = "Fira Code:pixelsize=34:antialias=true";
|
||||
static const char *textfont = "Fira Code:pixelsize=22:antialias=true";
|
||||
static const char *iconfont = "Symbols Nerd Font Mono:pixelsize=24:antialias=true";
|
||||
|
||||
static const int barheight = 10; /* alto de la barra inferior */
|
||||
static const unsigned int maxdots = 24; /* puntos máximos al teclear */
|
||||
|
||||
static const char *battery = "BAT1"; /* /sys/class/power_supply/... */
|
||||
static const int batterylow = 20; /* % para mostrarla en rojo */
|
||||
|
||||
/* treat a cleared input like a wrong password (color) */
|
||||
static const int failonclear = 1;
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ X11INC = /usr/X11R6/include
|
|||
X11LIB = /usr/X11R6/lib
|
||||
|
||||
# includes and libs
|
||||
INCS = -I. -I/usr/include -I${X11INC}
|
||||
LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr
|
||||
INCS = -I. -I/usr/include -I${X11INC} -I/usr/include/freetype2
|
||||
LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lXft -lfontconfig
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
|
||||
|
|
@ -21,7 +21,7 @@ LDFLAGS = -s ${LIBS}
|
|||
COMPATSRC = explicit_bzero.c
|
||||
|
||||
# On OpenBSD and Darwin remove -lcrypt from LIBS
|
||||
#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXext -lXrandr
|
||||
#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXext -lXrandr -lXft -lfontconfig
|
||||
# On *BSD remove -DHAVE_SHADOW_H from CPPFLAGS
|
||||
# On NetBSD add -D_NETBSD_SOURCE to CPPFLAGS
|
||||
#CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_NETBSD_SOURCE
|
||||
|
|
|
|||
375
slock/slock.c
375
slock/slock.c
|
|
@ -12,12 +12,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
|
@ -30,13 +33,40 @@ enum {
|
|||
NUMCOLS
|
||||
};
|
||||
|
||||
enum {
|
||||
COLBG,
|
||||
COLFG,
|
||||
COLDIM,
|
||||
COLCHARGE,
|
||||
COLLOW,
|
||||
NUMUICOLS
|
||||
};
|
||||
|
||||
struct lock {
|
||||
int screen;
|
||||
Window root, win;
|
||||
Pixmap pmap;
|
||||
unsigned long colors[NUMCOLS];
|
||||
/* dibujado: doble búfer del tamaño de la pantalla */
|
||||
int w, h;
|
||||
Pixmap buf;
|
||||
XftDraw *draw;
|
||||
XftColor bar[NUMCOLS];
|
||||
XftColor ui[NUMUICOLS];
|
||||
XftFont *fclock, *fdate, *ftext, *ficon;
|
||||
};
|
||||
|
||||
/* estado que se muestra en la pantalla de bloqueo */
|
||||
struct state {
|
||||
unsigned int len; /* caracteres tecleados */
|
||||
int color; /* INIT, INPUT o FAILED */
|
||||
int failure; /* ha habido una contraseña incorrecta */
|
||||
char clock[16], date[64], bat[16];
|
||||
int batlevel, charging;
|
||||
};
|
||||
|
||||
static char username[64];
|
||||
|
||||
struct xrandr {
|
||||
int active;
|
||||
int evbase;
|
||||
|
|
@ -123,23 +153,296 @@ gethash(void)
|
|||
return hash;
|
||||
}
|
||||
|
||||
static XftFont *
|
||||
loadfont(Display *dpy, int screen, const char *name)
|
||||
{
|
||||
XftFont *f;
|
||||
|
||||
if (!(f = XftFontOpenName(dpy, screen, name)) &&
|
||||
!(f = XftFontOpenName(dpy, screen, "monospace")))
|
||||
die("slock: cannot load font %s\n", name);
|
||||
return f;
|
||||
}
|
||||
|
||||
static void
|
||||
setupdraw(Display *dpy, struct lock *lock)
|
||||
{
|
||||
Visual *vis = DefaultVisual(dpy, lock->screen);
|
||||
Colormap cmap = DefaultColormap(dpy, lock->screen);
|
||||
const char *uinames[NUMUICOLS] = {
|
||||
[COLBG] = bgcolor, [COLFG] = fgcolor, [COLDIM] = dimcolor,
|
||||
[COLCHARGE] = colorname[INPUT], [COLLOW] = colorname[FAILED],
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUMCOLS; i++)
|
||||
if (!XftColorAllocName(dpy, vis, cmap, colorname[i], &lock->bar[i]))
|
||||
die("slock: cannot allocate color %s\n", colorname[i]);
|
||||
for (i = 0; i < NUMUICOLS; i++)
|
||||
if (!XftColorAllocName(dpy, vis, cmap, uinames[i], &lock->ui[i]))
|
||||
die("slock: cannot allocate color %s\n", uinames[i]);
|
||||
|
||||
lock->fclock = loadfont(dpy, lock->screen, clockfont);
|
||||
lock->fdate = loadfont(dpy, lock->screen, datefont);
|
||||
lock->ftext = loadfont(dpy, lock->screen, textfont);
|
||||
lock->ficon = loadfont(dpy, lock->screen, iconfont);
|
||||
|
||||
lock->w = DisplayWidth(dpy, lock->screen);
|
||||
lock->h = DisplayHeight(dpy, lock->screen);
|
||||
lock->buf = XCreatePixmap(dpy, lock->root, lock->w, lock->h,
|
||||
DefaultDepth(dpy, lock->screen));
|
||||
lock->draw = XftDrawCreate(dpy, lock->buf, vis, cmap);
|
||||
}
|
||||
|
||||
static void
|
||||
resizedraw(Display *dpy, struct lock *lock, int w, int h)
|
||||
{
|
||||
if (w == lock->w && h == lock->h)
|
||||
return;
|
||||
lock->w = w;
|
||||
lock->h = h;
|
||||
XFreePixmap(dpy, lock->buf);
|
||||
lock->buf = XCreatePixmap(dpy, lock->root, w, h,
|
||||
DefaultDepth(dpy, lock->screen));
|
||||
XftDrawChange(lock->draw, lock->buf);
|
||||
}
|
||||
|
||||
static int
|
||||
textw(Display *dpy, XftFont *f, const char *s)
|
||||
{
|
||||
XGlyphInfo ext;
|
||||
|
||||
XftTextExtentsUtf8(dpy, f, (const FcChar8 *)s, strlen(s), &ext);
|
||||
return ext.xOff;
|
||||
}
|
||||
|
||||
static int
|
||||
iconw(Display *dpy, XftFont *f, FcChar32 icon)
|
||||
{
|
||||
XGlyphInfo ext;
|
||||
|
||||
if (!icon || !XftCharExists(dpy, f, icon))
|
||||
return 0;
|
||||
XftTextExtents32(dpy, f, &icon, 1, &ext);
|
||||
return ext.xOff;
|
||||
}
|
||||
|
||||
/* icono (opcional) + separación + texto, con la línea base en y */
|
||||
static int
|
||||
drawlabel(Display *dpy, struct lock *lock, XftFont *f, XftColor *c,
|
||||
int x, int y, FcChar32 icon, const char *s)
|
||||
{
|
||||
int iw = iconw(dpy, lock->ficon, icon), gap = iw ? f->height / 2 : 0;
|
||||
|
||||
if (iw)
|
||||
XftDrawString32(lock->draw, c, lock->ficon, x, y, &icon, 1);
|
||||
XftDrawStringUtf8(lock->draw, c, f, x + iw + gap, y,
|
||||
(const FcChar8 *)s, strlen(s));
|
||||
return iw + gap + textw(dpy, f, s);
|
||||
}
|
||||
|
||||
static int
|
||||
labelw(Display *dpy, struct lock *lock, XftFont *f, FcChar32 icon,
|
||||
const char *s)
|
||||
{
|
||||
int iw = iconw(dpy, lock->ficon, icon);
|
||||
|
||||
return iw + (iw ? f->height / 2 : 0) + textw(dpy, f, s);
|
||||
}
|
||||
|
||||
/* Actualiza hora, fecha y batería. Devuelve 1 si algo ha cambiado. */
|
||||
static int
|
||||
updatestate(struct state *st)
|
||||
{
|
||||
static const char *wdays[] = { "domingo", "lunes", "martes",
|
||||
"miércoles", "jueves", "viernes", "sábado" };
|
||||
static const char *months[] = { "enero", "febrero", "marzo", "abril",
|
||||
"mayo", "junio", "julio", "agosto", "septiembre", "octubre",
|
||||
"noviembre", "diciembre" };
|
||||
char clk[sizeof(st->clock)], date[sizeof(st->date)], bat[sizeof(st->bat)];
|
||||
char path[128], status[32] = "";
|
||||
int level = -1, charging = 0, changed;
|
||||
time_t t = time(NULL);
|
||||
struct tm *tm = localtime(&t);
|
||||
FILE *f;
|
||||
|
||||
strftime(clk, sizeof(clk), "%H:%M", tm);
|
||||
snprintf(date, sizeof(date), "%s, %d de %s", wdays[tm->tm_wday],
|
||||
tm->tm_mday, months[tm->tm_mon]);
|
||||
date[0] = toupper((unsigned char)date[0]);
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/class/power_supply/%s/capacity",
|
||||
battery);
|
||||
if ((f = fopen(path, "r"))) {
|
||||
if (fscanf(f, "%d", &level) != 1)
|
||||
level = -1;
|
||||
fclose(f);
|
||||
}
|
||||
snprintf(path, sizeof(path), "/sys/class/power_supply/%s/status",
|
||||
battery);
|
||||
if ((f = fopen(path, "r"))) {
|
||||
if (fscanf(f, "%31s", status) != 1)
|
||||
status[0] = '\0';
|
||||
fclose(f);
|
||||
}
|
||||
charging = !strcmp(status, "Charging") || !strcmp(status, "Full");
|
||||
if (level >= 0)
|
||||
snprintf(bat, sizeof(bat), "%d%%", level);
|
||||
else
|
||||
bat[0] = '\0';
|
||||
|
||||
changed = strcmp(clk, st->clock) || strcmp(date, st->date) ||
|
||||
strcmp(bat, st->bat) || charging != st->charging;
|
||||
memcpy(st->clock, clk, sizeof(clk));
|
||||
memcpy(st->date, date, sizeof(date));
|
||||
memcpy(st->bat, bat, sizeof(bat));
|
||||
st->batlevel = level;
|
||||
st->charging = charging;
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* Símbolos de Nerd Font (Material Design) */
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#define ICON_LOCK 0xF033E
|
||||
#define ICON_ALERT 0xF0026
|
||||
#define ICON_USER 0xF0004
|
||||
#define ICON_CHARGING 0xF0084
|
||||
#define ICON_BAT10 0xF007A /* 10 % .. 90 % seguidos; 100 % es 0xF0079 */
|
||||
#define ICON_BAT100 0xF0079
|
||||
|
||||
static FcChar32
|
||||
baticon(const struct state *st)
|
||||
{
|
||||
if (st->charging)
|
||||
return ICON_CHARGING;
|
||||
if (st->batlevel >= 95)
|
||||
return ICON_BAT100;
|
||||
if (st->batlevel < 10)
|
||||
return ICON_ALERT;
|
||||
return ICON_BAT10 + st->batlevel / 10 - 1;
|
||||
}
|
||||
|
||||
/* Dibuja la pantalla de bloqueo en el rectángulo de un monitor */
|
||||
static void
|
||||
drawmon(Display *dpy, struct lock *lock, const struct state *st,
|
||||
int mx, int my, int mw, int mh)
|
||||
{
|
||||
XftColor *fg = &lock->ui[COLFG], *dim = &lock->ui[COLDIM], *msgc;
|
||||
char msg[128];
|
||||
FcChar32 icon = 0;
|
||||
int x, y, w, pad = mh / 24, low;
|
||||
unsigned int i, n;
|
||||
|
||||
/* reloj y fecha, algo por encima del centro */
|
||||
y = my + mh * 2 / 5;
|
||||
x = mx + (mw - textw(dpy, lock->fclock, st->clock)) / 2;
|
||||
XftDrawStringUtf8(lock->draw, fg, lock->fclock, x, y,
|
||||
(const FcChar8 *)st->clock, strlen(st->clock));
|
||||
y += lock->fdate->height * 3 / 2;
|
||||
x = mx + (mw - textw(dpy, lock->fdate, st->date)) / 2;
|
||||
XftDrawStringUtf8(lock->draw, dim, lock->fdate, x, y,
|
||||
(const FcChar8 *)st->date, strlen(st->date));
|
||||
|
||||
/* mensaje de estado: indicación, puntos o error */
|
||||
msgc = dim;
|
||||
if (st->color == INPUT) {
|
||||
n = MIN(st->len, maxdots);
|
||||
for (i = 0, msg[0] = '\0'; i < n; i++)
|
||||
strcat(msg, i ? " ●" : "●");
|
||||
msgc = &lock->bar[INPUT];
|
||||
} else if (st->color == FAILED && st->failure) {
|
||||
icon = ICON_ALERT;
|
||||
snprintf(msg, sizeof(msg), "Contraseña incorrecta");
|
||||
msgc = &lock->bar[FAILED];
|
||||
} else {
|
||||
icon = ICON_LOCK;
|
||||
snprintf(msg, sizeof(msg), "Escribe la contraseña");
|
||||
}
|
||||
y = my + mh * 3 / 5 + lock->ftext->ascent;
|
||||
x = mx + (mw - labelw(dpy, lock, lock->ftext, icon, msg)) / 2;
|
||||
drawlabel(dpy, lock, lock->ftext, msgc, x, y, icon, msg);
|
||||
|
||||
/* abajo: usuario a la izquierda, batería a la derecha */
|
||||
y = my + mh - barheight - pad;
|
||||
drawlabel(dpy, lock, lock->ftext, dim, mx + pad, y, ICON_USER, username);
|
||||
if (st->bat[0]) {
|
||||
low = !st->charging && st->batlevel <= batterylow;
|
||||
w = labelw(dpy, lock, lock->ftext, baticon(st), st->bat);
|
||||
drawlabel(dpy, lock, lock->ftext,
|
||||
low ? &lock->ui[COLLOW] :
|
||||
st->charging ? &lock->ui[COLCHARGE] : fg,
|
||||
mx + mw - pad - w, y, baticon(st), st->bat);
|
||||
}
|
||||
|
||||
/* barra con el color del estado */
|
||||
XftDrawRect(lock->draw, &lock->bar[st->color], mx, my + mh - barheight,
|
||||
mw, barheight);
|
||||
}
|
||||
|
||||
static void
|
||||
drawlock(Display *dpy, struct lock *lock, const struct state *st)
|
||||
{
|
||||
XRRMonitorInfo *mons;
|
||||
int i, n = 0;
|
||||
|
||||
XftDrawRect(lock->draw, &lock->ui[COLBG], 0, 0, lock->w, lock->h);
|
||||
mons = XRRGetMonitors(dpy, lock->root, True, &n);
|
||||
for (i = 0; i < n; i++)
|
||||
drawmon(dpy, lock, st, mons[i].x, mons[i].y,
|
||||
mons[i].width, mons[i].height);
|
||||
if (mons)
|
||||
XRRFreeMonitors(mons);
|
||||
if (n <= 0)
|
||||
drawmon(dpy, lock, st, 0, 0, lock->w, lock->h);
|
||||
XCopyArea(dpy, lock->buf, lock->win, DefaultGC(dpy, lock->screen),
|
||||
0, 0, lock->w, lock->h, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
drawall(Display *dpy, struct lock **locks, int nscreens,
|
||||
const struct state *st)
|
||||
{
|
||||
int screen;
|
||||
|
||||
for (screen = 0; screen < nscreens; screen++)
|
||||
drawlock(dpy, locks[screen], st);
|
||||
XFlush(dpy);
|
||||
}
|
||||
|
||||
static void
|
||||
readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
||||
const char *hash)
|
||||
{
|
||||
XRRScreenChangeNotifyEvent *rre;
|
||||
char buf[32], passwd[256], *inputhash;
|
||||
int num, screen, running, failure, oldc;
|
||||
unsigned int len, color;
|
||||
int num, screen, running, xfd;
|
||||
struct state st = { 0 };
|
||||
struct timeval tv;
|
||||
KeySym ksym;
|
||||
XEvent ev;
|
||||
fd_set fds;
|
||||
|
||||
len = 0;
|
||||
running = 1;
|
||||
failure = 0;
|
||||
oldc = INIT;
|
||||
st.color = INIT;
|
||||
xfd = ConnectionNumber(dpy);
|
||||
updatestate(&st);
|
||||
drawall(dpy, locks, nscreens, &st);
|
||||
|
||||
while (running && !XNextEvent(dpy, &ev)) {
|
||||
while (running) {
|
||||
/* sin eventos pendientes: esperar como mucho 1 s y refrescar
|
||||
* reloj y batería si han cambiado (también tras suspender) */
|
||||
if (!XPending(dpy)) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(xfd, &fds);
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
if (select(xfd + 1, &fds, NULL, NULL, &tv) <= 0 &&
|
||||
updatestate(&st))
|
||||
drawall(dpy, locks, nscreens, &st);
|
||||
continue;
|
||||
}
|
||||
XNextEvent(dpy, &ev);
|
||||
if (ev.type == KeyPress) {
|
||||
explicit_bzero(&buf, sizeof(buf));
|
||||
num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0);
|
||||
|
|
@ -157,7 +460,7 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
|||
continue;
|
||||
switch (ksym) {
|
||||
case XK_Return:
|
||||
passwd[len] = '\0';
|
||||
passwd[st.len] = '\0';
|
||||
errno = 0;
|
||||
if (!(inputhash = crypt(passwd, hash)))
|
||||
fprintf(stderr, "slock: crypt: %s\n", strerror(errno));
|
||||
|
|
@ -165,52 +468,56 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
|||
running = !!strcmp(inputhash, hash);
|
||||
if (running) {
|
||||
XBell(dpy, 100);
|
||||
failure = 1;
|
||||
st.failure = 1;
|
||||
}
|
||||
explicit_bzero(&passwd, sizeof(passwd));
|
||||
len = 0;
|
||||
st.len = 0;
|
||||
break;
|
||||
case XK_Escape:
|
||||
explicit_bzero(&passwd, sizeof(passwd));
|
||||
len = 0;
|
||||
st.len = 0;
|
||||
break;
|
||||
case XK_BackSpace:
|
||||
if (len)
|
||||
passwd[--len] = '\0';
|
||||
if (st.len)
|
||||
passwd[--st.len] = '\0';
|
||||
break;
|
||||
default:
|
||||
if (num && !iscntrl((unsigned char)buf[0]) &&
|
||||
(len + num < sizeof(passwd))) {
|
||||
memcpy(passwd + len, buf, num);
|
||||
len += num;
|
||||
(st.len + num < sizeof(passwd))) {
|
||||
memcpy(passwd + st.len, buf, num);
|
||||
st.len += num;
|
||||
} else if (buf[0] == '\025') { /* ctrl-u clears input */
|
||||
explicit_bzero(&passwd, sizeof(passwd));
|
||||
len = 0;
|
||||
st.len = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT);
|
||||
if (running && oldc != color) {
|
||||
for (screen = 0; screen < nscreens; screen++) {
|
||||
XSetWindowBackground(dpy,
|
||||
locks[screen]->win,
|
||||
locks[screen]->colors[color]);
|
||||
XClearWindow(dpy, locks[screen]->win);
|
||||
}
|
||||
oldc = color;
|
||||
st.color = st.len ? INPUT :
|
||||
((st.failure || failonclear) ? FAILED : INIT);
|
||||
if (running) {
|
||||
updatestate(&st);
|
||||
drawall(dpy, locks, nscreens, &st);
|
||||
}
|
||||
} else if (ev.type == Expose) {
|
||||
if (ev.xexpose.count == 0)
|
||||
drawall(dpy, locks, nscreens, &st);
|
||||
} else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) {
|
||||
rre = (XRRScreenChangeNotifyEvent*)&ev;
|
||||
for (screen = 0; screen < nscreens; screen++) {
|
||||
if (locks[screen]->win == rre->window) {
|
||||
if (rre->rotation == RR_Rotate_90 ||
|
||||
rre->rotation == RR_Rotate_270)
|
||||
rre->rotation == RR_Rotate_270) {
|
||||
XResizeWindow(dpy, locks[screen]->win,
|
||||
rre->height, rre->width);
|
||||
else
|
||||
resizedraw(dpy, locks[screen],
|
||||
rre->height, rre->width);
|
||||
} else {
|
||||
XResizeWindow(dpy, locks[screen]->win,
|
||||
rre->width, rre->height);
|
||||
XClearWindow(dpy, locks[screen]->win);
|
||||
resizedraw(dpy, locks[screen],
|
||||
rre->width, rre->height);
|
||||
}
|
||||
drawlock(dpy, locks[screen], &st);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -243,16 +550,20 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)
|
|||
lock->colors[i] = color.pixel;
|
||||
}
|
||||
|
||||
setupdraw(dpy, lock);
|
||||
|
||||
/* init */
|
||||
wa.override_redirect = 1;
|
||||
wa.background_pixel = lock->colors[INIT];
|
||||
wa.background_pixel = lock->ui[COLBG].pixel;
|
||||
wa.event_mask = ExposureMask;
|
||||
lock->win = XCreateWindow(dpy, lock->root, 0, 0,
|
||||
DisplayWidth(dpy, lock->screen),
|
||||
DisplayHeight(dpy, lock->screen),
|
||||
0, DefaultDepth(dpy, lock->screen),
|
||||
CopyFromParent,
|
||||
DefaultVisual(dpy, lock->screen),
|
||||
CWOverrideRedirect | CWBackPixel, &wa);
|
||||
CWOverrideRedirect | CWBackPixel | CWEventMask,
|
||||
&wa);
|
||||
lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8);
|
||||
invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap,
|
||||
&color, &color, 0, 0);
|
||||
|
|
@ -340,6 +651,10 @@ main(int argc, char **argv) {
|
|||
dontkillme();
|
||||
#endif
|
||||
|
||||
/* nombre del usuario que bloquea, para mostrarlo */
|
||||
if ((pwd = getpwuid(getuid())))
|
||||
snprintf(username, sizeof(username), "%s", pwd->pw_name);
|
||||
|
||||
hash = gethash();
|
||||
errno = 0;
|
||||
if (!crypt("", hash))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
/* interval between updates (in ms) */
|
||||
const unsigned int interval = 1000;
|
||||
const unsigned int interval = 2000;
|
||||
|
||||
/* text to show if no value can be retrieved */
|
||||
static const char unknown_str[] = "N/A";
|
||||
|
|
@ -21,18 +21,39 @@ static const char unknown_str[] = "N/A";
|
|||
* run_command output of a shell command command
|
||||
* wifi_essid WiFi network name interface name (wlan0)
|
||||
*/
|
||||
/*
|
||||
* Red sin lanzar procesos: ETH si hay cable en enp3s0; si no, la red WiFi de
|
||||
* wlp4s0 (se lee por netlink con el componente wifi_essid de slstatus).
|
||||
*/
|
||||
static const char *
|
||||
red(const char *unused)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
if ((s = cat("/sys/class/net/enp3s0/operstate")) && !strcmp(s, "up"))
|
||||
return "ETH";
|
||||
if (!(s = wifi_essid("wlp4s0")))
|
||||
return "WiFi: N/A";
|
||||
return bprintf("WiFi: %s", s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Los bytes \001, \002 y \003 delimitan las zonas clicables de la barra
|
||||
* (parche statuscmd de dwm): la red, el volumen y el bluetooth. Lo que hace
|
||||
* cada clic está en statuscmds, en el config.h de dwm.
|
||||
*/
|
||||
static const struct arg args[] = {
|
||||
/* function format argument */
|
||||
{ cpu_perc, "[ CPU: %s%% ] ", NULL },
|
||||
{ ram_perc, "[ RAM: %s%% ] ", NULL },
|
||||
/* ETH si hay cable en enp3s0; si no, la red WiFi de wlp4s0 */
|
||||
{ run_command, "[ %s ] ", "if [ \"$(cat /sys/class/net/enp3s0/operstate)\" = up ]; then echo ETH; "
|
||||
"else s=$(iw dev wlp4s0 link | sed -n 's/^[[:space:]]*SSID: //p'); echo \"WiFi: ${s:-N/A}\"; fi" },
|
||||
{ battery_perc, "[ BAT: %s%%", "BAT1" },
|
||||
{ battery_state, " %s ] ", "BAT1" },
|
||||
/* function format argument */
|
||||
{ cpu_perc, "[ CPU: %s%% ] ", NULL },
|
||||
{ ram_perc, "[ RAM: %s%% ] ", NULL },
|
||||
{ red, "\001[ %s ]\001 ", NULL },
|
||||
{ battery_perc, "[ BAT: %s%%", "BAT1" },
|
||||
{ battery_state, " %s ] ", "BAT1" },
|
||||
/* mismo volumen que maneja wpctl (PipeWire); MIC OFF si el micro está silenciado */
|
||||
{ run_command, "[ VOL: %s ] ", "wpctl get-volume @DEFAULT_AUDIO_SINK@ | awk '{ printf \"%d%%\", $2 * 100 + 0.5 } /MUTED/ { printf \" MUT\" }'; "
|
||||
"wpctl get-volume @DEFAULT_AUDIO_SOURCE@ | grep -q MUTED && printf ' MIC OFF'" },
|
||||
{ run_command, "[ BT: %s ] ", "bluetoothctl devices Connected | head -1 | cut -d' ' -f3-" },
|
||||
{ datetime, "[ %s ]", "%d/%m/%y %H:%M:%S" },
|
||||
{ run_command, "\002[ VOL: %s ]\002 ", "wpctl get-volume @DEFAULT_AUDIO_SINK@ | awk '{ printf \"%d%%\", $2 * 100 + 0.5 } /MUTED/ { printf \" MUT\" }'; "
|
||||
"wpctl get-volume @DEFAULT_AUDIO_SOURCE@ | grep -q MUTED && printf ' MIC OFF'" },
|
||||
/* OFF si el adaptador está apagado; si no, el primer dispositivo conectado */
|
||||
{ run_command, "\003[ BT: %s ]\003 ", "bluetoothctl show | grep -q 'Powered: yes' || { echo OFF; exit; }; "
|
||||
"bluetoothctl devices Connected | head -1 | cut -d' ' -f3-" },
|
||||
{ datetime, "[ %s ]", "%d/%m/%y %H:%M" },
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue