Compare commits
3 commits
813717224b
...
e9fa102625
Author | SHA1 | Date | |
---|---|---|---|
Alexis Jhon Gaspar | e9fa102625 | ||
Alexis Jhon Gaspar | ab0de64412 | ||
Alexis Jhon Gaspar | 5de5ece675 |
|
@ -1,4 +1,4 @@
|
|||
# Suckless Utilities version 6.4
|
||||
# Suckless Utilities version 6.5
|
||||
## About
|
||||
These are my builds of suckless software such as dwm and st, based on the work for flexipatch by bakkeby. This aims for much more streamlined configuration and patching than 6.3 (which becomes more complicated over time and whenever more patches are integrated).
|
||||
|
||||
|
@ -119,6 +119,7 @@ Linux/Unix users:
|
|||
- libexif(-devel or -dev) (for nsxiv)
|
||||
- jq (for handling eww notifications)
|
||||
- pamixer
|
||||
- xcb-util(-devel or -dev)
|
||||
|
||||
Termux users:
|
||||
- xorg
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Similar to [dwm-flexipatch](https://github.com/bakkeby/dwm-flexipatch) this dmenu 5.2 (8df553e,
|
||||
2023-09-22) project has a different take on patching. It uses preprocessor directives to decide
|
||||
Similar to [dwm-flexipatch](https://github.com/bakkeby/dwm-flexipatch) this dmenu 5.3 (7be720c,
|
||||
2024-03-19) project has a different take on patching. It uses preprocessor directives to decide
|
||||
whether or not to include a patch during build time. Essentially this means that this build, for
|
||||
better or worse, contains both the patched _and_ the original code. The aim being that you can
|
||||
select which patches to include and the build will contain that code and nothing more.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# dmenu version
|
||||
VERSION = 5.2
|
||||
VERSION = 5.3
|
||||
|
||||
# paths
|
||||
PREFIX = /usr/local
|
||||
|
|
|
@ -1645,7 +1645,11 @@ setup(void)
|
|||
|
||||
#if CENTER_PATCH
|
||||
if (center) {
|
||||
#if XYW_PATCH
|
||||
mw = (dmw>0 ? dmw : MIN(MAX(max_textw() + promptw, min_width), info[i].width));
|
||||
#else
|
||||
mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width);
|
||||
#endif // XYW_PATCH
|
||||
x = info[i].x_org + ((info[i].width - mw) / 2);
|
||||
y = info[i].y_org + ((info[i].height - mh) / 2);
|
||||
} else {
|
||||
|
@ -1677,7 +1681,11 @@ setup(void)
|
|||
parentwin);
|
||||
#if CENTER_PATCH
|
||||
if (center) {
|
||||
#if XYW_PATCH
|
||||
mw = (dmw>0 ? dmw : MIN(MAX(max_textw() + promptw, min_width), wa.width));
|
||||
#else
|
||||
mw = MIN(MAX(max_textw() + promptw, min_width), wa.width);
|
||||
#endif // XYW_PATCH
|
||||
x = (wa.width - mw) / 2;
|
||||
y = (wa.height - mh) / 2;
|
||||
} else {
|
||||
|
@ -2054,7 +2062,7 @@ main(int argc, char *argv[])
|
|||
prompt = argv[++i];
|
||||
else if (!strcmp(argv[i], "-fn")) /* font or font set */
|
||||
#if PANGO_PATCH
|
||||
strcpy(font, argv[++i]);
|
||||
font = argv[++i];
|
||||
#else
|
||||
fonts[0] = argv[++i];
|
||||
#endif // PANGO_PATCH
|
||||
|
|
|
@ -234,7 +234,7 @@ xfont_free(Fnt *font)
|
|||
|
||||
#if PANGO_PATCH
|
||||
Fnt*
|
||||
drw_font_create(Drw* drw, const char font[])
|
||||
drw_font_create(Drw* drw, const char *font)
|
||||
{
|
||||
Fnt *fnt = NULL;
|
||||
|
||||
|
@ -365,10 +365,10 @@ int
|
|||
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup)
|
||||
{
|
||||
char buf[1024];
|
||||
int ty;
|
||||
unsigned int ew;
|
||||
int i, ty, th;
|
||||
unsigned int ew, eh;
|
||||
XftDraw *d = NULL;
|
||||
size_t i, len;
|
||||
size_t len;
|
||||
int render = x || y || w || h;
|
||||
|
||||
if (!drw || (render && !drw->scheme) || !text || !drw->font)
|
||||
|
@ -393,10 +393,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
len = strlen(text);
|
||||
|
||||
if (len) {
|
||||
drw_font_getexts(drw->font, text, len, &ew, NULL, markup);
|
||||
drw_font_getexts(drw->font, text, len, &ew, &eh, markup);
|
||||
th = eh;
|
||||
/* shorten text if necessary */
|
||||
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--)
|
||||
drw_font_getexts(drw->font, text, len, &ew, NULL, markup);
|
||||
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--) {
|
||||
drw_font_getexts(drw->font, text, len, &ew, &eh, markup);
|
||||
if (eh > th)
|
||||
th = eh;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
memcpy(buf, text, len);
|
||||
|
@ -406,7 +410,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
; /* NOP */
|
||||
|
||||
if (render) {
|
||||
ty = y + (h - drw->font->h) / 2;
|
||||
ty = y + (h - th) / 2;
|
||||
if (markup)
|
||||
pango_layout_set_markup(drw->font->layout, buf, len);
|
||||
else
|
||||
|
@ -650,7 +654,7 @@ drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w,
|
|||
if (w)
|
||||
*w = r.width / PANGO_SCALE;
|
||||
if (h)
|
||||
*h = font->h;
|
||||
*h = r.height / PANGO_SCALE;
|
||||
}
|
||||
#else
|
||||
void
|
||||
|
|
|
@ -55,7 +55,7 @@ void drw_free(Drw *drw);
|
|||
|
||||
/* Fnt abstraction */
|
||||
#if PANGO_PATCH
|
||||
Fnt *drw_font_create(Drw* drw, const char font[]);
|
||||
Fnt *drw_font_create(Drw* drw, const char *font);
|
||||
void drw_font_free(Fnt* set);
|
||||
unsigned int drw_font_getwidth(Drw *drw, const char *text, Bool markup);
|
||||
unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
This dwm 6.4 (9f88553, 2023-09-22) side project has a different take on dwm patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. Due to the complexity of some of the patches dwm-flexipatch has diverged from mainstream dwm by making some core patches non-optional for maintenance reasons. For the classic dwm-flexipatch build refer to branch [dwm-flexipatch-1.0](https://github.com/bakkeby/dwm-flexipatch/tree/dwm-flexipatch-1.0).
|
||||
This dwm 6.5 (5687f46, 2024-06-08) side project has a different take on dwm patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. Due to the complexity of some of the patches dwm-flexipatch has diverged from mainstream dwm by making some core patches non-optional for maintenance reasons. For the classic dwm-flexipatch build refer to branch [dwm-flexipatch-1.0](https://github.com/bakkeby/dwm-flexipatch/tree/dwm-flexipatch-1.0).
|
||||
|
||||
For example to include the `alpha` patch then you would only need to flip this setting from 0 to 1 in [patches.h](https://github.com/bakkeby/dwm-flexipatch/blob/master/patches.def.h):
|
||||
```c
|
||||
|
@ -19,6 +19,14 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
|
|||
|
||||
### Changelog:
|
||||
|
||||
2024-01-31 - Added the placedir patch
|
||||
|
||||
2023-12-22 - Added the do-not-die-on-color-allocation-failure patch
|
||||
|
||||
2023-12-01 - Added the sendmoncenter patch
|
||||
|
||||
2023-11-12 - Added the focusmaster-return patch variant
|
||||
|
||||
2023-06-27 - Added the focusfollowmouse and unmanaged patches
|
||||
|
||||
2023-06-25 - Added the toggletopbar patch
|
||||
|
@ -355,6 +363,10 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
|
|||
- i.e. if topbar is 0 then dmenu will appear at the bottom and if 1 then dmenu will appear at
|
||||
the top
|
||||
|
||||
- do-not-die-on-color-allocation-failure
|
||||
- avoids dwm terminating (dying) on color allocation failures
|
||||
- useful for the xrdb (xresources) and status2d patches
|
||||
|
||||
- [dragcfact](https://github.com/bakkeby/patches/wiki/dragcfact/)
|
||||
- lets you resize clients' size (i.e. modify cfact) by holding modkey + shift + right-click
|
||||
and dragging the mouse
|
||||
|
@ -442,6 +454,10 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
|
|||
- [focusmaster](https://dwm.suckless.org/patches/focusmaster/)
|
||||
- a simple patch that just puts focus back to the master client
|
||||
|
||||
- [focusmaster-return](https://dwm.suckless.org/patches/focusmaster/)
|
||||
- a simple patch that just puts focus back to the master client
|
||||
- additionally allows focus to be switched back to the previous client
|
||||
|
||||
- [focusonclick](https://dwm.suckless.org/patches/focusonclick/)
|
||||
- this patch makes you switch focus only by mouse click and not sloppy (focus follows mouse
|
||||
pointer)
|
||||
|
@ -587,6 +603,9 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
|
|||
- [pertag](https://dwm.suckless.org/patches/pertag/)
|
||||
- adds nmaster, mfact, layouts and more per tag rather than per monitor
|
||||
|
||||
- [placedir](https://github.com/bakkeby/patches/wiki/placedir)
|
||||
- allows tiled windows to be moved in any direction (up, down, left, right)
|
||||
|
||||
- [placemouse](https://github.com/bakkeby/patches/wiki/placemouse)
|
||||
- lets the user change the position of a client in the stack using the mouse.
|
||||
|
||||
|
@ -644,6 +663,9 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
|
|||
- [selfrestart](https://dwm.suckless.org/patches/selfrestart/)
|
||||
- restart dwm without the unnecessary dependency of an external script
|
||||
|
||||
- [sendmoncenter](https://dwm.suckless.org/patches/sendmoncenter/)
|
||||
- floating windows being sent to another monitor will be centered
|
||||
|
||||
- [sendmon\_keepfocus](https://github.com/bakkeby/patches/wiki/sendmon_keepfocus/)
|
||||
- minor patch that allow clients to keep focus when being sent to another monitor
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
|||
/* This allows the bar border size to be explicitly set separately from borderpx.
|
||||
* If left as 0 then it will default to the borderpx value of the monitor and will
|
||||
* automatically update with setborderpx. */
|
||||
static const unsigned int barborderpx = 0; /* border pixel of bar */
|
||||
static const unsigned int barborderpx = 1; /* border pixel of bar */
|
||||
#endif // BAR_BORDER_PATCH
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
#if SWALLOW_PATCH
|
||||
|
@ -95,14 +95,20 @@ static const int vertpadbar = 0; /* vertical padding for statusba
|
|||
#endif // BAR_STATUSPADDING_PATCH
|
||||
#if BAR_STATUSBUTTON_PATCH
|
||||
static const char buttonbar[] = " Start";
|
||||
#endif // BAR_STATUSBUTTON_PATCH
|
||||
#if BAR_DOCKBUTTONS_PATCH
|
||||
static const char buttonbar2[] = " st";
|
||||
static const char buttonbar3[] = " Firefox";
|
||||
static const char buttonbar4[] = " mpd";
|
||||
#endif // BAR_DOCKBUTTONS_PATCH
|
||||
#if BAR_POWERBUTTON_PATCH
|
||||
static const char buttonbar5[] = " ";
|
||||
#endif // BAR_POWERBUTTON_PATCH
|
||||
#if BAR_WINCONTROLBUTTONS_PATCH
|
||||
static const char buttonbar6[] = "";
|
||||
static const char buttonbar7[] = "";
|
||||
static const char buttonbar8[] = "";
|
||||
#endif // BAR_STATUSBUTTON_PATCH
|
||||
#endif // BAR_WINCONTROLBUTTONS_PATCH
|
||||
#if BAR_SYSTRAY_PATCH
|
||||
static const unsigned int systrayspacing = 2; /* systray spacing */
|
||||
static const int showsystray = 1; /* 0 means no systray */
|
||||
|
@ -507,6 +513,17 @@ static const Rule rules[] = {
|
|||
RULE(.wintype = WTYPE "DOCK", .unmanaged = 1)
|
||||
RULE(.wintype = WTYPE "DIALOG", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "Xmessage", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-atarist", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-cpm80", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-dos", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-ibmpc", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-img", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-macplus", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-rc759", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-sim405", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-simarm", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-sims32", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.class = "pce-vic20", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.wintype = WTYPE "UTILITY", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.wintype = WTYPE "TOOLBAR", .isfloating = 1, .noswallow = 1)
|
||||
RULE(.wintype = WTYPE "SPLASH", .isfloating = 1, .noswallow = 1)
|
||||
|
@ -570,6 +587,14 @@ static const BarRule barrules[] = {
|
|||
{ -1, 1, BAR_ALIGN_LEFT, width_dcbutton2, draw_dcbutton2, click_dcbutton2, NULL, "dockbutton2" },
|
||||
{ -1, 1, BAR_ALIGN_LEFT, width_dcbutton3, draw_dcbutton3, click_dcbutton3, NULL, "dockbutton3" },
|
||||
#endif // BAR_DOCKBUTTONS_PATCH
|
||||
#if BAR_POWERBUTTON_PATCH
|
||||
{ -1, 0, BAR_ALIGN_RIGHT, width_powbutton, draw_powbutton, click_powbutton, NULL, "powerbutton" },
|
||||
#endif // BAR_POWERBUTTON_PATCH
|
||||
#if BAR_WINCONTROLBUTTONS_PATCH
|
||||
{ -1, 1, BAR_ALIGN_RIGHT, width_winbutton, draw_winbutton, click_winbutton, NULL, "statusbutton6" },
|
||||
{ -1, 1, BAR_ALIGN_RIGHT, width_winbutton2, draw_winbutton2, click_winbutton2, NULL, "statusbutton7" },
|
||||
{ -1, 1, BAR_ALIGN_RIGHT, width_winbutton3, draw_winbutton3, click_winbutton3, NULL, "statusbutton8" },
|
||||
#endif // BAR_WINCONTROLBUTTONS_PATCH
|
||||
#if BAR_TAGGRID_PATCH
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_taggrid, draw_taggrid, click_taggrid, NULL, "taggrid" },
|
||||
#endif // BAR_TAGGRID_PATCH
|
||||
|
@ -582,14 +607,6 @@ static const BarRule barrules[] = {
|
|||
#if BAR_TAGLABELS_PATCH
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_taglabels, draw_taglabels, click_taglabels, hover_taglabels, "taglabels" },
|
||||
#endif // BAR_TAGLABELS_PATCH
|
||||
#if BAR_POWERBUTTON_PATCH
|
||||
{ -1, 0, BAR_ALIGN_RIGHT, width_powbutton, draw_powbutton, click_powbutton, NULL, "powerbutton" },
|
||||
#endif // BAR_POWERBUTTON_PATCH
|
||||
#if BAR_WINCONTROLBUTTONS_PATCH
|
||||
{ -1, 1, BAR_ALIGN_RIGHT, width_winbutton, draw_winbutton, click_winbutton, NULL, "statusbutton6" },
|
||||
{ -1, 1, BAR_ALIGN_RIGHT, width_winbutton2, draw_winbutton2, click_winbutton2, NULL, "statusbutton7" },
|
||||
{ -1, 1, BAR_ALIGN_RIGHT, width_winbutton3, draw_winbutton3, click_winbutton3, NULL, "statusbutton8" },
|
||||
#endif // BAR_WINCONTROLBUTTONS_PATCH
|
||||
#if BAR_SYSTRAY_PATCH
|
||||
{ 0, 0, BAR_ALIGN_RIGHT, width_systray, draw_systray, click_systray, NULL, "systray" },
|
||||
#endif // BAR_SYSTRAY_PATCH
|
||||
|
@ -997,9 +1014,9 @@ static const Key keys[] = {
|
|||
#if TAB_PATCH
|
||||
{ MODKEY|ControlMask, XK_b, tabmode, {-1} },
|
||||
#endif // TAB_PATCH
|
||||
#if FOCUSMASTER_PATCH
|
||||
#if FOCUSMASTER_PATCH || FOCUSMASTER_RETURN_PATCH
|
||||
{ MODKEY|ControlMask, XK_space, focusmaster, {0} },
|
||||
#endif // FOCUSMASTER_PATCH
|
||||
#endif // FOCUSMASTER_PATCH / FOCUSMASTER_RETURN_PATCH
|
||||
#if STACKER_PATCH
|
||||
STACKKEYS(MODKEY, focus)
|
||||
STACKKEYS(MODKEY|ShiftMask, push)
|
||||
|
@ -1013,6 +1030,12 @@ static const Key keys[] = {
|
|||
{ MODKEY, XK_Up, focusdir, {.i = 2 } }, // up
|
||||
{ MODKEY, XK_Down, focusdir, {.i = 3 } }, // down
|
||||
#endif // FOCUSDIR_PATCH
|
||||
#if PLACEDIR_PATCH
|
||||
{ MODKEY|ControlMask, XK_Left, placedir, {.i = 0 } }, // left
|
||||
{ MODKEY|ControlMask, XK_Right, placedir, {.i = 1 } }, // right
|
||||
{ MODKEY|ControlMask, XK_Up, placedir, {.i = 2 } }, // up
|
||||
{ MODKEY|ControlMask, XK_Down, placedir, {.i = 3 } }, // down
|
||||
#endif // PLACEDIR_PATCH
|
||||
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
||||
{ MODKEY, XK_s, swapfocus, {.i = -1 } },
|
||||
#endif // SWAPFOCUS_PATCH
|
||||
|
@ -1227,8 +1250,8 @@ static const Key keys[] = {
|
|||
{ MODKEY, XK_Right, viewtoright, {0} }, // note keybinding conflict with focusdir
|
||||
{ MODKEY|ShiftMask, XK_Left, tagtoleft, {0} }, // note keybinding conflict with shifttag
|
||||
{ MODKEY|ShiftMask, XK_Right, tagtoright, {0} }, // note keybinding conflict with shifttag
|
||||
{ MODKEY|ControlMask, XK_Left, tagandviewtoleft, {0} },
|
||||
{ MODKEY|ControlMask, XK_Right, tagandviewtoright, {0} },
|
||||
{ MODKEY|ControlMask, XK_Left, tagandviewtoleft, {0} }, // note keybinding conflict with placedir
|
||||
{ MODKEY|ControlMask, XK_Right, tagandviewtoright, {0} }, // note keybinding conflict with placedir
|
||||
#endif // FOCUSADJACENTTAG_PATCH
|
||||
#if TAGALL_PATCH
|
||||
{ MODKEY|ShiftMask, XK_F1, tagall, {.v = "F1"} },
|
||||
|
@ -1267,8 +1290,8 @@ static const Key keys[] = {
|
|||
#if BAR_TAGGRID_PATCH
|
||||
{ MODKEY|ControlMask, XK_Up, switchtag, { .ui = SWITCHTAG_UP | SWITCHTAG_VIEW } },
|
||||
{ MODKEY|ControlMask, XK_Down, switchtag, { .ui = SWITCHTAG_DOWN | SWITCHTAG_VIEW } },
|
||||
{ MODKEY|ControlMask, XK_Right, switchtag, { .ui = SWITCHTAG_RIGHT | SWITCHTAG_VIEW } },
|
||||
{ MODKEY|ControlMask, XK_Left, switchtag, { .ui = SWITCHTAG_LEFT | SWITCHTAG_VIEW } },
|
||||
{ MODKEY|ControlMask, XK_Right, switchtag, { .ui = SWITCHTAG_RIGHT | SWITCHTAG_VIEW } }, // note keybinding conflict with placedir
|
||||
{ MODKEY|ControlMask, XK_Left, switchtag, { .ui = SWITCHTAG_LEFT | SWITCHTAG_VIEW } }, // note keybinding conflict with placedir
|
||||
{ MODKEY|Mod4Mask, XK_Up, switchtag, { .ui = SWITCHTAG_UP | SWITCHTAG_TAG | SWITCHTAG_VIEW } },
|
||||
{ MODKEY|Mod4Mask, XK_Down, switchtag, { .ui = SWITCHTAG_DOWN | SWITCHTAG_TAG | SWITCHTAG_VIEW } },
|
||||
{ MODKEY|Mod4Mask, XK_Right, switchtag, { .ui = SWITCHTAG_RIGHT | SWITCHTAG_TAG | SWITCHTAG_VIEW } },
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# dwm version
|
||||
VERSION = 6.4
|
||||
VERSION = 6.5
|
||||
|
||||
# Customize below to fit your system
|
||||
|
||||
|
|
|
@ -337,14 +337,22 @@ drw_clr_create(
|
|||
#if BAR_ALPHA_PATCH
|
||||
if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
|
||||
clrname, dest))
|
||||
#if DO_NOT_DIE_ON_COLOR_ALLOCATION_FAILURE_PATCH
|
||||
fprintf(stderr, "warning, cannot allocate color '%s'", clrname);
|
||||
#else
|
||||
die("error, cannot allocate color '%s'", clrname);
|
||||
#endif // DO_NOT_DIE_ON_COLOR_ALLOCATION_FAILURE_PATCH
|
||||
|
||||
dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
|
||||
#else
|
||||
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
||||
DefaultColormap(drw->dpy, drw->screen),
|
||||
clrname, dest))
|
||||
#if DO_NOT_DIE_ON_COLOR_ALLOCATION_FAILURE_PATCH
|
||||
fprintf(stderr, "warning, cannot allocate color '%s'", clrname);
|
||||
#else
|
||||
die("error, cannot allocate color '%s'", clrname);
|
||||
#endif // DO_NOT_DIE_ON_COLOR_ALLOCATION_FAILURE_PATCH
|
||||
|
||||
#if NO_TRANSPARENT_BORDERS_PATCH
|
||||
dest->pixel |= 0xff << 24;
|
||||
|
@ -428,10 +436,10 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
{
|
||||
#if BAR_PANGO_PATCH
|
||||
char buf[1024];
|
||||
int ty;
|
||||
unsigned int ew;
|
||||
int i, ty, th;
|
||||
unsigned int ew, eh;
|
||||
XftDraw *d = NULL;
|
||||
size_t i, len;
|
||||
size_t len;
|
||||
int render = x || y || w || h;
|
||||
|
||||
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
|
||||
|
@ -456,10 +464,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
len = strlen(text);
|
||||
|
||||
if (len) {
|
||||
drw_font_getexts(drw->fonts, text, len, &ew, NULL, markup);
|
||||
drw_font_getexts(drw->fonts, text, len, &ew, &eh, markup);
|
||||
th = eh;
|
||||
/* shorten text if necessary */
|
||||
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--)
|
||||
drw_font_getexts(drw->fonts, text, len, &ew, NULL, markup);
|
||||
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--) {
|
||||
drw_font_getexts(drw->fonts, text, len, &ew, &eh, markup);
|
||||
if (eh > th)
|
||||
th = eh;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
memcpy(buf, text, len);
|
||||
|
@ -469,7 +481,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
; /* NOP */
|
||||
|
||||
if (render) {
|
||||
ty = y + (h - drw->fonts->h) / 2;
|
||||
ty = y + (h - th) / 2;
|
||||
if (markup)
|
||||
pango_layout_set_markup(drw->fonts->layout, buf, len);
|
||||
else
|
||||
|
@ -701,7 +713,7 @@ drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w,
|
|||
if (w)
|
||||
*w = r.width / PANGO_SCALE;
|
||||
if (h)
|
||||
*h = font->h;
|
||||
*h = r.height / PANGO_SCALE;
|
||||
}
|
||||
#else
|
||||
void
|
||||
|
|
|
@ -495,6 +495,9 @@ struct Monitor {
|
|||
int gappiv; /* vertical gap between windows */
|
||||
int gappoh; /* horizontal outer gaps */
|
||||
int gappov; /* vertical outer gaps */
|
||||
#if PERMON_VANITYGAPS_PATCH
|
||||
int enablegaps; /* whether gaps are enabled */
|
||||
#endif // PERMON_VANITYGAPS_PATCH
|
||||
#endif // VANITYGAPS_PATCH
|
||||
#if SETBORDERPX_PATCH
|
||||
int borderpx;
|
||||
|
@ -517,6 +520,9 @@ struct Monitor {
|
|||
Client *clients;
|
||||
Client *sel;
|
||||
Client *stack;
|
||||
#if FOCUSMASTER_RETURN_PATCH
|
||||
Client *tagmarked[32];
|
||||
#endif // FOCUSMASTER_RETURN_PATCH
|
||||
Monitor *next;
|
||||
Bar *bar;
|
||||
const Layout *lt[2];
|
||||
|
@ -695,6 +701,9 @@ static void maprequest(XEvent *e);
|
|||
static void motionnotify(XEvent *e);
|
||||
static void movemouse(const Arg *arg);
|
||||
static Client *nexttiled(Client *c);
|
||||
#if NOBORDER_PATCH
|
||||
static int noborder(Client *c);
|
||||
#endif // NOBORDER_PATCH
|
||||
#if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH
|
||||
static void pop(Client *c);
|
||||
#endif // !ZOOMSWAP_PATCH / TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH
|
||||
|
@ -972,6 +981,7 @@ applyrules(Client *c)
|
|||
if (r->switchtag)
|
||||
#endif // SWALLOW_PATCH
|
||||
{
|
||||
unfocus(selmon->sel, 1, NULL);
|
||||
selmon = c->mon;
|
||||
if (r->switchtag == 2 || r->switchtag == 4)
|
||||
newtagset = c->mon->tagset[c->mon->seltags] ^ c->tags;
|
||||
|
@ -1115,6 +1125,11 @@ arrange(Monitor *m)
|
|||
void
|
||||
arrangemon(Monitor *m)
|
||||
{
|
||||
#if BAR_PADDING_SMART_PATCH
|
||||
updatebarpos(selmon);
|
||||
for (Bar *bar = selmon->bar; bar; bar = bar->next)
|
||||
XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
|
||||
#endif // BAR_PADDING_SMART_PATCH
|
||||
#if TAB_PATCH
|
||||
updatebarpos(m);
|
||||
XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th);
|
||||
|
@ -1468,6 +1483,15 @@ configure(Client *c)
|
|||
ce.width = c->w;
|
||||
ce.height = c->h;
|
||||
ce.border_width = c->bw;
|
||||
|
||||
#if NOBORDER_PATCH
|
||||
if (noborder(c)) {
|
||||
ce.width += c->bw * 2;
|
||||
ce.height += c->bw * 2;
|
||||
ce.border_width = 0;
|
||||
}
|
||||
#endif // NOBORDER_PATCH
|
||||
|
||||
ce.above = None;
|
||||
ce.override_redirect = False;
|
||||
XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
|
||||
|
@ -1779,6 +1803,10 @@ createmon(void)
|
|||
}
|
||||
#endif // PERTAG_PATCH
|
||||
|
||||
#if PERMON_VANITYGAPS_PATCH
|
||||
m->enablegaps = 1;
|
||||
#endif // PERMON_VANITYGAPS_PATCH
|
||||
|
||||
#if SEAMLESS_RESTART_PATCH
|
||||
restoremonitorstate(m);
|
||||
#endif // SEAMLESS_RESTART_PATCH
|
||||
|
@ -1831,6 +1859,11 @@ detach(Client *c)
|
|||
#if SEAMLESS_RESTART_PATCH
|
||||
c->idx = 0;
|
||||
#endif // SEAMLESS_RESTART_PATCH
|
||||
#if FOCUSMASTER_RETURN_PATCH
|
||||
for (int i = 1; i < NUMTAGS; i++)
|
||||
if (c == c->mon->tagmarked[i])
|
||||
c->mon->tagmarked[i] = NULL;
|
||||
#endif // FOCUSMASTER_RETURN_PATCH
|
||||
|
||||
for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
|
||||
*tc = c->next;
|
||||
|
@ -2059,6 +2092,10 @@ focus(Client *c)
|
|||
if (!c || !ISVISIBLE(c))
|
||||
c = getpointerclient();
|
||||
#endif // FOCUSFOLLOWMOUSE_PATCH
|
||||
#if STICKY_PATCH
|
||||
if (!c || !ISVISIBLE(c))
|
||||
for (c = selmon->stack; c && (!ISVISIBLE(c) || c->issticky); c = c->snext);
|
||||
#endif // STICKY_PATCH
|
||||
if (!c || !ISVISIBLE(c))
|
||||
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
||||
if (selmon->sel && selmon->sel != c)
|
||||
|
@ -2493,8 +2530,10 @@ manage(Window w, XWindowAttributes *wa)
|
|||
#endif // CENTER_TRANSIENT_WINDOWS_PATCH | CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH | CENTER_PATCH
|
||||
} else {
|
||||
#if SEAMLESS_RESTART_PATCH
|
||||
if (!settings_restored)
|
||||
if (!settings_restored || c->mon == NULL) {
|
||||
c->mon = selmon;
|
||||
settings_restored = 0;
|
||||
}
|
||||
#else
|
||||
c->mon = selmon;
|
||||
#endif // SEAMLESS_RESTART_PATCH
|
||||
|
@ -2851,10 +2890,63 @@ nexttiled(Client *c)
|
|||
return c;
|
||||
}
|
||||
|
||||
#if NOBORDER_PATCH
|
||||
int
|
||||
noborder(Client *c)
|
||||
{
|
||||
int monocle_layout = 0;
|
||||
|
||||
#if MONOCLE_LAYOUT
|
||||
if (&monocle == c->mon->lt[c->mon->sellt]->arrange)
|
||||
monocle_layout = 1;
|
||||
#endif // MONOCLE_LAYOUT
|
||||
|
||||
#if DECK_LAYOUT
|
||||
if (&deck == c->mon->lt[c->mon->sellt]->arrange && c->mon->nmaster == 0)
|
||||
monocle_layout = 1;
|
||||
#endif // DECK_LAYOUT
|
||||
|
||||
#if FLEXTILE_DELUXE_LAYOUT
|
||||
if (&flextile == c->mon->lt[c->mon->sellt]->arrange && (
|
||||
(c->mon->ltaxis[LAYOUT] == NO_SPLIT && c->mon->ltaxis[MASTER] == MONOCLE) ||
|
||||
(c->mon->ltaxis[STACK] == MONOCLE && c->mon->nmaster == 0)
|
||||
)) {
|
||||
monocle_layout = 1;
|
||||
}
|
||||
#endif //FLEXTILE_DELUXE_LAYOUT
|
||||
|
||||
if (!monocle_layout && (nexttiled(c->mon->clients) != c || nexttiled(c->next)))
|
||||
return 0;
|
||||
|
||||
if (c->isfloating)
|
||||
return 0;
|
||||
|
||||
if (!c->mon->lt[c->mon->sellt]->arrange)
|
||||
return 0;
|
||||
|
||||
#if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
||||
if (c->fakefullscreen != 1 && c->isfullscreen)
|
||||
return 0;
|
||||
#elif !FAKEFULLSCREEN_PATCH
|
||||
if (c->isfullscreen)
|
||||
return 0;
|
||||
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif // NOBORDER_PATCH
|
||||
|
||||
#if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH
|
||||
void
|
||||
pop(Client *c)
|
||||
{
|
||||
#if FOCUSMASTER_RETURN_PATCH
|
||||
int i;
|
||||
for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++);
|
||||
i++;
|
||||
|
||||
c->mon->tagmarked[i] = nexttiled(c->mon->clients);
|
||||
#endif // FOCUSMASTER_RETURN_PATCH
|
||||
detach(c);
|
||||
attach(c);
|
||||
focus(c);
|
||||
|
@ -2998,31 +3090,9 @@ resizeclient(Client *c, int x, int y, int w, int h)
|
|||
drawroundedcorners(c);
|
||||
#endif // ROUNDED_CORNERS_PATCH
|
||||
#if NOBORDER_PATCH
|
||||
if (((nexttiled(c->mon->clients) == c && !nexttiled(c->next))
|
||||
#if MONOCLE_LAYOUT
|
||||
|| &monocle == c->mon->lt[c->mon->sellt]->arrange
|
||||
#endif // MONOCLE_LAYOUT
|
||||
#if DECK_LAYOUT
|
||||
|| (&deck == c->mon->lt[c->mon->sellt]->arrange &&
|
||||
c->mon->nmaster == 0)
|
||||
#endif // DECK_LAYOUT
|
||||
#if FLEXTILE_DELUXE_LAYOUT
|
||||
|| (&flextile == c->mon->lt[c->mon->sellt]->arrange && (
|
||||
(c->mon->ltaxis[LAYOUT] == NO_SPLIT &&
|
||||
c->mon->ltaxis[MASTER] == MONOCLE) ||
|
||||
(c->mon->ltaxis[STACK] == MONOCLE &&
|
||||
c->mon->nmaster == 0)))
|
||||
#endif //FLEXTILE_DELUXE_LAYOUT
|
||||
)
|
||||
#if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
||||
&& (c->fakefullscreen == 1 || !c->isfullscreen)
|
||||
#else
|
||||
&& !c->isfullscreen
|
||||
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
||||
&& !c->isfloating
|
||||
&& c->mon->lt[c->mon->sellt]->arrange) {
|
||||
c->w = wc.width += c->bw * 2;
|
||||
c->h = wc.height += c->bw * 2;
|
||||
if (noborder(c)) {
|
||||
wc.width += c->bw * 2;
|
||||
wc.height += c->bw * 2;
|
||||
wc.border_width = 0;
|
||||
}
|
||||
#endif // NOBORDER_PATCH
|
||||
|
@ -3377,6 +3447,14 @@ sendmon(Client *c, Monitor *m)
|
|||
#else
|
||||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
#endif // EMPTYVIEW_PATCH
|
||||
#if SENDMON_CENTER_PATCH
|
||||
c->x = m->mx + (m->mw - WIDTH(c)) / 2;
|
||||
c->y = m->my + (m->mh - HEIGHT(c)) / 2;
|
||||
#if SAVEFLOATS_PATCH
|
||||
c->sfx = m->mx + (m->mw - c->sfw - 2 * c->bw) / 2;
|
||||
c->sfy = m->my + (m->mh - c->sfh - 2 * c->bw) / 2;
|
||||
#endif // SAVEFLOATS_PATCH
|
||||
#endif // SENDMON_CENTER_PATCH
|
||||
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
|
||||
attachx(c);
|
||||
#else
|
||||
|
@ -4219,10 +4297,21 @@ togglefloating(const Arg *arg)
|
|||
#endif // !FAKEFULLSCREEN_PATCH
|
||||
c->isfloating = !c->isfloating || c->isfixed;
|
||||
#if !BAR_FLEXWINTITLE_PATCH
|
||||
#if RENAMED_SCRATCHPADS_PATCH
|
||||
if (c->scratchkey != 0 && c->isfloating)
|
||||
XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColFloat].pixel);
|
||||
else if (c->scratchkey != 0)
|
||||
XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColBorder].pixel);
|
||||
else if (c->isfloating)
|
||||
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
|
||||
else
|
||||
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
||||
#else
|
||||
if (c->isfloating)
|
||||
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
|
||||
else
|
||||
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
||||
#endif // RENAMED_SCRATCHPADS_PATCH
|
||||
#endif // BAR_FLEXWINTITLE_PATCH
|
||||
if (c->isfloating) {
|
||||
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
||||
|
@ -4637,16 +4726,36 @@ updatebarpos(Monitor *m)
|
|||
#if BAR_PADDING_VANITYGAPS_PATCH && VANITYGAPS_PATCH
|
||||
#if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
|
||||
if (!selmon || selmon->pertag->enablegaps[selmon->pertag->curtag])
|
||||
#elif PERMON_VANITYGAPS_PATCH
|
||||
if (!selmon || selmon->enablegaps)
|
||||
#else
|
||||
if (enablegaps)
|
||||
#endif // PERTAG_VANITYGAPS_PATCH
|
||||
{
|
||||
#if BAR_PADDING_SMART_PATCH
|
||||
unsigned int n; Client *c;
|
||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
if (n > 1) {
|
||||
y_pad = gappoh;
|
||||
x_pad = gappov;
|
||||
}
|
||||
#else
|
||||
y_pad = gappoh;
|
||||
x_pad = gappov;
|
||||
#endif // BAR_PADDING_SMART_PATCH
|
||||
}
|
||||
#elif BAR_PADDING_PATCH
|
||||
#if BAR_PADDING_SMART_PATCH
|
||||
unsigned int n; Client *c;
|
||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
if (n > 1) {
|
||||
y_pad = vertpad;
|
||||
x_pad = sidepad;
|
||||
}
|
||||
#else
|
||||
y_pad = vertpad;
|
||||
x_pad = sidepad;
|
||||
#endif // BAR_PADDING_SMART_PATCH
|
||||
#endif // BAR_PADDING_PATCH | BAR_PADDING_VANITYGAPS_PATCH
|
||||
|
||||
#if INSETS_PATCH
|
||||
|
@ -4701,7 +4810,7 @@ updatebarpos(Monitor *m)
|
|||
}
|
||||
|
||||
void
|
||||
updateclientlist()
|
||||
updateclientlist(void)
|
||||
{
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
|
@ -5095,6 +5204,9 @@ void
|
|||
zoom(const Arg *arg)
|
||||
{
|
||||
Client *c = selmon->sel;
|
||||
#if FOCUSMASTER_RETURN_PATCH && ZOOMSWAP_PATCH
|
||||
int i;
|
||||
#endif // FOCUSMASTER_RETURN_PATCH
|
||||
if (arg && arg->v)
|
||||
c = (Client*)arg->v;
|
||||
if (!c)
|
||||
|
@ -5148,6 +5260,12 @@ zoom(const Arg *arg)
|
|||
cold = nexttiled(c->mon->clients);
|
||||
if (c != cold && !at)
|
||||
at = findbefore(c);
|
||||
#if FOCUSMASTER_RETURN_PATCH
|
||||
for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++);
|
||||
i++;
|
||||
|
||||
c->mon->tagmarked[i] = cold;
|
||||
#endif // FOCUSMASTER_RETURN_PATCH
|
||||
detach(c);
|
||||
attach(c);
|
||||
/* swap windows instead of pushing the previous one down */
|
||||
|
|
|
@ -21,7 +21,7 @@ alttab()
|
|||
|
||||
/* redraw tab */
|
||||
XRaiseWindow(dpy, alttabwin);
|
||||
drawtab(ntabs, 0, m);
|
||||
drawalttab(ntabs, 0, m);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -66,7 +66,7 @@ alttabend()
|
|||
}
|
||||
|
||||
void
|
||||
drawtab(int nwins, int first, Monitor *m)
|
||||
drawalttab(int nwins, int first, Monitor *m)
|
||||
{
|
||||
Client *c;
|
||||
int i, h;
|
||||
|
@ -178,7 +178,7 @@ alttabstart(const Arg *arg)
|
|||
i++;
|
||||
}
|
||||
|
||||
drawtab(ntabs, 1, m);
|
||||
drawalttab(ntabs, 1, m);
|
||||
|
||||
struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <time.h>
|
||||
|
||||
static void drawtab(int nwins, int first, Monitor *m);
|
||||
static void drawalttab(int nwins, int first, Monitor *m);
|
||||
static void alttabstart(const Arg *arg);
|
||||
static void alttabend();
|
||||
|
|
|
@ -15,8 +15,7 @@ click_dcbutton(Bar *bar, Arg *arg, BarArg *a)
|
|||
{
|
||||
return ClkButton2;
|
||||
}
|
||||
int
|
||||
width_dcbutton2(Bar *bar, BarArg *a)
|
||||
int width_dcbutton2(Bar *bar, BarArg *a)
|
||||
{
|
||||
return TEXTW(buttonbar3);
|
||||
}
|
||||
|
|
|
@ -102,6 +102,11 @@ click_pwrl_tags(Bar *bar, Arg *arg, BarArg *a)
|
|||
if (i < NUMTAGS) {
|
||||
arg->ui = 1 << i;
|
||||
}
|
||||
#if BAR_TAGPREVIEW_PATCH
|
||||
if (selmon->previewshow != 0) {
|
||||
hidetagpreview(selmon);
|
||||
}
|
||||
#endif // BAR_TAGPREVIEW_PATCH
|
||||
return ClkTagBar;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
static int width_stbutton(Bar *bar, BarArg *a);
|
||||
static int draw_stbutton(Bar *bar, BarArg *a);
|
||||
static int click_stbutton(Bar *bar, Arg *arg, BarArg *a);
|
||||
|
||||
|
|
|
@ -13,14 +13,7 @@ width_systray(Bar *bar, BarArg *a)
|
|||
if (!w)
|
||||
XMoveWindow(dpy, systray->win, -systray->h, bar->by);
|
||||
}
|
||||
|
||||
if (w) {
|
||||
w += lrpad / 2 - systrayspacing;
|
||||
#if !BAR_STATUS_PATCH
|
||||
w += lrpad / 2;
|
||||
#endif // BAR_STATUS_PATCH
|
||||
}
|
||||
return w;
|
||||
return w ? w + lrpad - systrayspacing : 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -101,11 +94,13 @@ draw_systray(Bar *bar, BarArg *a)
|
|||
i->mon = bar->mon;
|
||||
}
|
||||
|
||||
unsigned int xpos = bar->bx + a->x + lrpad / 2;
|
||||
#if BAR_STATUS_PATCH
|
||||
xpos -= lrpad / 2;
|
||||
#endif // BAR_STATUS_PATCH
|
||||
XMoveResizeWindow(dpy, systray->win, xpos, (w ? bar->by + a->y + (a->h - systray->h) / 2: -bar->by - a->y), MAX(w, 1), systray->h);
|
||||
#if !BAR_ALPHA_PATCH
|
||||
wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||
XChangeWindowAttributes(dpy, systray->win, CWBackPixel, &wa);
|
||||
XClearWindow(dpy, systray->win);
|
||||
#endif // BAR_ALPHA_PATCH
|
||||
|
||||
XMoveResizeWindow(dpy, systray->win, bar->bx + a->x + lrpad / 2, (w ? bar->by + a->y + (a->h - systray->h) / 2: -systray->h), MAX(w, 1), systray->h);
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,11 @@ click_taglabels(Bar *bar, Arg *arg, BarArg *a)
|
|||
if (i < NUMTAGS) {
|
||||
arg->ui = 1 << i;
|
||||
}
|
||||
#if BAR_TAGPREVIEW_PATCH
|
||||
if (selmon->previewshow != 0) {
|
||||
hidetagpreview(selmon);
|
||||
}
|
||||
#endif // BAR_TAGPREVIEW_PATCH
|
||||
return ClkTagBar;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,11 @@ click_tags(Bar *bar, Arg *arg, BarArg *a)
|
|||
if (i < NUMTAGS) {
|
||||
arg->ui = 1 << i;
|
||||
}
|
||||
#if BAR_TAGPREVIEW_PATCH
|
||||
if (selmon->previewshow != 0) {
|
||||
hidetagpreview(selmon);
|
||||
}
|
||||
#endif // BAR_TAGPREVIEW_PATCH
|
||||
return ClkTagBar;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ togglewin(const Arg *arg)
|
|||
Client *c = (Client*)arg->v;
|
||||
if (!c)
|
||||
return;
|
||||
if (c == selmon->sel)
|
||||
if (!HIDDEN(c) && c == selmon->sel)
|
||||
hide(c);
|
||||
else {
|
||||
if (HIDDEN(c))
|
||||
|
|
|
@ -1,14 +1,42 @@
|
|||
void
|
||||
focusmaster(const Arg *arg)
|
||||
{
|
||||
Client *c;
|
||||
Client *master;
|
||||
Monitor *m = selmon;
|
||||
#if FOCUSMASTER_RETURN_PATCH
|
||||
int i;
|
||||
#endif // FOCUSMASTER_RETURN_PATCH
|
||||
|
||||
if (selmon->nmaster < 1)
|
||||
if (m->nmaster < 1)
|
||||
return;
|
||||
#if !FAKEFULLSCREEN_PATCH
|
||||
#if FAKEFULLSCREEN_CLIENT_PATCH
|
||||
if (!m->sel || (m->sel->isfullscreen && m->sel->fakefullscreen != 1 && lockfullscreen))
|
||||
return;
|
||||
#else
|
||||
if (!m->sel || (m->sel->isfullscreen && lockfullscreen))
|
||||
return;
|
||||
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
||||
#endif // FAKEFULLSCREEN_PATCH
|
||||
|
||||
master = nexttiled(m->clients);
|
||||
|
||||
if (!master)
|
||||
return;
|
||||
|
||||
c = nexttiled(selmon->clients);
|
||||
#if FOCUSMASTER_RETURN_PATCH
|
||||
for (i = 0; !(m->tagset[m->seltags] & 1 << i); i++);
|
||||
i++;
|
||||
|
||||
if (c)
|
||||
focus(c);
|
||||
if (m->sel == master) {
|
||||
if (m->tagmarked[i] && ISVISIBLE(m->tagmarked[i]))
|
||||
focus(m->tagmarked[i]);
|
||||
} else {
|
||||
m->tagmarked[i] = m->sel;
|
||||
focus(master);
|
||||
}
|
||||
#else
|
||||
focus(master);
|
||||
#endif // FOCUSMASTER_RETURN_PATCH
|
||||
restack(m);
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
#if FOCUSFOLLOWMOUSE_PATCH
|
||||
#include "focusfollowmouse.c"
|
||||
#endif
|
||||
#if FOCUSMASTER_PATCH
|
||||
#if FOCUSMASTER_PATCH || FOCUSMASTER_RETURN_PATCH
|
||||
#include "focusmaster.c"
|
||||
#endif
|
||||
#if FOCUSURGENT_PATCH
|
||||
|
@ -208,6 +208,9 @@
|
|||
#if PERTAG_PATCH
|
||||
#include "pertag.c"
|
||||
#endif
|
||||
#if PLACEDIR_PATCH
|
||||
#include "placedir.c"
|
||||
#endif
|
||||
#if PLACEMOUSE_PATCH
|
||||
#include "placemouse.c"
|
||||
#endif
|
||||
|
@ -404,3 +407,4 @@
|
|||
#if BAR_WINCONTROLBUTTONS_PATCH
|
||||
#include "bar_wincontrolbutton.c"
|
||||
#endif
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
#if FOCUSFOLLOWMOUSE_PATCH
|
||||
#include "focusfollowmouse.h"
|
||||
#endif
|
||||
#if FOCUSMASTER_PATCH
|
||||
#if FOCUSMASTER_PATCH || FOCUSMASTER_RETURN_PATCH
|
||||
#include "focusmaster.h"
|
||||
#endif
|
||||
#if FOCUSURGENT_PATCH
|
||||
|
@ -207,6 +207,9 @@
|
|||
#if PERTAG_PATCH
|
||||
#include "pertag.h"
|
||||
#endif
|
||||
#if PLACEDIR_PATCH
|
||||
#include "placedir.h"
|
||||
#endif
|
||||
#if PLACEMOUSE_PATCH
|
||||
#include "placemouse.h"
|
||||
#endif
|
||||
|
|
|
@ -44,10 +44,9 @@ deck(Monitor *m)
|
|||
#endif // VANITYGAPS_PATCH
|
||||
|
||||
getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
|
||||
#if !MONOCLESYMBOL_PATCH
|
||||
|
||||
if (n - m->nmaster > 0) /* override layout symbol */
|
||||
snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster);
|
||||
#endif // MONOCLESMYBOL_PATCH
|
||||
|
||||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
if (i < m->nmaster) {
|
||||
|
|
96
dwm-flexipatch/patch/placedir.c
Normal file
96
dwm-flexipatch/patch/placedir.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
void
|
||||
placedir(const Arg *arg)
|
||||
{
|
||||
Client *s = selmon->sel, *f = NULL, *c, *next, *fprior, *sprior;
|
||||
|
||||
if (!s || s->isfloating)
|
||||
return;
|
||||
|
||||
unsigned int score = -1;
|
||||
unsigned int client_score;
|
||||
int dist;
|
||||
int dirweight = 20;
|
||||
|
||||
next = s->next;
|
||||
if (!next)
|
||||
next = s->mon->clients;
|
||||
for (c = next; c != s; c = next) {
|
||||
|
||||
next = c->next;
|
||||
if (!next)
|
||||
next = s->mon->clients;
|
||||
|
||||
if (!ISVISIBLE(c)) // || HIDDEN(c)
|
||||
continue;
|
||||
|
||||
switch (arg->i) {
|
||||
case 0: // left
|
||||
dist = s->x - c->x - c->w;
|
||||
client_score =
|
||||
dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
|
||||
abs(s->y - c->y);
|
||||
break;
|
||||
case 1: // right
|
||||
dist = c->x - s->x - s->w;
|
||||
client_score =
|
||||
dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
|
||||
abs(c->y - s->y);
|
||||
break;
|
||||
case 2: // up
|
||||
dist = s->y - c->y - c->h;
|
||||
client_score =
|
||||
dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
|
||||
abs(s->x - c->x);
|
||||
break;
|
||||
default:
|
||||
case 3: // down
|
||||
dist = c->y - s->y - s->h;
|
||||
client_score =
|
||||
dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
|
||||
abs(c->x - s->x);
|
||||
break;
|
||||
}
|
||||
|
||||
if (((arg->i == 0 || arg->i == 2) && client_score <= score) || client_score < score) {
|
||||
score = client_score;
|
||||
f = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (f && f != s) {
|
||||
for (fprior = f->mon->clients; fprior && fprior->next != f; fprior = fprior->next);
|
||||
for (sprior = s->mon->clients; sprior && sprior->next != s; sprior = sprior->next);
|
||||
|
||||
if (s == fprior) {
|
||||
next = f->next;
|
||||
if (sprior)
|
||||
sprior->next = f;
|
||||
else
|
||||
f->mon->clients = f;
|
||||
f->next = s;
|
||||
s->next = next;
|
||||
} else if (f == sprior) {
|
||||
next = s->next;
|
||||
if (fprior)
|
||||
fprior->next = s;
|
||||
else
|
||||
s->mon->clients = s;
|
||||
s->next = f;
|
||||
f->next = next;
|
||||
} else { // clients are not adjacent to each other
|
||||
next = f->next;
|
||||
f->next = s->next;
|
||||
s->next = next;
|
||||
if (fprior)
|
||||
fprior->next = s;
|
||||
else
|
||||
s->mon->clients = s;
|
||||
if (sprior)
|
||||
sprior->next = f;
|
||||
else
|
||||
f->mon->clients = f;
|
||||
}
|
||||
|
||||
arrange(f->mon);
|
||||
}
|
||||
}
|
1
dwm-flexipatch/patch/placedir.h
Normal file
1
dwm-flexipatch/patch/placedir.h
Normal file
|
@ -0,0 +1 @@
|
|||
static void placedir(const Arg *arg);
|
|
@ -149,3 +149,4 @@ togglescratch(const Arg *arg)
|
|||
spawnscratch(arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,12 +39,12 @@ persistclientstate(Client *c)
|
|||
int
|
||||
restoreclientstate(Client *c)
|
||||
{
|
||||
return getclienttags(c)
|
||||
| getclientfields(c)
|
||||
int restored = getclientfields(c);
|
||||
getclienttags(c);
|
||||
#if SAVEFLOATS_PATCH
|
||||
| restorewindowfloatposition(c, c->mon ? c->mon : selmon)
|
||||
restorewindowfloatposition(c, c->mon ? c->mon : selmon);
|
||||
#endif // SAVEFLOATS_PATCH
|
||||
;
|
||||
return restored;
|
||||
}
|
||||
|
||||
void setmonitorfields(Monitor *m)
|
||||
|
|
|
@ -6,7 +6,7 @@ shift(const Arg *arg, int clients)
|
|||
unsigned int tagmask = 0;
|
||||
|
||||
#if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH
|
||||
shifted.ui = selmon->tagset[selmon->seltags];
|
||||
shifted.ui = selmon->tagset[selmon->seltags] & ~SPTAGMASK;
|
||||
#else
|
||||
shifted.ui = selmon->tagset[selmon->seltags];
|
||||
#endif // SCRATCHPADS_PATCH
|
||||
|
@ -18,6 +18,10 @@ shift(const Arg *arg, int clients)
|
|||
for (c = selmon->clients; c && clients; c = c->next) {
|
||||
if (c == selmon->sel)
|
||||
continue;
|
||||
#if STICKY_PATCH
|
||||
if (c->issticky)
|
||||
continue;
|
||||
#endif // STICKY_PATCH
|
||||
#if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH
|
||||
if (!(c->tags & SPTAGMASK))
|
||||
tagmask |= c->tags;
|
||||
|
|
|
@ -10,8 +10,15 @@ resizemousescroll(const Arg *arg)
|
|||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
#if !FAKEFULLSCREEN_PATCH
|
||||
#if FAKEFULLSCREEN_CLIENT_PATCH
|
||||
if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
|
||||
return;
|
||||
#else
|
||||
if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
return;
|
||||
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
||||
#endif // !FAKEFULLSCREEN_PATCH
|
||||
restack(selmon);
|
||||
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Settings */
|
||||
#if !PERTAG_VANITYGAPS_PATCH
|
||||
#if !(PERTAG_VANITYGAPS_PATCH || PERMON_VANITYGAPS_PATCH)
|
||||
static int enablegaps = 1;
|
||||
#endif // PERTAG_VANITYGAPS_PATCH
|
||||
|
||||
|
@ -69,10 +69,12 @@ setgapsex(const Arg *arg)
|
|||
#if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
|
||||
if (!selmon->pertag->enablegaps[selmon->pertag->curtag])
|
||||
selmon->pertag->enablegaps[selmon->pertag->curtag] = 1;
|
||||
#elif PERMON_VANITYGAPS_PATCH
|
||||
selmon->enablegaps = 1;
|
||||
#else
|
||||
if (!enablegaps)
|
||||
enablegaps = 1;
|
||||
#endif // PERTAG_VANITYGAPS_PATCH
|
||||
#endif // PERTAG_VANITYGAPS_PATCH | PERMON_VANITYGAPS_PATCH
|
||||
|
||||
setgaps(oh, ov, ih, iv);
|
||||
}
|
||||
|
@ -83,24 +85,35 @@ togglegaps(const Arg *arg)
|
|||
{
|
||||
#if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
|
||||
selmon->pertag->enablegaps[selmon->pertag->curtag] = !selmon->pertag->enablegaps[selmon->pertag->curtag];
|
||||
#elif PERMON_VANITYGAPS_PATCH
|
||||
selmon->enablegaps = !selmon->enablegaps;
|
||||
#else
|
||||
enablegaps = !enablegaps;
|
||||
#endif // PERTAG_VANITYGAPS_PATCH
|
||||
#endif // PERTAG_VANITYGAPS_PATCH | PERMON_VANITYGAPS_PATCH
|
||||
|
||||
#if BAR_PADDING_VANITYGAPS_PATCH
|
||||
#if PERMON_VANITYGAPS_PATCH
|
||||
updatebarpos(selmon);
|
||||
for (Bar *bar = selmon->bar; bar; bar = bar->next)
|
||||
XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
|
||||
#else
|
||||
for (Monitor *m = mons; m; m = m->next) {
|
||||
updatebarpos(m);
|
||||
for (Bar *bar = m->bar; bar; bar = bar->next)
|
||||
XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
|
||||
}
|
||||
#endif // PERMON_VANITYGAPS_PATCH
|
||||
|
||||
#if BAR_SYSTRAY_PATCH
|
||||
drawbarwin(systray->bar);
|
||||
#endif // BAR_SYSTRAY_PATCH
|
||||
#endif // BAR_PADDING_VANITYGAPS_PATCH
|
||||
#if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
|
||||
|
||||
#if (PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH) || PERMON_VANITYGAPS_PATCH
|
||||
arrange(selmon);
|
||||
#else
|
||||
arrange(NULL);
|
||||
#endif // PERTAG_VANITYGAPS_PATCH
|
||||
#endif // PERTAG_VANITYGAPS_PATCH | PERMON_VANITYGAPS_PATCH
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -193,9 +206,11 @@ getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc)
|
|||
unsigned int n, oe, ie;
|
||||
#if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
|
||||
oe = ie = m->pertag->enablegaps[m->pertag->curtag];
|
||||
#elif PERMON_VANITYGAPS_PATCH
|
||||
oe = ie = m->enablegaps;
|
||||
#else
|
||||
oe = ie = enablegaps;
|
||||
#endif // PERTAG_VANITYGAPS_PATCH
|
||||
#endif // PERTAG_VANITYGAPS_PATCH | PERMON_VANITYGAPS_PATCH
|
||||
Client *c;
|
||||
|
||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
|
|
|
@ -132,6 +132,11 @@ xrdb(const Arg *arg)
|
|||
#endif // BAR_ALPHA_PATCH
|
||||
ColCount
|
||||
);
|
||||
#if BAR_SYSTRAY_PATCH && !BAR_ALPHA_PATCH
|
||||
if (systray) {
|
||||
XMoveWindow(dpy, systray->win, -32000, -32000);
|
||||
}
|
||||
#endif // BAR_SYSTRAY_PATCH
|
||||
arrange(NULL);
|
||||
focus(NULL);
|
||||
}
|
||||
|
|
|
@ -369,6 +369,12 @@
|
|||
*/
|
||||
#define BAR_PADDING_VANITYGAPS_PATCH 1
|
||||
|
||||
/* Smart bar padding patch that automatically adjusts the padding when there is
|
||||
* only one client on the monitor. Works well with vanitygaps and barpadding
|
||||
* patches.
|
||||
*/
|
||||
#define BAR_PADDING_SMART_PATCH 0
|
||||
|
||||
/* This patch adds simple markup for status messages using pango markup.
|
||||
* This depends on the pango library v1.44 or greater.
|
||||
* You need to uncomment the corresponding lines in config.mk to use the pango libraries
|
||||
|
@ -572,6 +578,18 @@
|
|||
*/
|
||||
#define DISTRIBUTETAGS_PATCH 0
|
||||
|
||||
/* By default dwm will terminate on color allocation failure and the behaviour is intended to
|
||||
* catch and inform the user of color configuration issues.
|
||||
*
|
||||
* Some patches like status2d and xresources / xrdb can change colours during runtime, which
|
||||
* means that if a color can't be allocated at this time then the window manager will abruptly
|
||||
* terminate.
|
||||
*
|
||||
* This patch will ignore color allocation failures and continue on as normal. The effect of
|
||||
* this is that the existing color, that was supposed to be replaced, will remain as-is.
|
||||
*/
|
||||
#define DO_NOT_DIE_ON_COLOR_ALLOCATION_FAILURE_PATCH 1
|
||||
|
||||
/* Similarly to the dragmfact patch this allows you to click and drag clients to change the
|
||||
* cfact to adjust the client's size in the stack. This patch depends on the cfacts patch.
|
||||
*/
|
||||
|
@ -657,6 +675,12 @@
|
|||
*/
|
||||
#define FOCUSMASTER_PATCH 0
|
||||
|
||||
/* A variant of the focusmaster patch that additionally allows the focus to be returned to the
|
||||
* previously focused client
|
||||
* https://dwm.suckless.org/patches/focusmaster/
|
||||
*/
|
||||
#define FOCUSMASTER_RETURN_PATCH 0
|
||||
|
||||
/* Switch focus only by mouse click and not sloppy (focus follows mouse pointer).
|
||||
* https://dwm.suckless.org/patches/focusonclick/
|
||||
*/
|
||||
|
@ -885,11 +909,22 @@
|
|||
*/
|
||||
#define PERTAG_VANITYGAPS_PATCH 0
|
||||
|
||||
/* This patch allows configuring vanity gaps on a per-monitor basis rather than
|
||||
* all monitors (default).
|
||||
*/
|
||||
#define PERMON_VANITYGAPS_PATCH 0
|
||||
|
||||
/* This controls whether or not to also store bar position on a per
|
||||
* tag basis, or leave it as one bar per monitor.
|
||||
*/
|
||||
#define PERTAGBAR_PATCH 0
|
||||
|
||||
/* Similar to the focusdir patch this patch allow users to move a window in any direction
|
||||
* in the tiled stack (up, down, left, right).
|
||||
* https://github.com/bakkeby/patches/wiki/placedir
|
||||
*/
|
||||
#define PLACEDIR_PATCH 0
|
||||
|
||||
/* This patch lets you change the position of a client in the stack using the mouse.
|
||||
* https://github.com/bakkeby/patches/wiki/placemouse
|
||||
*/
|
||||
|
@ -1022,6 +1057,11 @@
|
|||
*/
|
||||
#define SELFRESTART_PATCH 1
|
||||
|
||||
/* Floating windows being sent to another monitor will be centered.
|
||||
* https://dwm.suckless.org/patches/sendmoncenter/
|
||||
*/
|
||||
#define SENDMON_CENTER_PATCH 0
|
||||
|
||||
/* This patch allow clients to keep focus when being sent to another monitor.
|
||||
* https://github.com/bakkeby/patches/blob/master/dwm/dwm-sendmon_keepfocus-6.2.diff
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
InsertBraces: true
|
||||
ColumnLimit: 79
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveMacros: true
|
||||
AlignConsecutiveMacros: Consecutive
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
|
|
30
dwmblocks-async/.clang-tidy
Normal file
30
dwmblocks-async/.clang-tidy
Normal file
|
@ -0,0 +1,30 @@
|
|||
Checks: |
|
||||
-*,
|
||||
abseil-*,
|
||||
bugprone-*,
|
||||
clang-analyzer-*,
|
||||
misc-*,
|
||||
modernize-*,
|
||||
performance-*,
|
||||
portability-*,
|
||||
readability-*,
|
||||
llvm-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-readability-avoid-const-params-in-decls,
|
||||
-readability-identifier-length
|
||||
|
||||
CheckOptions:
|
||||
- key: readability-inconsistent-declaration-parameter-name.Strict
|
||||
value: true
|
||||
- key: readability-identifier-naming.StructCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.FunctionCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.VariableCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.EnumConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.MacroDefinitionCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-function-cognitive-complexity.Threshold
|
||||
value: 15
|
|
@ -1,6 +1,5 @@
|
|||
CompileFlags:
|
||||
Add:
|
||||
- "-I."
|
||||
- "-I./inc"
|
||||
- "-I.."
|
||||
- "-I../inc"
|
||||
Diagnostics:
|
||||
UnusedIncludes: Strict
|
||||
MissingIncludes: Strict
|
||||
Includes:
|
||||
IgnoreHeader: bits/getopt_core.h
|
||||
|
|
2
dwmblocks-async/.gitignore
vendored
2
dwmblocks-async/.gitignore
vendored
|
@ -1,3 +1,3 @@
|
|||
build/
|
||||
.cache/
|
||||
dwmblocks
|
||||
compile_commands.json
|
||||
|
|
|
@ -3,19 +3,22 @@
|
|||
BIN := dwmblocks
|
||||
BUILD_DIR := build
|
||||
SRC_DIR := src
|
||||
INC_DIR := inc
|
||||
INC_DIR := include
|
||||
CC=cc
|
||||
|
||||
DEBUG := 0
|
||||
VERBOSE := 0
|
||||
LIBS := xcb-atom
|
||||
|
||||
PREFIX := /usr/local
|
||||
CC = cc
|
||||
CFLAGS := -Wall -Wextra -Ofast -I. -I$(INC_DIR)
|
||||
CFLAGS += -Wall -Wextra -Wno-missing-field-initializers
|
||||
LDLIBS := -lX11
|
||||
CFLAGS := -Ofast -I. -I$(INC_DIR) -std=c99
|
||||
CFLAGS += -DBINARY=\"$(BIN)\" -D_POSIX_C_SOURCE=200809L
|
||||
CFLAGS += -Wall -Wpedantic -Wextra -Wswitch-enum
|
||||
CFLAGS += $(shell pkg-config --cflags $(LIBS))
|
||||
LDLIBS := $(shell pkg-config --libs $(LIBS))
|
||||
|
||||
VPATH := $(SRC_DIR)
|
||||
OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(wildcard $(SRC_DIR)/*.c))
|
||||
OBJS += $(patsubst %.c,$(BUILD_DIR)/%.o,$(wildcard *.c))
|
||||
SRCS := $(wildcard $(SRC_DIR)/*.c)
|
||||
OBJS := $(subst $(SRC_DIR)/,$(BUILD_DIR)/,$(SRCS:.c=.o))
|
||||
|
||||
INSTALL_DIR := $(DESTDIR)$(PREFIX)/bin
|
||||
|
||||
|
@ -25,20 +28,21 @@ ifeq ($(VERBOSE), 0)
|
|||
Q := @
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -g
|
||||
endif
|
||||
|
||||
all: $(BUILD_DIR)/$(BIN)
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c config.h
|
||||
$Qmkdir -p $(@D)
|
||||
$(PRINTF) "CC" $@
|
||||
$Q$(COMPILE.c) -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/$(BIN): $(OBJS)
|
||||
$(PRINTF) "LD" $@
|
||||
$Q$(LINK.o) $^ $(LDLIBS) -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: %.c config.h | $(BUILD_DIR)
|
||||
$(PRINTF) "CC" $@
|
||||
$Q$(COMPILE.c) -o $@ $<
|
||||
|
||||
$(BUILD_DIR):
|
||||
$(PRINTF) "MKDIR" $@
|
||||
$Qmkdir -p $@
|
||||
|
||||
clean:
|
||||
$(PRINTF) "CLEAN" $(BUILD_DIR)
|
||||
$Q$(RM) $(BUILD_DIR)/*
|
||||
|
|
|
@ -85,21 +85,21 @@ dwmblocks &
|
|||
|
||||
### Modifying the blocks
|
||||
|
||||
You can define your status bar blocks in `config.c`:
|
||||
You can define your status bar blocks in `config.h`:
|
||||
|
||||
```c
|
||||
Block blocks[] = {
|
||||
#define BLOCKS(X) \
|
||||
...
|
||||
{"volume", 0, 5},
|
||||
{"date", 1800, 1},
|
||||
X(" ", "wpctl get-volume @DEFAULT_AUDIO_SINK@ | cut -d' ' -f2", 0, 5) \
|
||||
X(" ", "date '+%H:%M:%S'", 1, 1) \
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Each block has the following properties:
|
||||
|
||||
| Property | Description |
|
||||
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Icon | An icon you wish to prepend to your block output. |
|
||||
| Command | The command you wish to execute in your block. |
|
||||
| Update interval | Time in seconds, after which you want the block to update. If `0`, the block will never be updated. |
|
||||
| Update signal | Signal to be used for triggering the block. Must be a positive integer. If `0`, a signal won't be set up for the block and it will be unclickable. |
|
||||
|
@ -107,17 +107,20 @@ Each block has the following properties:
|
|||
Apart from defining the blocks, features can be toggled through `config.h`:
|
||||
|
||||
```c
|
||||
// Maximum possible length of output from block, expressed in number of characters.
|
||||
#define CMDLENGTH 50
|
||||
|
||||
// The status bar's delimiter that appears in between each block.
|
||||
// String used to delimit block outputs in the status.
|
||||
#define DELIMITER " "
|
||||
|
||||
// Adds a leading delimiter to the status bar, useful for powerline.
|
||||
#define LEADING_DELIMITER 1
|
||||
// Maximum number of Unicode characters that a block can output.
|
||||
#define MAX_BLOCK_OUTPUT_LENGTH 45
|
||||
|
||||
// Enable clickability for blocks. See the "Clickable blocks" section below.
|
||||
// Control whether blocks are clickable.
|
||||
#define CLICKABLE_BLOCKS 1
|
||||
|
||||
// Control whether a leading delimiter should be prepended to the status.
|
||||
#define LEADING_DELIMITER 0
|
||||
|
||||
// Control whether a trailing delimiter should be appended to the status.
|
||||
#define TRAILING_DELIMITER 0
|
||||
```
|
||||
|
||||
### Signalling changes
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "block.h"
|
||||
#include "util.h"
|
||||
|
||||
Block blocks[] = {
|
||||
{"sb-forecast", 900, 1 },
|
||||
{"sb-disk", 1800, 2 },
|
||||
{"sb-memory", 10, 3 },
|
||||
{"sb-loadavg", 5, 4 },
|
||||
{"sb-music", 1, 5 },
|
||||
{"sb-volume", 1, 6 },
|
||||
{"sb-date", 1, 7 },
|
||||
{"sb-user", 0, 8 },
|
||||
};
|
||||
|
||||
const unsigned short blockCount = LEN(blocks);
|
|
@ -1,6 +1,29 @@
|
|||
#pragma once
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#define CLICKABLE_BLOCKS 1 // Enable clickability for blocks
|
||||
#define CMDLENGTH 45 // Trim block output to this length
|
||||
#define DELIMITER " " // Delimiter string used to separate blocks
|
||||
#define LEADING_DELIMITER 0 // Whether a leading separator should be used
|
||||
// String used to delimit block outputs in the status.
|
||||
#define DELIMITER " "
|
||||
|
||||
// Maximum number of Unicode characters that a block can output.
|
||||
#define MAX_BLOCK_OUTPUT_LENGTH 45
|
||||
|
||||
// Control whether blocks are clickable.
|
||||
#define CLICKABLE_BLOCKS 1
|
||||
|
||||
// Control whether a leading delimiter should be prepended to the status.
|
||||
#define LEADING_DELIMITER 0
|
||||
|
||||
// Control whether a trailing delimiter should be appended to the status.
|
||||
#define TRAILING_DELIMITER 0
|
||||
|
||||
// Define blocks for the status feed as X(icon, cmd, interval, signal).
|
||||
#define BLOCKS(X) \
|
||||
X("", "sb-forecast", 900, 1) \
|
||||
X("", "sb-disk", 1800, 2) \
|
||||
X("", "sb-memory", 10, 3) \
|
||||
X("", "sb-loadavg", 5, 4) \
|
||||
X("", "sb-music", 1, 5) \
|
||||
X("", "sb-volume", 1, 6) \
|
||||
X("", "sb-date", 1, 7) \
|
||||
X("", "sb-user", 0, 8)
|
||||
#endif // CONFIG_H
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
#include "block.h"
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct {
|
||||
char *current;
|
||||
char *previous;
|
||||
} BarStatus;
|
||||
|
||||
extern unsigned short debugMode;
|
||||
|
||||
void initStatus(BarStatus *);
|
||||
void freeStatus(BarStatus *);
|
||||
void writeStatus(BarStatus *);
|
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
#include "config.h"
|
||||
|
||||
typedef struct {
|
||||
const char *command;
|
||||
const unsigned int interval;
|
||||
const unsigned int signal;
|
||||
int pipe[2];
|
||||
char output[CMDLENGTH * 4 + 1];
|
||||
} Block;
|
||||
|
||||
extern Block blocks[];
|
||||
extern const unsigned short blockCount;
|
||||
|
||||
void execBlock(const Block *, const char *);
|
||||
void execBlocks(unsigned int);
|
||||
void updateBlock(Block *);
|
|
@ -1,8 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
#define MAX(a, b) (a > b ? a : b)
|
||||
|
||||
int gcd(int, int);
|
||||
void closePipe(int[2]);
|
||||
void trimUTF8(char*, unsigned int);
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
int setupX();
|
||||
int closeX();
|
||||
void setXRootName(char *);
|
29
dwmblocks-async/include/block.h
Normal file
29
dwmblocks-async/include/block.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef BLOCK_H
|
||||
#define BLOCK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct {
|
||||
const char *const icon;
|
||||
const char *const command;
|
||||
const unsigned int interval;
|
||||
const int signal;
|
||||
|
||||
int pipe[PIPE_FD_COUNT];
|
||||
char output[MAX_BLOCK_OUTPUT_LENGTH * UTF8_MAX_BYTE_COUNT + 1];
|
||||
pid_t fork_pid;
|
||||
} block;
|
||||
|
||||
block block_new(const char *const icon, const char *const command,
|
||||
const unsigned int interval, const int signal);
|
||||
int block_init(block *const block);
|
||||
int block_deinit(block *const block);
|
||||
int block_execute(block *const block, const uint8_t button);
|
||||
int block_update(block *const block);
|
||||
|
||||
#endif // BLOCK_H
|
12
dwmblocks-async/include/cli.h
Normal file
12
dwmblocks-async/include/cli.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef CLI_H
|
||||
#define CLI_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
bool is_debug_mode;
|
||||
} cli_arguments;
|
||||
|
||||
cli_arguments cli_parse_arguments(const char* const argv[], const int argc);
|
||||
|
||||
#endif // CLI_H
|
16
dwmblocks-async/include/main.h
Normal file
16
dwmblocks-async/include/main.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
#define REFRESH_SIGNAL SIGUSR1
|
||||
|
||||
// Utilise C's adjacent string concatenation to count the number of blocks.
|
||||
#define X(...) "."
|
||||
enum { BLOCK_COUNT = LEN(BLOCKS(X)) - 1 };
|
||||
#undef X
|
||||
|
||||
#endif // MAIN_H
|
33
dwmblocks-async/include/signal-handler.h
Normal file
33
dwmblocks-async/include/signal-handler.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef SIGNAL_HANDLER_H
|
||||
#define SIGNAL_HANDLER_H
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "timer.h"
|
||||
|
||||
typedef sigset_t signal_set;
|
||||
typedef int (*signal_refresh_callback)(block* const blocks,
|
||||
const unsigned short block_count);
|
||||
typedef int (*signal_timer_callback)(block* const blocks,
|
||||
const unsigned short block_code,
|
||||
timer* const timer);
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
const signal_refresh_callback refresh_callback;
|
||||
const signal_timer_callback timer_callback;
|
||||
|
||||
block* const blocks;
|
||||
const unsigned short block_count;
|
||||
} signal_handler;
|
||||
|
||||
signal_handler signal_handler_new(
|
||||
block* const blocks, const unsigned short block_count,
|
||||
const signal_refresh_callback refresh_callback,
|
||||
const signal_timer_callback timer_callback);
|
||||
int signal_handler_init(signal_handler* const handler);
|
||||
int signal_handler_deinit(signal_handler* const handler);
|
||||
int signal_handler_process(signal_handler* const handler, timer* const timer);
|
||||
|
||||
#endif // SIGNAL_HANDLER_H
|
31
dwmblocks-async/include/status.h
Normal file
31
dwmblocks-async/include/status.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef STATUS_H
|
||||
#define STATUS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "config.h"
|
||||
#include "main.h"
|
||||
#include "util.h"
|
||||
#include "x11.h"
|
||||
|
||||
typedef struct {
|
||||
#define STATUS_LENGTH \
|
||||
((BLOCK_COUNT * (MEMBER_LENGTH(block, output) - 1) + CLICKABLE_BLOCKS) + \
|
||||
(BLOCK_COUNT - 1 + LEADING_DELIMITER + TRAILING_DELIMITER) * \
|
||||
(LEN(DELIMITER) - 1) + \
|
||||
1)
|
||||
char current[STATUS_LENGTH];
|
||||
char previous[STATUS_LENGTH];
|
||||
#undef STATUS_LENGTH
|
||||
|
||||
const block* const blocks;
|
||||
const unsigned short block_count;
|
||||
} status;
|
||||
|
||||
status status_new(const block* const blocks, const unsigned short block_count);
|
||||
bool status_update(status* const status);
|
||||
int status_write(const status* const status, const bool is_debug_mode,
|
||||
x11_connection* const connection);
|
||||
|
||||
#endif // STATUS_H
|
21
dwmblocks-async/include/timer.h
Normal file
21
dwmblocks-async/include/timer.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "block.h"
|
||||
|
||||
#define TIMER_SIGNAL SIGALRM
|
||||
|
||||
typedef struct {
|
||||
unsigned int time;
|
||||
const unsigned int tick;
|
||||
const unsigned int reset_value;
|
||||
} timer;
|
||||
|
||||
timer timer_new(const block *const blocks, const unsigned short block_count);
|
||||
int timer_arm(timer *const timer);
|
||||
bool timer_must_run_block(const timer *const timer, const block *const block);
|
||||
|
||||
#endif // TIMER_H
|
28
dwmblocks-async/include/util.h
Normal file
28
dwmblocks-async/include/util.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#define BIT(n) (1 << (n))
|
||||
|
||||
// NOLINTBEGIN(bugprone-macro-parentheses)
|
||||
#define MEMBER_SIZE(type, member) sizeof(((type*)NULL)->member)
|
||||
#define MEMBER_LENGTH(type, member) \
|
||||
(MEMBER_SIZE(type, member) / MEMBER_SIZE(type, member[0]))
|
||||
// NOLINTEND(bugprone-macro-parentheses)
|
||||
|
||||
#define UTF8_MAX_BYTE_COUNT 4
|
||||
|
||||
enum pipe_fd_index {
|
||||
READ_END,
|
||||
WRITE_END,
|
||||
PIPE_FD_COUNT,
|
||||
};
|
||||
|
||||
unsigned int gcd(unsigned int a, unsigned int b);
|
||||
size_t truncate_utf8_string(char* const buffer, const size_t size,
|
||||
const size_t char_limit);
|
||||
|
||||
#endif // UTIL_H
|
28
dwmblocks-async/include/watcher.h
Normal file
28
dwmblocks-async/include/watcher.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef WATCHER_H
|
||||
#define WATCHER_H
|
||||
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "main.h"
|
||||
|
||||
enum watcher_fd_index {
|
||||
SIGNAL_FD = BLOCK_COUNT,
|
||||
WATCHER_FD_COUNT,
|
||||
};
|
||||
|
||||
typedef struct pollfd watcher_fd;
|
||||
|
||||
typedef struct {
|
||||
watcher_fd fds[WATCHER_FD_COUNT];
|
||||
unsigned short active_blocks[BLOCK_COUNT];
|
||||
unsigned short active_block_count;
|
||||
bool got_signal;
|
||||
} watcher;
|
||||
|
||||
int watcher_init(watcher *const watcher, const block *const blocks,
|
||||
const unsigned short block_count, const int signal_fd);
|
||||
int watcher_poll(watcher *const watcher, const int timeout_ms);
|
||||
|
||||
#endif // WATCHER_H
|
13
dwmblocks-async/include/x11.h
Normal file
13
dwmblocks-async/include/x11.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef X11_H
|
||||
#define X11_H
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
typedef xcb_connection_t x11_connection;
|
||||
|
||||
x11_connection* x11_connection_open(void);
|
||||
void x11_connection_close(x11_connection* const connection);
|
||||
int x11_set_root_name(x11_connection* const connection,
|
||||
const char* const name);
|
||||
|
||||
#endif // X11_H
|
|
@ -1,62 +0,0 @@
|
|||
#include "bar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "x11.h"
|
||||
|
||||
void initStatus(BarStatus *status) {
|
||||
const unsigned int statusLength =
|
||||
(blockCount * (LEN(blocks[0].output) - 1)) +
|
||||
(blockCount - 1 + LEADING_DELIMITER) * (LEN(DELIMITER) - 1);
|
||||
|
||||
status->current = (char *)malloc(statusLength);
|
||||
status->previous = (char *)malloc(statusLength);
|
||||
status->current[0] = '\0';
|
||||
status->previous[0] = '\0';
|
||||
}
|
||||
|
||||
void freeStatus(BarStatus *status) {
|
||||
free(status->current);
|
||||
free(status->previous);
|
||||
}
|
||||
|
||||
int updateStatus(BarStatus *status) {
|
||||
strcpy(status->previous, status->current);
|
||||
status->current[0] = '\0';
|
||||
|
||||
for (int i = 0; i < blockCount; i++) {
|
||||
Block *block = blocks + i;
|
||||
|
||||
if (strlen(block->output)) {
|
||||
#if LEADING_DELIMITER
|
||||
strcat(status->current, DELIMITER);
|
||||
#else
|
||||
if (status->current[0]) strcat(status->current, DELIMITER);
|
||||
#endif
|
||||
|
||||
#if CLICKABLE_BLOCKS
|
||||
if (!debugMode && block->signal) {
|
||||
char signal[] = {block->signal, '\0'};
|
||||
strcat(status->current, signal);
|
||||
}
|
||||
#endif
|
||||
|
||||
strcat(status->current, block->output);
|
||||
}
|
||||
}
|
||||
return strcmp(status->current, status->previous);
|
||||
}
|
||||
|
||||
void writeStatus(BarStatus *status) {
|
||||
// Only write out if status has changed
|
||||
if (!updateStatus(status)) return;
|
||||
|
||||
if (debugMode) {
|
||||
printf("%s\n", status->current);
|
||||
return;
|
||||
}
|
||||
setXRootName(status->current);
|
||||
}
|
|
@ -1,72 +1,147 @@
|
|||
#include "block.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
static int execLock = 0;
|
||||
block block_new(const char *const icon, const char *const command,
|
||||
const unsigned int interval, const int signal) {
|
||||
block block = {
|
||||
.icon = icon,
|
||||
.command = command,
|
||||
.interval = interval,
|
||||
.signal = signal,
|
||||
|
||||
void execBlock(const Block *block, const char *button) {
|
||||
unsigned short i = block - blocks;
|
||||
.output = {[0] = '\0'},
|
||||
.fork_pid = -1,
|
||||
};
|
||||
|
||||
// Ensure only one child process exists per block at an instance
|
||||
if (execLock & 1 << i) return;
|
||||
// Lock execution of block until current instance finishes execution
|
||||
execLock |= 1 << i;
|
||||
return block;
|
||||
}
|
||||
|
||||
if (fork() == 0) {
|
||||
close(block->pipe[0]);
|
||||
dup2(block->pipe[1], STDOUT_FILENO);
|
||||
close(block->pipe[1]);
|
||||
int block_init(block *const block) {
|
||||
if (pipe(block->pipe) != 0) {
|
||||
(void)fprintf(stderr,
|
||||
"error: could not create a pipe for \"%s\" block\n",
|
||||
block->command);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (button) setenv("BLOCK_BUTTON", button, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *file = popen(block->command, "r");
|
||||
if (!file) {
|
||||
printf("\n");
|
||||
int block_deinit(block *const block) {
|
||||
int status = close(block->pipe[READ_END]);
|
||||
status |= close(block->pipe[WRITE_END]);
|
||||
if (status != 0) {
|
||||
(void)fprintf(stderr, "error: could not close \"%s\" block's pipe\n",
|
||||
block->command);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int block_execute(block *const block, const uint8_t button) {
|
||||
// Ensure only one child process exists per block at an instance.
|
||||
if (block->fork_pid != -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
block->fork_pid = fork();
|
||||
if (block->fork_pid == -1) {
|
||||
(void)fprintf(
|
||||
stderr, "error: could not create a subprocess for \"%s\" block\n",
|
||||
block->command);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (block->fork_pid == 0) {
|
||||
const int write_fd = block->pipe[WRITE_END];
|
||||
int status = close(block->pipe[READ_END]);
|
||||
|
||||
if (button != 0) {
|
||||
char button_str[4];
|
||||
(void)snprintf(button_str, LEN(button_str), "%hhu", button);
|
||||
status |= setenv("BLOCK_BUTTON", button_str, 1);
|
||||
}
|
||||
|
||||
const char null = '\0';
|
||||
if (status != 0) {
|
||||
(void)write(write_fd, &null, sizeof(null));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Buffer will hold both '\n' and '\0'
|
||||
char buffer[LEN(block->output) + 1];
|
||||
if (fgets(buffer, LEN(buffer), file) == NULL) {
|
||||
// Send an empty line in case of no output
|
||||
printf("\n");
|
||||
FILE *const file = popen(block->command, "r");
|
||||
if (file == NULL) {
|
||||
(void)write(write_fd, &null, sizeof(null));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Ensure null-termination since fgets() will leave buffer untouched on
|
||||
// no output.
|
||||
char buffer[LEN(block->output)] = {[0] = null};
|
||||
(void)fgets(buffer, LEN(buffer), file);
|
||||
|
||||
// Remove trailing newlines.
|
||||
const size_t length = strcspn(buffer, "\n");
|
||||
buffer[length] = null;
|
||||
|
||||
// Exit if command execution failed or if file could not be closed.
|
||||
if (pclose(file) != 0) {
|
||||
(void)write(write_fd, &null, sizeof(null));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const size_t output_size =
|
||||
truncate_utf8_string(buffer, LEN(buffer), MAX_BLOCK_OUTPUT_LENGTH);
|
||||
(void)write(write_fd, buffer, output_size);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
pclose(file);
|
||||
|
||||
// Trim to the max possible UTF-8 capacity
|
||||
trimUTF8(buffer, LEN(buffer));
|
||||
|
||||
printf("%s\n", buffer);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void execBlocks(unsigned int time) {
|
||||
for (int i = 0; i < blockCount; i++) {
|
||||
const Block *block = blocks + i;
|
||||
if (time == 0 ||
|
||||
(block->interval != 0 && time % block->interval == 0)) {
|
||||
execBlock(block, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateBlock(Block *block) {
|
||||
int block_update(block *const block) {
|
||||
char buffer[LEN(block->output)];
|
||||
int bytesRead = read(block->pipe[0], buffer, LEN(buffer));
|
||||
|
||||
// String from pipe will always end with '\n'
|
||||
buffer[bytesRead - 1] = '\0';
|
||||
const ssize_t bytes_read =
|
||||
read(block->pipe[READ_END], buffer, LEN(buffer));
|
||||
if (bytes_read == -1) {
|
||||
(void)fprintf(stderr,
|
||||
"error: could not fetch output of \"%s\" block\n",
|
||||
block->command);
|
||||
return 2;
|
||||
}
|
||||
|
||||
strcpy(block->output, buffer);
|
||||
// Collect exit-status of the subprocess to avoid zombification.
|
||||
int fork_status = 0;
|
||||
if (waitpid(block->fork_pid, &fork_status, 0) == -1) {
|
||||
(void)fprintf(stderr,
|
||||
"error: could not obtain exit status for \"%s\" block\n",
|
||||
block->command);
|
||||
return 2;
|
||||
}
|
||||
block->fork_pid = -1;
|
||||
|
||||
// Remove execution lock for the current block
|
||||
execLock &= ~(1 << (block - blocks));
|
||||
if (fork_status != 0) {
|
||||
(void)fprintf(stderr,
|
||||
"error: \"%s\" block exited with non-zero status\n",
|
||||
block->command);
|
||||
return 1;
|
||||
}
|
||||
|
||||
(void)strncpy(block->output, buffer, LEN(buffer));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
33
dwmblocks-async/src/cli.c
Normal file
33
dwmblocks-async/src/cli.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "cli.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
cli_arguments cli_parse_arguments(const char *const argv[], const int argc) {
|
||||
errno = 0;
|
||||
cli_arguments args = {
|
||||
.is_debug_mode = false,
|
||||
};
|
||||
|
||||
int opt = -1;
|
||||
opterr = 0; // Suppress getopt's built-in invalid opt message
|
||||
while ((opt = getopt(argc, (char *const *)argv, "dh")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
args.is_debug_mode = true;
|
||||
break;
|
||||
case '?':
|
||||
(void)fprintf(stderr, "error: unknown option `-%c'\n", optopt);
|
||||
// fall through
|
||||
case 'h':
|
||||
// fall through
|
||||
default:
|
||||
(void)fprintf(stderr, "usage: %s [-d]\n", BINARY);
|
||||
errno = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
|
@ -1,157 +1,168 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include "main.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "bar.h"
|
||||
#include "block.h"
|
||||
#include "cli.h"
|
||||
#include "config.h"
|
||||
#include "signal-handler.h"
|
||||
#include "status.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
#include "watcher.h"
|
||||
#include "x11.h"
|
||||
|
||||
static unsigned short statusContinue = 1;
|
||||
unsigned short debugMode = 0;
|
||||
static int epollFD, signalFD;
|
||||
static unsigned int timerTick = 0, maxInterval = 1;
|
||||
|
||||
void signalHandler() {
|
||||
struct signalfd_siginfo info;
|
||||
read(signalFD, &info, sizeof(info));
|
||||
unsigned int signal = info.ssi_signo;
|
||||
|
||||
static unsigned int timer = 0;
|
||||
switch (signal) {
|
||||
case SIGALRM:
|
||||
// Schedule the next timer event and execute blocks
|
||||
alarm(timerTick);
|
||||
execBlocks(timer);
|
||||
|
||||
// Wrap `timer` to the interval [1, `maxInterval`]
|
||||
timer = (timer + timerTick - 1) % maxInterval + 1;
|
||||
return;
|
||||
case SIGUSR1:
|
||||
// Update all blocks on receiving SIGUSR1
|
||||
execBlocks(0);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int j = 0; j < blockCount; j++) {
|
||||
const Block *block = blocks + j;
|
||||
if (block->signal == signal - SIGRTMIN) {
|
||||
char button[4]; // value can't be more than 255;
|
||||
sprintf(button, "%d", info.ssi_int & 0xff);
|
||||
execBlock(block, button);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void termHandler() {
|
||||
statusContinue = 0;
|
||||
}
|
||||
|
||||
void setupSignals() {
|
||||
sigset_t handledSignals;
|
||||
sigemptyset(&handledSignals);
|
||||
sigaddset(&handledSignals, SIGUSR1);
|
||||
sigaddset(&handledSignals, SIGALRM);
|
||||
|
||||
// Append all block signals to `handledSignals`
|
||||
for (int i = 0; i < blockCount; i++)
|
||||
if (blocks[i].signal > 0)
|
||||
sigaddset(&handledSignals, SIGRTMIN + blocks[i].signal);
|
||||
|
||||
// Create a signal file descriptor for epoll to watch
|
||||
signalFD = signalfd(-1, &handledSignals, 0);
|
||||
|
||||
// Block all realtime and handled signals
|
||||
for (int i = SIGRTMIN; i <= SIGRTMAX; i++) sigaddset(&handledSignals, i);
|
||||
sigprocmask(SIG_BLOCK, &handledSignals, NULL);
|
||||
|
||||
// Handle termination signals
|
||||
signal(SIGINT, termHandler);
|
||||
signal(SIGTERM, termHandler);
|
||||
|
||||
// Avoid zombie subprocesses
|
||||
struct sigaction signalAction;
|
||||
signalAction.sa_handler = SIG_DFL;
|
||||
sigemptyset(&signalAction.sa_mask);
|
||||
signalAction.sa_flags = SA_NOCLDWAIT;
|
||||
sigaction(SIGCHLD, &signalAction, 0);
|
||||
}
|
||||
|
||||
void statusLoop() {
|
||||
// Update all blocks initially
|
||||
raise(SIGALRM);
|
||||
|
||||
BarStatus status;
|
||||
initStatus(&status);
|
||||
struct epoll_event events[blockCount + 1];
|
||||
while (statusContinue) {
|
||||
int eventCount = epoll_wait(epollFD, events, LEN(events), 100);
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
unsigned short id = events[i].data.u32;
|
||||
if (id < blockCount) {
|
||||
updateBlock(blocks + id);
|
||||
} else {
|
||||
signalHandler();
|
||||
}
|
||||
}
|
||||
|
||||
if (eventCount != -1) writeStatus(&status);
|
||||
}
|
||||
freeStatus(&status);
|
||||
}
|
||||
|
||||
void init() {
|
||||
epollFD = epoll_create(blockCount);
|
||||
struct epoll_event event = {
|
||||
.events = EPOLLIN,
|
||||
};
|
||||
|
||||
for (int i = 0; i < blockCount; i++) {
|
||||
// Append each block's pipe's read end to `epollFD`
|
||||
pipe(blocks[i].pipe);
|
||||
event.data.u32 = i;
|
||||
epoll_ctl(epollFD, EPOLL_CTL_ADD, blocks[i].pipe[0], &event);
|
||||
|
||||
// Calculate the max interval and tick size for the timer
|
||||
if (blocks[i].interval) {
|
||||
maxInterval = MAX(blocks[i].interval, maxInterval);
|
||||
timerTick = gcd(blocks[i].interval, timerTick);
|
||||
}
|
||||
}
|
||||
|
||||
setupSignals();
|
||||
|
||||
// Watch signal file descriptor as well
|
||||
event.data.u32 = blockCount;
|
||||
epoll_ctl(epollFD, EPOLL_CTL_ADD, signalFD, &event);
|
||||
}
|
||||
|
||||
int main(const int argc, const char *argv[]) {
|
||||
if (setupX()) {
|
||||
fprintf(stderr, "%s\n", "dwmblocks: Failed to open display");
|
||||
static int init_blocks(block *const blocks, const unsigned short block_count) {
|
||||
for (unsigned short i = 0; i < block_count; ++i) {
|
||||
block *const block = &blocks[i];
|
||||
if (block_init(block) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (!strcmp("-d", argv[i])) {
|
||||
debugMode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
statusLoop();
|
||||
|
||||
if (closeX())
|
||||
fprintf(stderr, "%s\n", "dwmblocks: Failed to close display");
|
||||
|
||||
close(epollFD);
|
||||
close(signalFD);
|
||||
for (int i = 0; i < blockCount; i++) closePipe(blocks[i].pipe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deinit_blocks(block *const blocks,
|
||||
const unsigned short block_count) {
|
||||
for (unsigned short i = 0; i < block_count; ++i) {
|
||||
block *const block = &blocks[i];
|
||||
if (block_deinit(block) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int execute_blocks(block *const blocks,
|
||||
const unsigned short block_count,
|
||||
const timer *const timer) {
|
||||
for (unsigned short i = 0; i < block_count; ++i) {
|
||||
block *const block = &blocks[i];
|
||||
if (!timer_must_run_block(timer, block)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (block_execute(&blocks[i], 0) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trigger_event(block *const blocks, const unsigned short block_count,
|
||||
timer *const timer) {
|
||||
if (execute_blocks(blocks, block_count, timer) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (timer_arm(timer) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int refresh_callback(block *const blocks,
|
||||
const unsigned short block_count) {
|
||||
if (execute_blocks(blocks, block_count, NULL) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int event_loop(block *const blocks, const unsigned short block_count,
|
||||
const bool is_debug_mode,
|
||||
x11_connection *const connection,
|
||||
signal_handler *const signal_handler) {
|
||||
timer timer = timer_new(blocks, block_count);
|
||||
|
||||
// Kickstart the event loop with an initial execution.
|
||||
if (trigger_event(blocks, block_count, &timer) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
watcher watcher;
|
||||
if (watcher_init(&watcher, blocks, block_count, signal_handler->fd) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
status status = status_new(blocks, block_count);
|
||||
bool is_alive = true;
|
||||
while (is_alive) {
|
||||
if (watcher_poll(&watcher, -1) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (watcher.got_signal) {
|
||||
is_alive = signal_handler_process(signal_handler, &timer) == 0;
|
||||
}
|
||||
|
||||
for (unsigned short i = 0; i < watcher.active_block_count; ++i) {
|
||||
(void)block_update(&blocks[watcher.active_blocks[i]]);
|
||||
}
|
||||
|
||||
const bool has_status_changed = status_update(&status);
|
||||
if (has_status_changed &&
|
||||
status_write(&status, is_debug_mode, connection) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(const int argc, const char *const argv[]) {
|
||||
const cli_arguments cli_args = cli_parse_arguments(argv, argc);
|
||||
if (errno != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
x11_connection *const connection = x11_connection_open();
|
||||
if (connection == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define BLOCK(icon, command, interval, signal) \
|
||||
block_new(icon, command, interval, signal),
|
||||
block blocks[BLOCK_COUNT] = {BLOCKS(BLOCK)};
|
||||
#undef BLOCK
|
||||
const unsigned short block_count = LEN(blocks);
|
||||
|
||||
int status = 0;
|
||||
if (init_blocks(blocks, block_count) != 0) {
|
||||
status = 1;
|
||||
goto x11_close;
|
||||
}
|
||||
|
||||
signal_handler signal_handler = signal_handler_new(
|
||||
blocks, block_count, refresh_callback, trigger_event);
|
||||
if (signal_handler_init(&signal_handler) != 0) {
|
||||
status = 1;
|
||||
goto deinit_blocks;
|
||||
}
|
||||
|
||||
if (event_loop(blocks, block_count, cli_args.is_debug_mode, connection,
|
||||
&signal_handler) != 0) {
|
||||
status = 1;
|
||||
}
|
||||
|
||||
if (signal_handler_deinit(&signal_handler) != 0) {
|
||||
status = 1;
|
||||
}
|
||||
|
||||
deinit_blocks:
|
||||
if (deinit_blocks(blocks, block_count) != 0) {
|
||||
status = 1;
|
||||
}
|
||||
|
||||
x11_close:
|
||||
x11_connection_close(connection);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
124
dwmblocks-async/src/signal-handler.c
Normal file
124
dwmblocks-async/src/signal-handler.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include "signal-handler.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "main.h"
|
||||
#include "timer.h"
|
||||
|
||||
typedef struct signalfd_siginfo signal_info;
|
||||
|
||||
signal_handler signal_handler_new(
|
||||
block *const blocks, const unsigned short block_count,
|
||||
const signal_refresh_callback refresh_callback,
|
||||
const signal_timer_callback timer_callback) {
|
||||
signal_handler handler = {
|
||||
.refresh_callback = refresh_callback,
|
||||
.timer_callback = timer_callback,
|
||||
|
||||
.blocks = blocks,
|
||||
.block_count = block_count,
|
||||
};
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
int signal_handler_init(signal_handler *const handler) {
|
||||
signal_set set;
|
||||
(void)sigemptyset(&set);
|
||||
|
||||
// Handle user-generated signal for refreshing the status.
|
||||
(void)sigaddset(&set, REFRESH_SIGNAL);
|
||||
|
||||
// Handle SIGALRM generated by the timer.
|
||||
(void)sigaddset(&set, TIMER_SIGNAL);
|
||||
|
||||
// Handle termination signals.
|
||||
(void)sigaddset(&set, SIGINT);
|
||||
(void)sigaddset(&set, SIGTERM);
|
||||
|
||||
for (unsigned short i = 0; i < handler->block_count; ++i) {
|
||||
const block *const block = &handler->blocks[i];
|
||||
if (block->signal > 0) {
|
||||
if (sigaddset(&set, SIGRTMIN + block->signal) != 0) {
|
||||
(void)fprintf(
|
||||
stderr,
|
||||
"error: invalid or unsupported signal specified for "
|
||||
"\"%s\" block\n",
|
||||
block->command);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a signal file descriptor for epoll to watch.
|
||||
handler->fd = signalfd(-1, &set, 0);
|
||||
if (handler->fd == -1) {
|
||||
(void)fprintf(stderr,
|
||||
"error: could not create file descriptor for signals\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Block all realtime and handled signals.
|
||||
for (int i = SIGRTMIN; i <= SIGRTMAX; ++i) {
|
||||
(void)sigaddset(&set, i);
|
||||
}
|
||||
(void)sigprocmask(SIG_BLOCK, &set, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int signal_handler_deinit(signal_handler *const handler) {
|
||||
if (close(handler->fd) != 0) {
|
||||
(void)fprintf(stderr,
|
||||
"error: could not close signal file descriptor\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int signal_handler_process(signal_handler *const handler, timer *const timer) {
|
||||
signal_info info;
|
||||
const ssize_t bytes_read = read(handler->fd, &info, sizeof(info));
|
||||
if (bytes_read == -1) {
|
||||
(void)fprintf(stderr, "error: could not read info of incoming signal");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const int signal = (int)info.ssi_signo;
|
||||
switch (signal) {
|
||||
case TIMER_SIGNAL:
|
||||
if (handler->timer_callback(handler->blocks, handler->block_count,
|
||||
timer) != 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
case REFRESH_SIGNAL:
|
||||
if (handler->refresh_callback(handler->blocks,
|
||||
handler->block_count) != 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
case SIGTERM:
|
||||
// fall through
|
||||
case SIGINT:
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (unsigned short i = 0; i < handler->block_count; ++i) {
|
||||
block *const block = &handler->blocks[i];
|
||||
if (block->signal == signal - SIGRTMIN) {
|
||||
const uint8_t button = (uint8_t)info.ssi_int;
|
||||
block_execute(block, button);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
78
dwmblocks-async/src/status.c
Normal file
78
dwmblocks-async/src/status.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include "status.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
#include "x11.h"
|
||||
|
||||
static bool has_status_changed(const status *const status) {
|
||||
return strcmp(status->current, status->previous) != 0;
|
||||
}
|
||||
|
||||
status status_new(const block *const blocks,
|
||||
const unsigned short block_count) {
|
||||
status status = {
|
||||
.current = {[0] = '\0'},
|
||||
.previous = {[0] = '\0'},
|
||||
|
||||
.blocks = blocks,
|
||||
.block_count = block_count,
|
||||
};
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool status_update(status *const status) {
|
||||
(void)strncpy(status->previous, status->current, LEN(status->current));
|
||||
status->current[0] = '\0';
|
||||
|
||||
for (unsigned short i = 0; i < status->block_count; ++i) {
|
||||
const block *const block = &status->blocks[i];
|
||||
|
||||
if (strlen(block->output) > 0) {
|
||||
#if LEADING_DELIMITER
|
||||
(void)strncat(status->current, DELIMITER, LEN(DELIMITER));
|
||||
#else
|
||||
if (status->current[0] != '\0') {
|
||||
(void)strncat(status->current, DELIMITER, LEN(DELIMITER));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CLICKABLE_BLOCKS
|
||||
if (block->signal > 0) {
|
||||
const char signal[] = {(char)block->signal, '\0'};
|
||||
(void)strncat(status->current, signal, LEN(signal));
|
||||
}
|
||||
#endif
|
||||
|
||||
(void)strncat(status->current, block->icon, LEN(block->output));
|
||||
(void)strncat(status->current, block->output, LEN(block->output));
|
||||
}
|
||||
}
|
||||
|
||||
#if TRAILING_DELIMITER
|
||||
if (status->current[0] != '\0') {
|
||||
(void)strncat(status->current, DELIMITER, LEN(DELIMITER));
|
||||
}
|
||||
#endif
|
||||
|
||||
return has_status_changed(status);
|
||||
}
|
||||
|
||||
int status_write(const status *const status, const bool is_debug_mode,
|
||||
x11_connection *const connection) {
|
||||
if (is_debug_mode) {
|
||||
(void)printf("%s\n", status->current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (x11_set_root_name(connection, status->current) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
72
dwmblocks-async/src/timer.c
Normal file
72
dwmblocks-async/src/timer.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "timer.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "util.h"
|
||||
|
||||
static unsigned int compute_tick(const block *const blocks,
|
||||
const unsigned short block_count) {
|
||||
unsigned int tick = 0;
|
||||
|
||||
for (unsigned short i = 0; i < block_count; ++i) {
|
||||
const block *const block = &blocks[i];
|
||||
tick = gcd(block->interval, tick);
|
||||
}
|
||||
|
||||
return tick;
|
||||
}
|
||||
|
||||
static unsigned int compute_reset_value(const block *const blocks,
|
||||
const unsigned short block_count) {
|
||||
unsigned int reset_value = 1;
|
||||
|
||||
for (unsigned short i = 0; i < block_count; ++i) {
|
||||
const block *const block = &blocks[i];
|
||||
reset_value = MAX(block->interval, reset_value);
|
||||
}
|
||||
|
||||
return reset_value;
|
||||
}
|
||||
|
||||
timer timer_new(const block *const blocks, const unsigned short block_count) {
|
||||
const unsigned int reset_value = compute_reset_value(blocks, block_count);
|
||||
|
||||
timer timer = {
|
||||
.time = reset_value, // Initial value to execute all blocks.
|
||||
.tick = compute_tick(blocks, block_count),
|
||||
.reset_value = reset_value,
|
||||
};
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
int timer_arm(timer *const timer) {
|
||||
errno = 0;
|
||||
(void)alarm(timer->tick);
|
||||
|
||||
if (errno != 0) {
|
||||
(void)fprintf(stderr, "error: could not arm timer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Wrap `time` to the interval [1, reset_value].
|
||||
timer->time = (timer->time + timer->tick) % timer->reset_value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool timer_must_run_block(const timer *const timer, const block *const block) {
|
||||
if (timer == NULL || timer->time == timer->reset_value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (block->interval == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return timer->time % block->interval == 0;
|
||||
}
|
|
@ -1,41 +1,49 @@
|
|||
#include "util.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#define UTF8_MULTIBYTE_BIT BIT(7)
|
||||
|
||||
int gcd(int a, int b) {
|
||||
int temp;
|
||||
unsigned int gcd(unsigned int a, unsigned int b) {
|
||||
while (b > 0) {
|
||||
temp = a % b;
|
||||
const unsigned int temp = a % b;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void closePipe(int pipe[2]) {
|
||||
close(pipe[0]);
|
||||
close(pipe[1]);
|
||||
}
|
||||
size_t truncate_utf8_string(char* const buffer, const size_t size,
|
||||
const size_t char_limit) {
|
||||
size_t char_count = 0;
|
||||
size_t i = 0;
|
||||
while (char_count < char_limit) {
|
||||
char ch = buffer[i];
|
||||
if (ch == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
void trimUTF8(char* buffer, unsigned int size) {
|
||||
int length = (size - 1) / 4;
|
||||
int count = 0, j = 0;
|
||||
char ch = buffer[j];
|
||||
while (ch != '\0' && ch != '\n' && count < length) {
|
||||
// Skip continuation bytes, if any
|
||||
int skip = 1;
|
||||
while ((ch & 0xc0) > 0x80) {
|
||||
unsigned short skip = 1;
|
||||
|
||||
// Multibyte unicode character.
|
||||
if ((ch & UTF8_MULTIBYTE_BIT) != 0) {
|
||||
// Skip continuation bytes.
|
||||
ch <<= 1;
|
||||
skip++;
|
||||
while ((ch & UTF8_MULTIBYTE_BIT) != 0) {
|
||||
ch <<= 1;
|
||||
++skip;
|
||||
}
|
||||
}
|
||||
|
||||
j += skip;
|
||||
ch = buffer[j];
|
||||
count++;
|
||||
// Avoid buffer overflow.
|
||||
if (i + skip >= size) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Trim trailing newline and spaces
|
||||
buffer[j] = ' ';
|
||||
while (j >= 0 && buffer[j] == ' ') j--;
|
||||
buffer[j + 1] = '\0';
|
||||
++char_count;
|
||||
i += skip;
|
||||
}
|
||||
|
||||
buffer[i] = '\0';
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
|
69
dwmblocks-async/src/watcher.c
Normal file
69
dwmblocks-async/src/watcher.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include "watcher.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "util.h"
|
||||
|
||||
static bool watcher_fd_is_readable(const watcher_fd* const watcher_fd) {
|
||||
return (watcher_fd->revents & POLLIN) != 0;
|
||||
}
|
||||
|
||||
int watcher_init(watcher* const watcher, const block* const blocks,
|
||||
const unsigned short block_count, const int signal_fd) {
|
||||
if (signal_fd == -1) {
|
||||
(void)fprintf(
|
||||
stderr,
|
||||
"error: invalid signal file descriptor passed to watcher\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
watcher_fd* const fd = &watcher->fds[SIGNAL_FD];
|
||||
fd->fd = signal_fd;
|
||||
fd->events = POLLIN;
|
||||
|
||||
for (unsigned short i = 0; i < block_count; ++i) {
|
||||
const int block_fd = blocks[i].pipe[READ_END];
|
||||
if (block_fd == -1) {
|
||||
(void)fprintf(
|
||||
stderr,
|
||||
"error: invalid block file descriptors passed to watcher\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
watcher_fd* const fd = &watcher->fds[i];
|
||||
fd->fd = block_fd;
|
||||
fd->events = POLLIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int watcher_poll(watcher* watcher, const int timeout_ms) {
|
||||
int event_count = poll(watcher->fds, LEN(watcher->fds), timeout_ms);
|
||||
|
||||
// Don't return non-zero status for signal interruptions.
|
||||
if (event_count == -1 && errno != EINTR) {
|
||||
(void)fprintf(stderr, "error: watcher could not poll blocks\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
watcher->got_signal = watcher_fd_is_readable(&watcher->fds[SIGNAL_FD]);
|
||||
|
||||
watcher->active_block_count = event_count - (int)watcher->got_signal;
|
||||
unsigned short i = 0;
|
||||
unsigned short j = 0;
|
||||
while (i < event_count && j < LEN(watcher->active_blocks)) {
|
||||
if (watcher_fd_is_readable(&watcher->fds[j])) {
|
||||
watcher->active_blocks[i] = j;
|
||||
++i;
|
||||
}
|
||||
|
||||
++j;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,25 +1,44 @@
|
|||
#include "x11.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
static Display *display;
|
||||
static Window rootWindow;
|
||||
x11_connection *x11_connection_open(void) {
|
||||
xcb_connection_t *const connection = xcb_connect(NULL, NULL);
|
||||
if (xcb_connection_has_error(connection)) {
|
||||
(void)fprintf(stderr, "error: could not connect to X server\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int setupX() {
|
||||
display = XOpenDisplay(NULL);
|
||||
if (!display) {
|
||||
return connection;
|
||||
}
|
||||
|
||||
void x11_connection_close(xcb_connection_t *const connection) {
|
||||
xcb_disconnect(connection);
|
||||
}
|
||||
|
||||
int x11_set_root_name(x11_connection *const connection, const char *name) {
|
||||
xcb_screen_t *const screen =
|
||||
xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
|
||||
const xcb_window_t root_window = screen->root;
|
||||
|
||||
const unsigned short name_format = 8;
|
||||
const xcb_void_cookie_t cookie = xcb_change_property(
|
||||
connection, XCB_PROP_MODE_REPLACE, root_window, XCB_ATOM_WM_NAME,
|
||||
XCB_ATOM_STRING, name_format, strlen(name), name);
|
||||
|
||||
xcb_generic_error_t *error = xcb_request_check(connection, cookie);
|
||||
if (error != NULL) {
|
||||
(void)fprintf(stderr, "error: could not set X root name\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (xcb_flush(connection) <= 0) {
|
||||
(void)fprintf(stderr, "error: could not flush X output buffer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
rootWindow = DefaultRootWindow(display);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int closeX() {
|
||||
return XCloseDisplay(display);
|
||||
}
|
||||
|
||||
void setXRootName(char *str) {
|
||||
XStoreName(display, rootWindow, str);
|
||||
XFlush(display);
|
||||
}
|
||||
|
|
8
nsxiv/.github/workflows/build.yml
vendored
8
nsxiv/.github/workflows/build.yml
vendored
|
@ -47,7 +47,11 @@ jobs:
|
|||
- name: build
|
||||
run: |
|
||||
# libinotify-kqueue isn't available on homebrew
|
||||
make clean && make -s OPT_DEP_DEFAULT=1 HAVE_INOTIFY=0
|
||||
make clean && make -s OPT_DEP_DEFAULT=1 HAVE_INOTIFY=0 \
|
||||
CPPFLAGS="-I/opt/homebrew/include -I/opt/homebrew/include/freetype2" \
|
||||
LDLIBS="-L/opt/homebrew/lib"
|
||||
# force uninstallation with --ignore-dependencies
|
||||
brew uninstall --ignore-dependencies libxft libexif
|
||||
make clean && make -s OPT_DEP_DEFAULT=0
|
||||
make clean && make -s OPT_DEP_DEFAULT=0 \
|
||||
CPPFLAGS="-I/opt/homebrew/include" \
|
||||
LDLIBS="-L/opt/homebrew/lib"
|
||||
|
|
|
@ -81,8 +81,8 @@ you want to build nsxiv on a distribution with separate runtime and development
|
|||
packages (e.g. \*-dev on Debian).
|
||||
|
||||
\* [inotify][] is a Linux-specific API for monitoring filesystem changes.
|
||||
It's not natively available on `*BSD` systems but can be enabed via installing
|
||||
and linking against [libinotify-kqueue][].
|
||||
It's not natively available on `*BSD` systems but can be enabled via
|
||||
installing and linking against [libinotify-kqueue][].
|
||||
|
||||
[inotify]: https://www.man7.org/linux/man-pages/man7/inotify.7.html
|
||||
[libinotify-kqueue]: https://github.com/libinotify-kqueue/libinotify-kqueue
|
||||
|
|
|
@ -85,8 +85,8 @@ void arl_add(arl_t *arl, const char *filepath)
|
|||
add_watch(arl->fd, &arl->wd_file, filepath, IN_CLOSE_WRITE | IN_DELETE_SELF);
|
||||
|
||||
base = strrchr(filepath, '/');
|
||||
assert(base != NULL); /* filepath must be result of `realpath(3)` */
|
||||
dir = arl_scratch_push(filepath, base - filepath);
|
||||
assert(base != NULL && "filepath must be result of realpath(3)");
|
||||
dir = arl_scratch_push(filepath, MAX(base - filepath, 1));
|
||||
add_watch(arl->fd, &arl->wd_dir, dir, IN_CREATE | IN_MOVED_TO);
|
||||
arl->filename = arl_scratch_push(base + 1, strlen(base + 1));
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ static const char *MARK_FG[] = { "Nsxiv.mark.foreground", NULL };
|
|||
#if HAVE_LIBFONTS
|
||||
static const char *BAR_BG[] = { "Nsxiv.bar.background", NULL };
|
||||
static const char *BAR_FG[] = { "Nsxiv.bar.foreground", NULL };
|
||||
static const char *BAR_FONT[] = { "Nsxiv.bar.font", "Hack Nerd Font-11" };
|
||||
static const char *BAR_FONT[] = { "Nsxiv.bar.font", "monospace-8" };
|
||||
|
||||
/* if true, statusbar appears on top of the window */
|
||||
static const bool TOP_STATUSBAR = false;
|
||||
|
|
|
@ -25,7 +25,6 @@ CFLAGS = -Wall -pedantic -O2 -DNDEBUG
|
|||
# icons that will be installed via `make icon`
|
||||
ICONS = 16x16.png 32x32.png 48x48.png 64x64.png 128x128.png
|
||||
|
||||
CC = gcc
|
||||
# Uncomment on OpenBSD
|
||||
# HAVE_INOTIFY = 0
|
||||
# lib_fonts_bsd_0 =
|
||||
|
@ -34,3 +33,5 @@ CC = gcc
|
|||
# inc_fonts_bsd_1 = -I/usr/X11R6/include/freetype2
|
||||
# CPPFLAGS = -I/usr/X11R6/include -I/usr/local/include $(inc_fonts_bsd_$(HAVE_LIBFONTS))
|
||||
# LDLIBS = -L/usr/X11R6/lib -L/usr/local/lib $(lib_fonts_bsd_$(HAVE_LIBFONTS))
|
||||
|
||||
CC = gcc
|
||||
|
|
|
@ -440,7 +440,9 @@ Zoom in.
|
|||
.B Button5
|
||||
Zoom out.
|
||||
.SH CONFIGURATION
|
||||
The following X resources are supported:
|
||||
The following X resources are supported under "Nsxiv" (e.g.
|
||||
.B Nsxiv.bar.font
|
||||
):
|
||||
.TP
|
||||
.B window.background
|
||||
Color of the window background
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
[Desktop Entry]
|
||||
Comment=
|
||||
Exec=nsxiv ~/Pictures
|
||||
GenericName=Image Viewer
|
||||
Icon=nsxiv
|
||||
Type=Application
|
||||
Name=nsxiv
|
||||
GenericName=Image Viewer
|
||||
Exec=nsxiv %F
|
||||
MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/png;image/tiff;image/x-bmp;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-tga;image/x-xpixmap;image/webp;image/heic;image/svg+xml;application/postscript;image/jp2;image/jxl;image/avif;image/heif;
|
||||
NoDisplay=true
|
||||
Path=
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
TerminalOptions=
|
||||
Type=Application
|
||||
X-KDE-SubstituteUID=false
|
||||
X-KDE-Username=
|
||||
Icon=nsxiv
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
branches: master
|
||||
when:
|
||||
branch: master
|
||||
|
||||
pipeline:
|
||||
steps:
|
||||
analysis:
|
||||
image: alpine
|
||||
commands: |
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
branches: master
|
||||
when:
|
||||
branch: master
|
||||
|
||||
# NOTE: "stable" tcc is too old and fails at linking. instead fetching a recent known working commit.
|
||||
pipeline:
|
||||
steps:
|
||||
build:
|
||||
image: alpine
|
||||
environment:
|
||||
|
|
|
@ -4,13 +4,13 @@ misc-*,android-cloexec-*,llvm-include-order
|
|||
-readability-*,readability-duplicate-include,readability-misleading-indentation
|
||||
|
||||
# silence
|
||||
-misc-unused-parameters
|
||||
-misc-unused-parameters,-misc-include-cleaner,-misc-no-recursion
|
||||
-bugprone-easily-swappable-parameters,-bugprone-narrowing-conversions,-bugprone-incorrect-roundings
|
||||
-bugprone-implicit-widening-of-multiplication-result,-bugprone-integer-division
|
||||
-android-cloexec-fopen,-android-cloexec-pipe,-cert-err33-c
|
||||
-bugprone-assignment-in-if-condition
|
||||
-bugprone-suspicious-realloc-usage
|
||||
-bugprone-switch-missing-default-case
|
||||
|
||||
# false positive warnings
|
||||
-clang-analyzer-valist.Uninitialized
|
||||
-misc-no-recursion
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
branches: master
|
||||
when:
|
||||
branch: master
|
||||
|
||||
# NOTE: codespell not available on stable alpine, use edge
|
||||
pipeline:
|
||||
# NOTE: codespell not available on stable alpine, grab it from pip
|
||||
steps:
|
||||
spell-check:
|
||||
image: alpine:edge
|
||||
commands: |
|
||||
apk add --no-cache python3 py3-pip git
|
||||
python3 -m venv ~/py3-venv
|
||||
. ~/py3-venv/bin/activate
|
||||
pip install codespell
|
||||
git ls-files | sed '/\.png$/d' | xargs codespell
|
||||
|
|
|
@ -234,7 +234,8 @@ static bool img_load_multiframe(img_t *img, const fileinfo_t *file)
|
|||
imlib_context_set_blend(!!(finfo.frame_flags & IMLIB_FRAME_BLEND));
|
||||
imlib_blend_image_onto_image(frame, has_alpha, 0, 0, sw, sh, sx, sy, sw, sh);
|
||||
m->frames[m->cnt].im = canvas;
|
||||
m->frames[m->cnt].delay = finfo.frame_delay ? finfo.frame_delay : DEF_ANIM_DELAY;
|
||||
m->frames[m->cnt].delay = m->framedelay ? m->framedelay :
|
||||
(finfo.frame_delay ? finfo.frame_delay : DEF_ANIM_DELAY);
|
||||
m->length += m->frames[m->cnt].delay;
|
||||
m->cnt++;
|
||||
img_free(frame, false);
|
||||
|
@ -676,8 +677,8 @@ void img_rotate(img_t *img, degree_t d)
|
|||
ox = d == DEGREE_90 ? img->x : img->win->w - img->x - img->w * img->zoom;
|
||||
oy = d == DEGREE_270 ? img->y : img->win->h - img->y - img->h * img->zoom;
|
||||
|
||||
img->x = oy + (img->win->w - img->win->h) / 2;
|
||||
img->y = ox + (img->win->h - img->win->w) / 2;
|
||||
img->x = oy + (int)(img->win->w - img->win->h) / 2;
|
||||
img->y = ox + (int)(img->win->h - img->win->w) / 2;
|
||||
|
||||
tmp = img->w;
|
||||
img->w = img->h;
|
||||
|
|
53
nsxiv/main.c
53
nsxiv/main.c
|
@ -25,6 +25,7 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
|
@ -249,10 +250,10 @@ void reset_timeout(timeout_f handler)
|
|||
|
||||
static bool check_timeouts(int *t)
|
||||
{
|
||||
int i = 0, tdiff, tmin = -1;
|
||||
int i = 0, tdiff, tmin;
|
||||
struct timeval now;
|
||||
|
||||
while (i < (int)ARRLEN(timeouts)) {
|
||||
for (i = 0; i < (int)ARRLEN(timeouts); ++i) {
|
||||
if (timeouts[i].active) {
|
||||
gettimeofday(&now, 0);
|
||||
tdiff = TV_DIFF(&timeouts[i].when, &now);
|
||||
|
@ -260,16 +261,22 @@ static bool check_timeouts(int *t)
|
|||
timeouts[i].active = false;
|
||||
if (timeouts[i].handler != NULL)
|
||||
timeouts[i].handler();
|
||||
i = tmin = -1;
|
||||
} else if (tmin < 0 || tdiff < tmin) {
|
||||
tmin = tdiff;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (tmin > 0 && t != NULL)
|
||||
*t = tmin;
|
||||
return tmin > 0;
|
||||
|
||||
tmin = INT_MAX;
|
||||
gettimeofday(&now, 0);
|
||||
for (i = 0; i < (int)ARRLEN(timeouts); ++i) {
|
||||
if (timeouts[i].active) {
|
||||
tdiff = TV_DIFF(&timeouts[i].when, &now);
|
||||
tmin = MIN(tmin, tdiff);
|
||||
}
|
||||
}
|
||||
|
||||
if (tmin != INT_MAX && t != NULL)
|
||||
*t = MAX(tmin, 0);
|
||||
return tmin != INT_MAX;
|
||||
}
|
||||
|
||||
static void autoreload(void)
|
||||
|
@ -328,8 +335,7 @@ static void open_title(void)
|
|||
snprintf(fcnt, ARRLEN(fcnt), "%d", filecnt);
|
||||
construct_argv(argv, ARRLEN(argv), wintitle.f.cmd, files[fileidx].path,
|
||||
fidx, fcnt, w, h, z, NULL);
|
||||
if ((wintitle.pid = spawn(&wintitle.fd, NULL, argv)) > 0)
|
||||
fcntl(wintitle.fd, F_SETFL, O_NONBLOCK);
|
||||
wintitle.pid = spawn(&wintitle.fd, NULL, O_NONBLOCK, argv);
|
||||
}
|
||||
|
||||
void close_info(void)
|
||||
|
@ -352,8 +358,7 @@ void open_info(void)
|
|||
}
|
||||
construct_argv(argv, ARRLEN(argv), cmd, files[fileidx].name, w, h,
|
||||
files[fileidx].path, NULL);
|
||||
if ((info.pid = spawn(&info.fd, NULL, argv)) > 0)
|
||||
fcntl(info.fd, F_SETFL, O_NONBLOCK);
|
||||
info.pid = spawn(&info.fd, NULL, O_NONBLOCK, argv);
|
||||
}
|
||||
|
||||
static void read_info(void)
|
||||
|
@ -455,7 +460,6 @@ static void update_info(void)
|
|||
open_title();
|
||||
}
|
||||
|
||||
/* update bar contents */
|
||||
if (win.bar.h == 0 || extprefix)
|
||||
return;
|
||||
|
||||
|
@ -601,12 +605,10 @@ void handle_key_handler(bool init)
|
|||
if (win.bar.h == 0)
|
||||
return;
|
||||
if (init) {
|
||||
close_info();
|
||||
snprintf(win.bar.l.buf, win.bar.l.size,
|
||||
snprintf(win.bar.r.buf, win.bar.r.size,
|
||||
"Getting key handler input (%s to abort)...",
|
||||
XKeysymToString(KEYHANDLER_ABORT));
|
||||
} else { /* abort */
|
||||
open_info();
|
||||
update_info();
|
||||
}
|
||||
win_draw(&win);
|
||||
|
@ -635,8 +637,7 @@ static bool run_key_handler(const char *key, unsigned int mask)
|
|||
if (key == NULL)
|
||||
return false;
|
||||
|
||||
close_info();
|
||||
strncpy(win.bar.l.buf, "Running key handler...", win.bar.l.size);
|
||||
strncpy(win.bar.r.buf, "Running key handler...", win.bar.r.size);
|
||||
win_draw(&win);
|
||||
win_set_cursor(&win, CURSOR_WATCH);
|
||||
setenv("NSXIV_USING_NULL", options->using_null ? "1" : "0", 1);
|
||||
|
@ -646,7 +647,7 @@ static bool run_key_handler(const char *key, unsigned int mask)
|
|||
mask & Mod1Mask ? "M-" : "",
|
||||
mask & ShiftMask ? "S-" : "", key);
|
||||
construct_argv(argv, ARRLEN(argv), keyhandler.f.cmd, kstr, NULL);
|
||||
if ((pid = spawn(NULL, &writefd, argv)) < 0)
|
||||
if ((pid = spawn(NULL, &writefd, 0x0, argv)) < 0)
|
||||
return false;
|
||||
if ((pfs = fdopen(writefd, "w")) == NULL) {
|
||||
error(0, errno, "open pipe");
|
||||
|
@ -687,6 +688,8 @@ static bool run_key_handler(const char *key, unsigned int mask)
|
|||
if (mode == MODE_IMAGE && changed) {
|
||||
img_close(&img, true);
|
||||
load_image(fileidx);
|
||||
} else {
|
||||
update_info();
|
||||
}
|
||||
free(oldst);
|
||||
reset_cursor();
|
||||
|
@ -801,13 +804,15 @@ static void run(void)
|
|||
pfd[FD_INFO].fd = info.fd;
|
||||
pfd[FD_TITLE].fd = wintitle.fd;
|
||||
pfd[FD_ARL].fd = arl.fd;
|
||||
pfd[FD_X].events = pfd[FD_INFO].events = pfd[FD_TITLE].events = pfd[FD_ARL].events = POLLIN;
|
||||
|
||||
pfd[FD_X].events = pfd[FD_ARL].events = POLLIN;
|
||||
pfd[FD_INFO].events = pfd[FD_TITLE].events = 0;
|
||||
|
||||
if (poll(pfd, ARRLEN(pfd), to_set ? timeout : -1) < 0)
|
||||
continue;
|
||||
if (pfd[FD_INFO].revents & POLLIN)
|
||||
if (pfd[FD_INFO].revents & POLLHUP)
|
||||
read_info();
|
||||
if (pfd[FD_TITLE].revents & POLLIN)
|
||||
if (pfd[FD_TITLE].revents & POLLHUP)
|
||||
read_title();
|
||||
if ((pfd[FD_ARL].revents & POLLIN) && arl_handle(&arl)) {
|
||||
img.autoreload_pending = true;
|
||||
|
@ -835,7 +840,7 @@ static void run(void)
|
|||
}
|
||||
} while (discard);
|
||||
|
||||
switch (ev.type) { /* handle events */
|
||||
switch (ev.type) {
|
||||
case ButtonPress:
|
||||
on_buttonpress(&ev.xbutton);
|
||||
break;
|
||||
|
|
|
@ -101,7 +101,7 @@ typedef enum {
|
|||
|
||||
typedef struct {
|
||||
const char *name; /* as given by user */
|
||||
const char *path; /* always absolute */
|
||||
const char *path; /* always absolute, result of realpath(3) */
|
||||
fileflags_t flags;
|
||||
} fileinfo_t;
|
||||
|
||||
|
@ -180,7 +180,7 @@ typedef struct {
|
|||
unsigned int cnt;
|
||||
unsigned int sel;
|
||||
bool animate;
|
||||
unsigned int framedelay;
|
||||
int framedelay;
|
||||
int length;
|
||||
} multi_img_t;
|
||||
|
||||
|
@ -265,7 +265,7 @@ struct opt {
|
|||
/* window: */
|
||||
bool fullscreen;
|
||||
bool hide_bar;
|
||||
Window embed; /* unsigned long */
|
||||
Window embed;
|
||||
char *geometry;
|
||||
char *res_name;
|
||||
|
||||
|
@ -356,7 +356,7 @@ int r_closedir(r_dir_t*);
|
|||
char* r_readdir(r_dir_t*, bool);
|
||||
int r_mkdir(char*);
|
||||
void construct_argv(char**, unsigned int, ...);
|
||||
pid_t spawn(int*, int*, char *const []);
|
||||
pid_t spawn(int*, int*, int, char *const []);
|
||||
|
||||
|
||||
/* window.c */
|
||||
|
|
|
@ -43,7 +43,7 @@ static char *tns_cache_filepath(const char *filepath)
|
|||
size_t len;
|
||||
char *cfile = NULL;
|
||||
|
||||
assert(*filepath == '/' && "filepath should be result of realpath(3)");
|
||||
assert(*filepath == '/' && "filepath must be result of realpath(3)");
|
||||
|
||||
if (strncmp(filepath, cache_dir, strlen(cache_dir)) != 0) {
|
||||
/* don't cache images inside the cache directory! */
|
||||
|
@ -181,7 +181,7 @@ void tns_init(tns_t *tns, fileinfo_t *tns_files, const int *cnt, int *sel, win_t
|
|||
memcpy(cache_tmpfile, cache_dir, len - 1);
|
||||
cache_tmpfile_base = cache_tmpfile + len - 1;
|
||||
} else {
|
||||
error(0, 0, "Cache directory not found");
|
||||
error(EXIT_FAILURE, 0, "Cache directory not found");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +198,8 @@ CLEANUP void tns_free(tns_t *tns)
|
|||
|
||||
free(cache_dir);
|
||||
cache_dir = NULL;
|
||||
free(cache_tmpfile);
|
||||
cache_tmpfile = cache_tmpfile_base = NULL;
|
||||
}
|
||||
|
||||
static Imlib_Image tns_scale_down(Imlib_Image im, int dim)
|
||||
|
|
17
nsxiv/util.c
17
nsxiv/util.c
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <spawn.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
@ -230,25 +231,27 @@ void construct_argv(char **argv, unsigned int len, ...)
|
|||
assert(argv[len - 1] == NULL && "argv should be NULL terminated");
|
||||
}
|
||||
|
||||
static int mkspawn_pipe(posix_spawn_file_actions_t *fa, const char *cmd, int *pfd, int dupidx)
|
||||
static int mkspawn_pipe(posix_spawn_file_actions_t *fa, const char *cmd, int *pfd, int dupidx, int pipeflags)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
if (pipe(pfd) < 0) {
|
||||
error(0, errno, "pipe: %s", cmd);
|
||||
return -1;
|
||||
}
|
||||
err = posix_spawn_file_actions_adddup2(fa, pfd[dupidx], dupidx);
|
||||
if (pipeflags && (fcntl(pfd[0], F_SETFL, pipeflags) < 0 || fcntl(pfd[1], F_SETFL, pipeflags) < 0))
|
||||
err = errno;
|
||||
err = err ? err : posix_spawn_file_actions_adddup2(fa, pfd[dupidx], dupidx);
|
||||
err = err ? err : posix_spawn_file_actions_addclose(fa, pfd[0]);
|
||||
err = err ? err : posix_spawn_file_actions_addclose(fa, pfd[1]);
|
||||
if (err) {
|
||||
error(0, err, "posix_spawn_file_actions: %s", cmd);
|
||||
error(0, err, "mkspawn_pipe: %s", cmd);
|
||||
close(pfd[0]);
|
||||
close(pfd[1]);
|
||||
}
|
||||
return err ? -1 : 0;
|
||||
}
|
||||
|
||||
pid_t spawn(int *readfd, int *writefd, char *const argv[])
|
||||
pid_t spawn(int *readfd, int *writefd, int pipeflags, char *const argv[])
|
||||
{
|
||||
pid_t pid = -1;
|
||||
const char *cmd;
|
||||
|
@ -263,9 +266,9 @@ pid_t spawn(int *readfd, int *writefd, char *const argv[])
|
|||
return pid;
|
||||
}
|
||||
|
||||
if (readfd != NULL && mkspawn_pipe(&fa, cmd, pfd_read, 1) < 0)
|
||||
if (readfd != NULL && mkspawn_pipe(&fa, cmd, pfd_read, 1, pipeflags) < 0)
|
||||
goto err_destroy_fa;
|
||||
if (writefd != NULL && mkspawn_pipe(&fa, cmd, pfd_write, 0) < 0)
|
||||
if (writefd != NULL && mkspawn_pipe(&fa, cmd, pfd_write, 0, pipeflags) < 0)
|
||||
goto err_close_readfd;
|
||||
|
||||
if ((err = posix_spawnp(&pid, cmd, &fa, NULL, argv, environ)) != 0) {
|
||||
|
|
|
@ -470,17 +470,15 @@ static void win_draw_bar(win_t *win)
|
|||
XSetBackground(e->dpy, gc, win->bar_bg.pixel);
|
||||
|
||||
if ((len = strlen(r->buf)) > 0) {
|
||||
if ((tw = TEXTWIDTH(win, r->buf, len)) > w) {
|
||||
XftDrawDestroy(d);
|
||||
return;
|
||||
}
|
||||
if ((tw = TEXTWIDTH(win, r->buf, len)) <= w) {
|
||||
x = win->w - tw - H_TEXT_PAD;
|
||||
w -= tw;
|
||||
win_draw_text(win, d, &win->bar_fg, x, y, r->buf, len, tw);
|
||||
}
|
||||
if ((len = strlen(l->buf)) > 0) {
|
||||
/* remaining width, also keeping gap between left and right parts */
|
||||
w -= tw + (2 * H_TEXT_PAD);
|
||||
}
|
||||
if ((len = strlen(l->buf)) > 0 && w > 0) {
|
||||
x = H_TEXT_PAD;
|
||||
w -= 2 * H_TEXT_PAD; /* gap between left and right parts */
|
||||
win_draw_text(win, d, &win->bar_fg, x, y, l->buf, len, w);
|
||||
}
|
||||
XftDrawDestroy(d);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 806e4373a75533ab18ddcad922883a07f1287329
|
||||
Subproject commit 78113baeaa4a75ee616c92addf2ae43c5f3c724c
|
2
sfm
2
sfm
|
@ -1 +1 @@
|
|||
Subproject commit 1b5eeb09742e587b9cbdef26b02173ea82bda3fa
|
||||
Subproject commit 7961f3ee45daf18207a03b32a9b78eaf0852e163
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue