rm xrdb patch to xresources to load non-color vars
This commit is contained in:
parent
ad08183a60
commit
bc040702d9
5 changed files with 117 additions and 88 deletions
63
config.h
63
config.h
|
@ -5,18 +5,17 @@
|
||||||
#define TERMCLASS "St"
|
#define TERMCLASS "St"
|
||||||
|
|
||||||
/* appearance */
|
/* appearance */
|
||||||
static const unsigned int borderpx = 3; /* border pixel of windows */
|
static unsigned int borderpx = 3; /* border pixel of windows */
|
||||||
static const unsigned int snap = 32; /* snap pixel */
|
static unsigned int snap = 32; /* snap pixel */
|
||||||
static const unsigned int gappih = 20; /* horiz inner gap between windows */
|
static unsigned int gappih = 20; /* horiz inner gap between windows */
|
||||||
static const unsigned int gappiv = 10; /* vert inner gap between windows */
|
static unsigned int gappiv = 10; /* vert inner gap between windows */
|
||||||
static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */
|
static unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */
|
||||||
static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */
|
static unsigned int gappov = 30; /* vert outer gap between windows and screen edge */
|
||||||
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
|
static int swallowfloating = 0; /* 1 means swallow floating windows by default */
|
||||||
static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */
|
static int smartgaps = 0; /* 1 means no outer gap when there is only one window */
|
||||||
static const int showbar = 1; /* 0 means no bar */
|
static int showbar = 1; /* 0 means no bar */
|
||||||
static const int topbar = 1; /* 0 means bottom bar */
|
static int topbar = 1; /* 0 means bottom bar */
|
||||||
static const char *fonts[] = { "monospace:size=10", "JoyPixels:pixelsize=10:antialias=true:autohint=true" };
|
static char *fonts[] = { "monospace:size=10", "JoyPixels:pixelsize=10:antialias=true:autohint=true" };
|
||||||
static char dmenufont[] = "monospace:size=10";
|
|
||||||
static char normbgcolor[] = "#222222";
|
static char normbgcolor[] = "#222222";
|
||||||
static char normbordercolor[] = "#444444";
|
static char normbordercolor[] = "#444444";
|
||||||
static char normfgcolor[] = "#bbbbbb";
|
static char normfgcolor[] = "#bbbbbb";
|
||||||
|
@ -58,9 +57,9 @@ static const Rule rules[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* layout(s) */
|
/* layout(s) */
|
||||||
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
static float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||||
static const int nmaster = 1; /* number of clients in master area */
|
static int nmaster = 1; /* number of clients in master area */
|
||||||
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
static int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
||||||
#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */
|
#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */
|
||||||
#include "vanitygaps.c"
|
#include "vanitygaps.c"
|
||||||
static const Layout layouts[] = {
|
static const Layout layouts[] = {
|
||||||
|
@ -101,12 +100,36 @@ static const Layout layouts[] = {
|
||||||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||||
|
|
||||||
/* commands */
|
/* commands */
|
||||||
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
|
|
||||||
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
|
|
||||||
static const char *termcmd[] = { TERMINAL, NULL };
|
static const char *termcmd[] = { TERMINAL, NULL };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Xresources preferences to load at startup
|
||||||
|
*/
|
||||||
|
ResourcePref resources[] = {
|
||||||
|
{ "dwm.color0", STRING, &normbordercolor },
|
||||||
|
{ "dwm.color8", STRING, &selbordercolor },
|
||||||
|
{ "dwm.color0", STRING, &normbgcolor },
|
||||||
|
{ "dwm.color4", STRING, &normfgcolor },
|
||||||
|
{ "dwm.color0", STRING, &selfgcolor },
|
||||||
|
{ "dwm.color4", STRING, &selbgcolor },
|
||||||
|
{ "borderpx", INTEGER, &borderpx },
|
||||||
|
{ "snap", INTEGER, &snap },
|
||||||
|
{ "showbar", INTEGER, &showbar },
|
||||||
|
{ "topbar", INTEGER, &topbar },
|
||||||
|
{ "nmaster", INTEGER, &nmaster },
|
||||||
|
{ "resizehints", INTEGER, &resizehints },
|
||||||
|
{ "mfact", FLOAT, &mfact },
|
||||||
|
{ "gappih", STRING, &gappih },
|
||||||
|
{ "gappiv", STRING, &gappiv },
|
||||||
|
{ "gappoh", STRING, &gappoh },
|
||||||
|
{ "gappov", STRING, &gappov },
|
||||||
|
{ "swallowfloating", STRING, &swallowfloating },
|
||||||
|
{ "smartgaps", STRING, &smartgaps },
|
||||||
|
};
|
||||||
|
|
||||||
#include <X11/XF86keysym.h>
|
#include <X11/XF86keysym.h>
|
||||||
#include "shiftview.c"
|
#include "shiftview.c"
|
||||||
|
|
||||||
static Key keys[] = {
|
static Key keys[] = {
|
||||||
/* modifier key function argument */
|
/* modifier key function argument */
|
||||||
STACKKEYS(MODKEY, focus)
|
STACKKEYS(MODKEY, focus)
|
||||||
|
@ -165,7 +188,7 @@ static Key keys[] = {
|
||||||
{ MODKEY|ShiftMask, XK_a, defaultgaps, {0} },
|
{ MODKEY|ShiftMask, XK_a, defaultgaps, {0} },
|
||||||
{ MODKEY, XK_s, togglesticky, {0} },
|
{ MODKEY, XK_s, togglesticky, {0} },
|
||||||
/* { MODKEY|ShiftMask, XK_s, spawn, SHCMD("") }, */
|
/* { MODKEY|ShiftMask, XK_s, spawn, SHCMD("") }, */
|
||||||
{ MODKEY, XK_d, spawn, {.v = dmenucmd } },
|
{ MODKEY, XK_d, spawn, SHCMD("dmenu_run") },
|
||||||
/* { MODKEY, XK_d, spawn, SHCMD("") } }, */
|
/* { MODKEY, XK_d, spawn, SHCMD("") } }, */
|
||||||
{ MODKEY, XK_f, togglefullscr, {0} },
|
{ MODKEY, XK_f, togglefullscr, {0} },
|
||||||
{ MODKEY|ShiftMask, XK_f, setlayout, {.v = &layouts[8]} },
|
{ MODKEY|ShiftMask, XK_f, setlayout, {.v = &layouts[8]} },
|
||||||
|
@ -214,14 +237,14 @@ static Key keys[] = {
|
||||||
{ MODKEY, XK_F2, spawn, SHCMD("tutorialvids") },
|
{ MODKEY, XK_F2, spawn, SHCMD("tutorialvids") },
|
||||||
{ MODKEY, XK_F3, spawn, SHCMD("displayselect") },
|
{ MODKEY, XK_F3, spawn, SHCMD("displayselect") },
|
||||||
{ MODKEY, XK_F4, spawn, SHCMD(TERMINAL " -e pulsemixer; kill -44 $(pidof dwmblocks)") },
|
{ MODKEY, XK_F4, spawn, SHCMD(TERMINAL " -e pulsemixer; kill -44 $(pidof dwmblocks)") },
|
||||||
{ MODKEY, XK_F5, xrdb, {.v = NULL } },
|
/* { MODKEY, XK_F5, xrdb, {.v = NULL } }, */
|
||||||
{ MODKEY, XK_F6, spawn, SHCMD("torwrap") },
|
{ MODKEY, XK_F6, spawn, SHCMD("torwrap") },
|
||||||
{ MODKEY, XK_F7, spawn, SHCMD("td-toggle") },
|
{ MODKEY, XK_F7, spawn, SHCMD("td-toggle") },
|
||||||
{ MODKEY, XK_F8, spawn, SHCMD("mw -Y") },
|
{ MODKEY, XK_F8, spawn, SHCMD("mw -Y") },
|
||||||
{ MODKEY, XK_F9, spawn, SHCMD("dmenumount") },
|
{ MODKEY, XK_F9, spawn, SHCMD("dmenumount") },
|
||||||
{ MODKEY, XK_F10, spawn, SHCMD("dmenuumount") },
|
{ MODKEY, XK_F10, spawn, SHCMD("dmenuumount") },
|
||||||
{ MODKEY, XK_F11, spawn, SHCMD("mpv --no-cache --no-osc --no-input-default-bindings --input-conf=/dev/null --title=webcam $(ls /dev/video[0,2,4,6,8] | tail -n 1)") },
|
{ MODKEY, XK_F11, spawn, SHCMD("mpv --no-cache --no-osc --no-input-default-bindings --input-conf=/dev/null --title=webcam $(ls /dev/video[0,2,4,6,8] | tail -n 1)") },
|
||||||
{ MODKEY, XK_F12, xrdb, {.v = NULL } },
|
/* { MODKEY, XK_F12, xrdb, {.v = NULL } }, */
|
||||||
{ MODKEY, XK_space, zoom, {0} },
|
{ MODKEY, XK_space, zoom, {0} },
|
||||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||||
|
|
||||||
|
|
2
drw.c
2
drw.c
|
@ -153,7 +153,7 @@ xfont_free(Fnt *font)
|
||||||
}
|
}
|
||||||
|
|
||||||
Fnt*
|
Fnt*
|
||||||
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
|
drw_fontset_create(Drw* drw, char *fonts[], size_t fontcount)
|
||||||
{
|
{
|
||||||
Fnt *cur, *ret = NULL;
|
Fnt *cur, *ret = NULL;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
2
drw.h
2
drw.h
|
@ -32,7 +32,7 @@ void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
||||||
void drw_free(Drw *drw);
|
void drw_free(Drw *drw);
|
||||||
|
|
||||||
/* Fnt abstraction */
|
/* Fnt abstraction */
|
||||||
Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
|
Fnt *drw_fontset_create(Drw* drw, char *fonts[], size_t fontcount);
|
||||||
void drw_fontset_free(Fnt* set);
|
void drw_fontset_free(Fnt* set);
|
||||||
unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
|
unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
|
||||||
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
||||||
|
|
134
dwm.c
134
dwm.c
|
@ -35,8 +35,8 @@
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xproto.h>
|
#include <X11/Xproto.h>
|
||||||
#include <X11/Xresource.h>
|
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/Xresource.h>
|
||||||
#ifdef XINERAMA
|
#ifdef XINERAMA
|
||||||
#include <X11/extensions/Xinerama.h>
|
#include <X11/extensions/Xinerama.h>
|
||||||
#endif /* XINERAMA */
|
#endif /* XINERAMA */
|
||||||
|
@ -68,21 +68,6 @@
|
||||||
#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << LENGTH(tags))
|
#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << LENGTH(tags))
|
||||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||||
#define TRUNC(X,A,B) (MAX((A), MIN((X), (B))))
|
#define TRUNC(X,A,B) (MAX((A), MIN((X), (B))))
|
||||||
#define XRDB_LOAD_COLOR(R,V) if (XrmGetResource(xrdb, R, NULL, &type, &value) == True) { \
|
|
||||||
if (value.addr != NULL && strnlen(value.addr, 8) == 7 && value.addr[0] == '#') { \
|
|
||||||
int i = 1; \
|
|
||||||
for (; i <= 6; i++) { \
|
|
||||||
if (value.addr[i] < 48) break; \
|
|
||||||
if (value.addr[i] > 57 && value.addr[i] < 65) break; \
|
|
||||||
if (value.addr[i] > 70 && value.addr[i] < 97) break; \
|
|
||||||
if (value.addr[i] > 102) break; \
|
|
||||||
} \
|
|
||||||
if (i == 7) { \
|
|
||||||
strncpy(V, value.addr, 7); \
|
|
||||||
V[7] = '\0'; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* enums */
|
/* enums */
|
||||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||||
|
@ -176,6 +161,19 @@ typedef struct {
|
||||||
int monitor;
|
int monitor;
|
||||||
} Rule;
|
} Rule;
|
||||||
|
|
||||||
|
/* Xresources preferences */
|
||||||
|
enum resource_type {
|
||||||
|
STRING = 0,
|
||||||
|
INTEGER = 1,
|
||||||
|
FLOAT = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
enum resource_type type;
|
||||||
|
void *dst;
|
||||||
|
} ResourcePref;
|
||||||
|
|
||||||
/* function declarations */
|
/* function declarations */
|
||||||
static void applyrules(Client *c);
|
static void applyrules(Client *c);
|
||||||
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
|
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
|
||||||
|
@ -214,7 +212,6 @@ static void grabkeys(void);
|
||||||
static void incnmaster(const Arg *arg);
|
static void incnmaster(const Arg *arg);
|
||||||
static void keypress(XEvent *e);
|
static void keypress(XEvent *e);
|
||||||
static void killclient(const Arg *arg);
|
static void killclient(const Arg *arg);
|
||||||
static void loadxrdb(void);
|
|
||||||
static void manage(Window w, XWindowAttributes *wa);
|
static void manage(Window w, XWindowAttributes *wa);
|
||||||
static void mappingnotify(XEvent *e);
|
static void mappingnotify(XEvent *e);
|
||||||
static void maprequest(XEvent *e);
|
static void maprequest(XEvent *e);
|
||||||
|
@ -281,8 +278,9 @@ static Monitor *wintomon(Window w);
|
||||||
static int xerror(Display *dpy, XErrorEvent *ee);
|
static int xerror(Display *dpy, XErrorEvent *ee);
|
||||||
static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
||||||
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
||||||
static void xrdb(const Arg *arg);
|
|
||||||
static void zoom(const Arg *arg);
|
static void zoom(const Arg *arg);
|
||||||
|
static void load_xresources(void);
|
||||||
|
static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst);
|
||||||
|
|
||||||
static pid_t getparentprocess(pid_t p);
|
static pid_t getparentprocess(pid_t p);
|
||||||
static int isdescprocess(pid_t p, pid_t c);
|
static int isdescprocess(pid_t p, pid_t c);
|
||||||
|
@ -1175,37 +1173,6 @@ killclient(const Arg *arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
loadxrdb()
|
|
||||||
{
|
|
||||||
Display *display;
|
|
||||||
char * resm;
|
|
||||||
XrmDatabase xrdb;
|
|
||||||
char *type;
|
|
||||||
XrmValue value;
|
|
||||||
|
|
||||||
display = XOpenDisplay(NULL);
|
|
||||||
|
|
||||||
if (display != NULL) {
|
|
||||||
resm = XResourceManagerString(display);
|
|
||||||
|
|
||||||
if (resm != NULL) {
|
|
||||||
xrdb = XrmGetStringDatabase(resm);
|
|
||||||
|
|
||||||
if (xrdb != NULL) {
|
|
||||||
XRDB_LOAD_COLOR("dwm.color0", normbordercolor);
|
|
||||||
XRDB_LOAD_COLOR("dwm.color8", selbordercolor);
|
|
||||||
XRDB_LOAD_COLOR("dwm.color0", normbgcolor);
|
|
||||||
XRDB_LOAD_COLOR("dwm.color4", normfgcolor);
|
|
||||||
XRDB_LOAD_COLOR("dwm.color0", selfgcolor);
|
|
||||||
XRDB_LOAD_COLOR("dwm.color4", selbgcolor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XCloseDisplay(display);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
manage(Window w, XWindowAttributes *wa)
|
manage(Window w, XWindowAttributes *wa)
|
||||||
{
|
{
|
||||||
|
@ -1934,8 +1901,6 @@ sigdwmblocks(const Arg *arg)
|
||||||
void
|
void
|
||||||
spawn(const Arg *arg)
|
spawn(const Arg *arg)
|
||||||
{
|
{
|
||||||
if (arg->v == dmenucmd)
|
|
||||||
dmenumon[0] = '0' + selmon->num;
|
|
||||||
if (fork() == 0) {
|
if (fork() == 0) {
|
||||||
if (dpy)
|
if (dpy)
|
||||||
close(ConnectionNumber(dpy));
|
close(ConnectionNumber(dpy));
|
||||||
|
@ -2544,17 +2509,6 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
xrdb(const Arg *arg)
|
|
||||||
{
|
|
||||||
loadxrdb();
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < LENGTH(colors); i++)
|
|
||||||
scheme[i] = drw_scm_create(drw, colors[i], 3);
|
|
||||||
focus(NULL);
|
|
||||||
arrange(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
zoom(const Arg *arg)
|
zoom(const Arg *arg)
|
||||||
{
|
{
|
||||||
|
@ -2569,6 +2523,60 @@ zoom(const Arg *arg)
|
||||||
pop(c);
|
pop(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
|
||||||
|
{
|
||||||
|
char *sdst = NULL;
|
||||||
|
int *idst = NULL;
|
||||||
|
float *fdst = NULL;
|
||||||
|
|
||||||
|
sdst = dst;
|
||||||
|
idst = dst;
|
||||||
|
fdst = dst;
|
||||||
|
|
||||||
|
char fullname[256];
|
||||||
|
char *type;
|
||||||
|
XrmValue ret;
|
||||||
|
|
||||||
|
snprintf(fullname, sizeof(fullname), "%s.%s", "dwm", name);
|
||||||
|
fullname[sizeof(fullname) - 1] = '\0';
|
||||||
|
|
||||||
|
XrmGetResource(db, fullname, "*", &type, &ret);
|
||||||
|
if (!(ret.addr == NULL || strncmp("String", type, 64)))
|
||||||
|
{
|
||||||
|
switch (rtype) {
|
||||||
|
case STRING:
|
||||||
|
strcpy(sdst, ret.addr);
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
*idst = strtoul(ret.addr, NULL, 10);
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
*fdst = strtof(ret.addr, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
load_xresources(void)
|
||||||
|
{
|
||||||
|
Display *display;
|
||||||
|
char *resm;
|
||||||
|
XrmDatabase db;
|
||||||
|
ResourcePref *p;
|
||||||
|
|
||||||
|
display = XOpenDisplay(NULL);
|
||||||
|
resm = XResourceManagerString(display);
|
||||||
|
if (!resm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
db = XrmGetStringDatabase(resm);
|
||||||
|
for (p = resources; p < resources + LENGTH(resources); p++)
|
||||||
|
resource_load(db, p->name, p->type, p->dst);
|
||||||
|
XCloseDisplay(display);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -2584,7 +2592,7 @@ main(int argc, char *argv[])
|
||||||
die("dwm: cannot get xcb connection\n");
|
die("dwm: cannot get xcb connection\n");
|
||||||
checkotherwm();
|
checkotherwm();
|
||||||
XrmInitialize();
|
XrmInitialize();
|
||||||
loadxrdb();
|
load_xresources();
|
||||||
setup();
|
setup();
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
if (pledge("stdio rpath proc exec", NULL) == -1)
|
if (pledge("stdio rpath proc exec", NULL) == -1)
|
||||||
|
|
|
@ -196,8 +196,6 @@ To type capital letters, hold down the \f(CWShift\fP key\(emthat might sound lik
|
||||||
.ITEM
|
.ITEM
|
||||||
\f(CWMod+F11\fP \(en View webcam
|
\f(CWMod+F11\fP \(en View webcam
|
||||||
.ITEM
|
.ITEM
|
||||||
\f(CWMod+F12\fP \(en Update dwm's colorscheme if you have changed Xresources
|
|
||||||
.ITEM
|
|
||||||
\f(CWMod+`\fP \(en Select an emoji to copy to clipboard
|
\f(CWMod+`\fP \(en Select an emoji to copy to clipboard
|
||||||
.ITEM
|
.ITEM
|
||||||
\f(CWMod+Insert\fP \(en Show contents of clipboard/primary selection
|
\f(CWMod+Insert\fP \(en Show contents of clipboard/primary selection
|
||||||
|
|
Loading…
Reference in a new issue