Introduce support for specifying variables from X resources. (#2286)
This patch introduces a new 'set_from_resource' config directive which allows defining a variable by retrieving its value from the X resource database. This avoids having to configure a color scheme in multiple files. The directive takes an additional fallback value which is used in case the resource cannot be found or during config validation where no X connection is available. Furthermore, this patch includes the following changes: - If the same variable is defined twice, we now properly overwrite the value of the assignment rather than inserting two variable definitions with the same key. - We now depend on xcb-util-xrm to query the resource. - Increase the buffer size for variable / resource assignments. fixes #2130
This commit is contained in:
parent
dbafb3cf23
commit
47562b4143
45
DEPENDS
45
DEPENDS
|
@ -4,28 +4,29 @@
|
||||||
"min" means minimum required version
|
"min" means minimum required version
|
||||||
"lkgv" means last known good version
|
"lkgv" means last known good version
|
||||||
|
|
||||||
┌──────────────┬────────┬────────┬────────────────────────────────────────┐
|
┌──────────────┬────────┬────────┬───────────────────────────────────────────────────────────┐
|
||||||
│ dependency │ min. │ lkgv │ URL │
|
│ dependency │ min. │ lkgv │ URL │
|
||||||
├──────────────┼────────┼────────┼────────────────────────────────────────┤
|
├──────────────┼────────┼────────┼───────────────────────────────────────────────────────────┤
|
||||||
│ pkg-config │ 0.25 │ 0.28 │ http://pkgconfig.freedesktop.org/ │
|
│ pkg-config │ 0.25 │ 0.28 │ http://pkgconfig.freedesktop.org/ │
|
||||||
│ libxcb │ 1.1.93 │ 1.11 │ http://xcb.freedesktop.org/dist/ │
|
│ libxcb │ 1.1.93 │ 1.11 │ http://xcb.freedesktop.org/dist/ │
|
||||||
│ xcb-util │ 0.3.3 │ 0.4.1 │ http://xcb.freedesktop.org/dist/ │
|
│ xcb-util │ 0.3.3 │ 0.4.1 │ http://xcb.freedesktop.org/dist/ │
|
||||||
│ xkbcommon │ 0.4.0 │ 0.5.0 │ http://xkbcommon.org/ │
|
│ xkbcommon │ 0.4.0 │ 0.5.0 │ http://xkbcommon.org/ │
|
||||||
│ xkbcommon-x11│ 0.4.0 │ 0.5.0 │ http://xkbcommon.org/ │
|
│ xkbcommon-x11│ 0.4.0 │ 0.5.0 │ http://xkbcommon.org/ │
|
||||||
│ util-cursor³⁴│ 0.0.99 │ 0.1.2 │ http://xcb.freedesktop.org/dist/ │
|
│ util-cursor³⁴│ 0.0.99 │ 0.1.2 │ http://xcb.freedesktop.org/dist/ │
|
||||||
│ util-wm⁴ │ 0.3.8 │ 0.3.8 │ http://xcb.freedesktop.org/dist/ │
|
│ util-wm⁴ │ 0.3.8 │ 0.3.8 │ http://xcb.freedesktop.org/dist/ │
|
||||||
│ util-keysyms⁴│ 0.3.8 │ 0.4.0 │ http://xcb.freedesktop.org/dist/ │
|
│ util-keysyms⁴│ 0.3.8 │ 0.4.0 │ http://xcb.freedesktop.org/dist/ │
|
||||||
│ libev │ 4.0 │ 4.19 │ http://libev.schmorp.de/ │
|
│ util-xrm⁴ │ 1.0.0 │ 1.0.0 │ https://github.com/Airblader/xcb-util-xrm │
|
||||||
│ yajl │ 2.0.1 │ 2.1.0 │ http://lloyd.github.com/yajl/ │
|
│ libev │ 4.0 │ 4.19 │ http://libev.schmorp.de/ │
|
||||||
│ asciidoc │ 8.3.0 │ 8.6.8 │ http://www.methods.co.nz/asciidoc/ │
|
│ yajl │ 2.0.1 │ 2.1.0 │ http://lloyd.github.com/yajl/ │
|
||||||
│ xmlto │ 0.0.23 │ 0.0.23 │ http://www.methods.co.nz/asciidoc/ │
|
│ asciidoc │ 8.3.0 │ 8.6.8 │ http://www.methods.co.nz/asciidoc/ │
|
||||||
│ Pod::Simple² │ 3.22 │ 3.22 │ http://search.cpan.org/~dwheeler/Pod-Simple-3.23/
|
│ xmlto │ 0.0.23 │ 0.0.23 │ http://www.methods.co.nz/asciidoc/ │
|
||||||
│ docbook-xml │ 4.5 │ 4.5 │ http://www.methods.co.nz/asciidoc/ │
|
│ Pod::Simple² │ 3.22 │ 3.22 │ http://search.cpan.org/~dwheeler/Pod-Simple-3.23/ │
|
||||||
│ PCRE │ 8.12 │ 8.35 │ http://www.pcre.org/ │
|
│ docbook-xml │ 4.5 │ 4.5 │ http://www.methods.co.nz/asciidoc/ │
|
||||||
│ libsn¹ │ 0.10 │ 0.12 │ http://freedesktop.org/wiki/Software/startup-notification
|
│ PCRE │ 8.12 │ 8.35 │ http://www.pcre.org/ │
|
||||||
│ pango │ 1.30.0 | 1.36.8 │ http://www.pango.org/ │
|
│ libsn¹ │ 0.10 │ 0.12 │ http://freedesktop.org/wiki/Software/startup-notification │
|
||||||
│ cairo │ 1.14.4 │ 1.14.4 │ http://cairographics.org/ │
|
│ pango │ 1.30.0 | 1.36.8 │ http://www.pango.org/ │
|
||||||
└──────────────┴────────┴────────┴────────────────────────────────────────┘
|
│ cairo │ 1.14.4 │ 1.14.4 │ http://cairographics.org/ │
|
||||||
|
└──────────────┴────────┴────────┴───────────────────────────────────────────────────────────┘
|
||||||
¹ libsn = libstartup-notification
|
¹ libsn = libstartup-notification
|
||||||
² Pod::Simple is a Perl module required for converting the testsuite
|
² Pod::Simple is a Perl module required for converting the testsuite
|
||||||
documentation to HTML. See http://michael.stapelberg.de/cpan/#Pod::Simple
|
documentation to HTML. See http://michael.stapelberg.de/cpan/#Pod::Simple
|
||||||
|
|
|
@ -126,6 +126,10 @@ XKB_COMMON_LIBS := $(call ldflags_for_lib, xkbcommon,xkbcommon)
|
||||||
XKB_COMMON_X11_CFLAGS := $(call cflags_for_lib, xkbcommon-x11,xkbcommon-x11)
|
XKB_COMMON_X11_CFLAGS := $(call cflags_for_lib, xkbcommon-x11,xkbcommon-x11)
|
||||||
XKB_COMMON_X11_LIBS := $(call ldflags_for_lib, xkbcommon-x11,xkbcommon-x11)
|
XKB_COMMON_X11_LIBS := $(call ldflags_for_lib, xkbcommon-x11,xkbcommon-x11)
|
||||||
|
|
||||||
|
# XCB xrm
|
||||||
|
XCB_XRM_CFLAGS := $(call cflags_for_lib, xcb-xrm)
|
||||||
|
XCB_XRM_LIBS := $(call ldflags_for_lib, xcb-xrm,xcb-xrm)
|
||||||
|
|
||||||
# yajl
|
# yajl
|
||||||
YAJL_CFLAGS := $(call cflags_for_lib, yajl)
|
YAJL_CFLAGS := $(call cflags_for_lib, yajl)
|
||||||
YAJL_LIBS := $(call ldflags_for_lib, yajl,yajl)
|
YAJL_LIBS := $(call ldflags_for_lib, yajl,yajl)
|
||||||
|
|
|
@ -10,6 +10,7 @@ Build-Depends: debhelper (>= 9),
|
||||||
libxcb-randr0-dev,
|
libxcb-randr0-dev,
|
||||||
libxcb-icccm4-dev,
|
libxcb-icccm4-dev,
|
||||||
libxcb-cursor-dev,
|
libxcb-cursor-dev,
|
||||||
|
libxcb-xrm-dev,
|
||||||
libxcb-xkb-dev,
|
libxcb-xkb-dev,
|
||||||
libxkbcommon-dev (>= 0.4.0),
|
libxkbcommon-dev (>= 0.4.0),
|
||||||
libxkbcommon-x11-dev (>= 0.4.0),
|
libxkbcommon-x11-dev (>= 0.4.0),
|
||||||
|
|
|
@ -700,6 +700,38 @@ absolutely no plans to change this. If you need a more dynamic configuration
|
||||||
you should create a little script which generates a configuration file and run
|
you should create a little script which generates a configuration file and run
|
||||||
it before starting i3 (for example in your +~/.xsession+ file).
|
it before starting i3 (for example in your +~/.xsession+ file).
|
||||||
|
|
||||||
|
Also see <<xresources>> to learn how to create variables based on resources
|
||||||
|
loaded from the X resource database.
|
||||||
|
|
||||||
|
[[xresources]]
|
||||||
|
=== X resources
|
||||||
|
|
||||||
|
<<variables>> can also be created using a value configured in the X resource
|
||||||
|
database. This is useful, for example, to avoid configuring color values within
|
||||||
|
the i3 configuration. Instead, the values can be configured, once, in the X
|
||||||
|
resource database to achieve an easily maintainable, consistent color theme
|
||||||
|
across many X applications.
|
||||||
|
|
||||||
|
Defining a resource will load this resource from the resource database and
|
||||||
|
assign its value to the specified variable. A fallback must be specified in
|
||||||
|
case the resource cannot be loaded from the database.
|
||||||
|
|
||||||
|
*Syntax*:
|
||||||
|
----------------------------------------------------
|
||||||
|
set_from_resource $<name> <resource_name> <fallback>
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
*Example*:
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
# The ~/.Xresources should contain a line such as
|
||||||
|
# *color0: #121212
|
||||||
|
# and must be loaded properly, e.g., by using
|
||||||
|
# xrdb ~/.Xresources
|
||||||
|
# This value is picked up on by other applications (e.g., the URxvt terminal
|
||||||
|
# emulator) and can be used in i3 like this:
|
||||||
|
set_from_resource $black i3wm.color0 #000000
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
[[assign_workspace]]
|
[[assign_workspace]]
|
||||||
=== Automatically putting clients on specific workspaces
|
=== Automatically putting clients on specific workspaces
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <yajl/yajl_gen.h>
|
#include <yajl/yajl_gen.h>
|
||||||
|
|
||||||
|
SLIST_HEAD(variables_head, Variable);
|
||||||
extern pid_t config_error_nagbar_pid;
|
extern pid_t config_error_nagbar_pid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -18,6 +18,7 @@ state INITIAL:
|
||||||
error ->
|
error ->
|
||||||
'#' -> IGNORE_LINE
|
'#' -> IGNORE_LINE
|
||||||
'set' -> IGNORE_LINE
|
'set' -> IGNORE_LINE
|
||||||
|
'set_from_resource' -> IGNORE_LINE
|
||||||
bindtype = 'bindsym', 'bindcode', 'bind' -> BINDING
|
bindtype = 'bindsym', 'bindcode', 'bind' -> BINDING
|
||||||
'bar' -> BARBRACE
|
'bar' -> BARBRACE
|
||||||
'font' -> FONT
|
'font' -> FONT
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <xcb/xcb_xrm.h>
|
||||||
|
|
||||||
#include "all.h"
|
#include "all.h"
|
||||||
|
|
||||||
|
@ -42,6 +43,8 @@
|
||||||
#define y(x, ...) yajl_gen_##x(command_output.json_gen, ##__VA_ARGS__)
|
#define y(x, ...) yajl_gen_##x(command_output.json_gen, ##__VA_ARGS__)
|
||||||
#define ystr(str) yajl_gen_string(command_output.json_gen, (unsigned char *)str, strlen(str))
|
#define ystr(str) yajl_gen_string(command_output.json_gen, (unsigned char *)str, strlen(str))
|
||||||
|
|
||||||
|
xcb_xrm_database_t *database = NULL;
|
||||||
|
|
||||||
#ifndef TEST_PARSER
|
#ifndef TEST_PARSER
|
||||||
pid_t config_error_nagbar_pid = -1;
|
pid_t config_error_nagbar_pid = -1;
|
||||||
static struct context *context;
|
static struct context *context;
|
||||||
|
@ -811,18 +814,80 @@ void start_config_error_nagbar(const char *configpath, bool has_errors) {
|
||||||
free(pageraction);
|
free(pageraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inserts or updates a variable assignment depending on whether it already exists.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void upsert_variable(struct variables_head *variables, char *key, char *value) {
|
||||||
|
struct Variable *current;
|
||||||
|
SLIST_FOREACH(current, variables, variables) {
|
||||||
|
if (strcmp(current->key, key) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLOG("Updated variable: %s = %s -> %s\n", key, current->value, value);
|
||||||
|
FREE(current->value);
|
||||||
|
current->value = sstrdup(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLOG("Defined new variable: %s = %s\n", key, value);
|
||||||
|
struct Variable *new = scalloc(1, sizeof(struct Variable));
|
||||||
|
struct Variable *test = NULL, *loc = NULL;
|
||||||
|
new->key = sstrdup(key);
|
||||||
|
new->value = sstrdup(value);
|
||||||
|
/* ensure that the correct variable is matched in case of one being
|
||||||
|
* the prefix of another */
|
||||||
|
SLIST_FOREACH(test, variables, variables) {
|
||||||
|
if (strlen(new->key) >= strlen(test->key))
|
||||||
|
break;
|
||||||
|
loc = test;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loc == NULL) {
|
||||||
|
SLIST_INSERT_HEAD(variables, new, variables);
|
||||||
|
} else {
|
||||||
|
SLIST_INSERT_AFTER(loc, new, variables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_resource(char *name) {
|
||||||
|
if (conn == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load the resource database lazily. */
|
||||||
|
if (database == NULL) {
|
||||||
|
database = xcb_xrm_database_from_default(conn);
|
||||||
|
|
||||||
|
if (database == NULL) {
|
||||||
|
ELOG("Failed to open the resource database.\n");
|
||||||
|
|
||||||
|
/* Load an empty database so we don't keep trying to load the
|
||||||
|
* default database over and over again. */
|
||||||
|
database = xcb_xrm_database_from_string("");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *resource;
|
||||||
|
xcb_xrm_resource_get_string(database, name, NULL, &resource);
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parses the given file by first replacing the variables, then calling
|
* Parses the given file by first replacing the variables, then calling
|
||||||
* parse_config and possibly launching i3-nagbar.
|
* parse_config and possibly launching i3-nagbar.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
bool parse_file(const char *f, bool use_nagbar) {
|
bool parse_file(const char *f, bool use_nagbar) {
|
||||||
SLIST_HEAD(variables_head, Variable) variables = SLIST_HEAD_INITIALIZER(&variables);
|
struct variables_head variables = SLIST_HEAD_INITIALIZER(&variables);
|
||||||
int fd;
|
int fd;
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
char *buf;
|
char *buf;
|
||||||
FILE *fstr;
|
FILE *fstr;
|
||||||
char buffer[4096], key[512], value[512], *continuation = NULL;
|
char buffer[4096], key[512], value[4096], *continuation = NULL;
|
||||||
|
|
||||||
if ((fd = open(f, O_RDONLY)) == -1)
|
if ((fd = open(f, O_RDONLY)) == -1)
|
||||||
die("Could not open configuration file: %s\n", strerror(errno));
|
die("Could not open configuration file: %s\n", strerror(errno));
|
||||||
|
@ -848,8 +913,9 @@ bool parse_file(const char *f, bool use_nagbar) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sscanf implicitly strips whitespace. */
|
/* sscanf implicitly strips whitespace. */
|
||||||
const bool skip_line = (sscanf(buffer, "%511s %511[^\n]", key, value) < 1 || strlen(key) < 3);
|
const bool skip_line = (sscanf(buffer, "%511s %4095[^\n]", key, value) < 1 || strlen(key) < 3);
|
||||||
const bool comment = (key[0] == '#');
|
const bool comment = (key[0] == '#');
|
||||||
|
value[4095] = '\n';
|
||||||
|
|
||||||
continuation = strstr(buffer, "\\\n");
|
continuation = strstr(buffer, "\\\n");
|
||||||
if (continuation) {
|
if (continuation) {
|
||||||
|
@ -868,49 +934,55 @@ bool parse_file(const char *f, bool use_nagbar) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp(key, "set") == 0) {
|
if (strcasecmp(key, "set") == 0) {
|
||||||
if (value[0] != '$') {
|
char v_key[512];
|
||||||
|
char v_value[4096];
|
||||||
|
|
||||||
|
if (sscanf(value, "%511s %4095[^\n]", v_key, v_value) < 1) {
|
||||||
|
ELOG("Failed to parse variable specification '%s', skipping it.\n", value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v_key[0] != '$') {
|
||||||
ELOG("Malformed variable assignment, name has to start with $\n");
|
ELOG("Malformed variable assignment, name has to start with $\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get key/value for this variable */
|
upsert_variable(&variables, v_key, v_value);
|
||||||
char *v_key = value, *v_value;
|
continue;
|
||||||
if (strstr(value, " ") == NULL && strstr(value, "\t") == NULL) {
|
} else if (strcasecmp(key, "set_from_resource") == 0) {
|
||||||
ELOG("Malformed variable assignment, need a value\n");
|
char res_name[512];
|
||||||
|
char v_key[512];
|
||||||
|
char fallback[4096];
|
||||||
|
|
||||||
|
if (sscanf(value, "%511s %511s %4095[^\n]", v_key, res_name, fallback) < 1) {
|
||||||
|
ELOG("Failed to parse resource specification '%s', skipping it.\n", value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(v_value = strstr(value, " ")))
|
if (v_key[0] != '$') {
|
||||||
v_value = strstr(value, "\t");
|
ELOG("Malformed variable assignment, name has to start with $\n");
|
||||||
|
continue;
|
||||||
*(v_value++) = '\0';
|
|
||||||
while (*v_value == '\t' || *v_value == ' ')
|
|
||||||
v_value++;
|
|
||||||
|
|
||||||
struct Variable *new = scalloc(1, sizeof(struct Variable));
|
|
||||||
struct Variable *test = NULL, *loc = NULL;
|
|
||||||
new->key = sstrdup(v_key);
|
|
||||||
new->value = sstrdup(v_value);
|
|
||||||
/* ensure that the correct variable is matched in case of one being
|
|
||||||
* the prefix of another */
|
|
||||||
SLIST_FOREACH(test, &variables, variables) {
|
|
||||||
if (strlen(new->key) >= strlen(test->key))
|
|
||||||
break;
|
|
||||||
loc = test;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loc == NULL) {
|
char *res_value = get_resource(res_name);
|
||||||
SLIST_INSERT_HEAD(&variables, new, variables);
|
if (res_value == NULL) {
|
||||||
} else {
|
DLOG("Could not get resource '%s', using fallback '%s'.\n", res_name, fallback);
|
||||||
SLIST_INSERT_AFTER(loc, new, variables);
|
res_value = sstrdup(fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLOG("Got new variable %s = %s\n", v_key, v_value);
|
upsert_variable(&variables, v_key, res_value);
|
||||||
|
FREE(res_value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(fstr);
|
fclose(fstr);
|
||||||
|
|
||||||
|
if (database != NULL) {
|
||||||
|
xcb_xrm_database_free(database);
|
||||||
|
/* Explicitly set the database to NULL again in case the config gets reloaded. */
|
||||||
|
database = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* For every custom variable, see how often it occurs in the file and
|
/* For every custom variable, see how often it occurs in the file and
|
||||||
* how much extra bytes it requires when replaced. */
|
* how much extra bytes it requires when replaced. */
|
||||||
struct Variable *current, *nearest;
|
struct Variable *current, *nearest;
|
||||||
|
|
|
@ -5,8 +5,8 @@ CLEAN_TARGETS += clean-i3
|
||||||
i3_SOURCES := $(filter-out $(i3_SOURCES_GENERATED),$(wildcard src/*.c))
|
i3_SOURCES := $(filter-out $(i3_SOURCES_GENERATED),$(wildcard src/*.c))
|
||||||
i3_HEADERS_CMDPARSER := $(wildcard include/GENERATED_*.h)
|
i3_HEADERS_CMDPARSER := $(wildcard include/GENERATED_*.h)
|
||||||
i3_HEADERS := $(filter-out $(i3_HEADERS_CMDPARSER),$(wildcard include/*.h))
|
i3_HEADERS := $(filter-out $(i3_HEADERS_CMDPARSER),$(wildcard include/*.h))
|
||||||
i3_CFLAGS = $(XKB_COMMON_CFLAGS) $(XKB_COMMON_X11_CFLAGS) $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(XCB_WM_CFLAGS) $(XCB_CURSOR_CFLAGS) $(PANGO_CFLAGS) $(YAJL_CFLAGS) $(LIBEV_CFLAGS) $(PCRE_CFLAGS) $(LIBSN_CFLAGS)
|
i3_CFLAGS = $(XKB_COMMON_CFLAGS) $(XKB_COMMON_X11_CFLAGS) $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(XCB_WM_CFLAGS) $(XCB_CURSOR_CFLAGS) $(XCB_XRM_CFLAGS) $(PANGO_CFLAGS) $(YAJL_CFLAGS) $(LIBEV_CFLAGS) $(PCRE_CFLAGS) $(LIBSN_CFLAGS)
|
||||||
i3_LIBS = $(XKB_COMMON_LIBS) $(XKB_COMMON_X11_LIBS) $(XCB_LIBS) $(XCB_XKB_LIBS) $(XCB_KBD_LIBS) $(XCB_WM_LIBS) $(XCB_CURSOR_LIBS) $(PANGO_LIBS) $(YAJL_LIBS) $(LIBEV_LIBS) $(PCRE_LIBS) $(LIBSN_LIBS) -lm -lpthread
|
i3_LIBS = $(XKB_COMMON_LIBS) $(XKB_COMMON_X11_LIBS) $(XCB_LIBS) $(XCB_XKB_LIBS) $(XCB_KBD_LIBS) $(XCB_WM_LIBS) $(XCB_CURSOR_LIBS) $(XCB_XRM_LIBS) $(PANGO_LIBS) $(YAJL_LIBS) $(LIBEV_LIBS) $(PCRE_LIBS) $(LIBSN_LIBS) -lm -lpthread
|
||||||
|
|
||||||
# When using clang, we use pre-compiled headers to speed up the build. With
|
# When using clang, we use pre-compiled headers to speed up the build. With
|
||||||
# gcc, this actually makes the build slower.
|
# gcc, this actually makes the build slower.
|
||||||
|
|
|
@ -441,7 +441,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
my $expected_all_tokens = <<'EOT';
|
my $expected_all_tokens = <<'EOT';
|
||||||
ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'no_focus', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder'
|
ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'set_from_resource', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'no_focus', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder'
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
my $expected_end = <<'EOT';
|
my $expected_end = <<'EOT';
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
#!perl
|
||||||
|
# vim:ts=4:sw=4:expandtab
|
||||||
|
#
|
||||||
|
# Please read the following documents before working on tests:
|
||||||
|
# • http://build.i3wm.org/docs/testsuite.html
|
||||||
|
# (or docs/testsuite)
|
||||||
|
#
|
||||||
|
# • http://build.i3wm.org/docs/lib-i3test.html
|
||||||
|
# (alternatively: perldoc ./testcases/lib/i3test.pm)
|
||||||
|
#
|
||||||
|
# • http://build.i3wm.org/docs/ipc.html
|
||||||
|
# (or docs/ipc)
|
||||||
|
#
|
||||||
|
# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
|
||||||
|
# (unless you are already familiar with Perl)
|
||||||
|
#
|
||||||
|
# Tests for using X resources in the config.
|
||||||
|
# Ticket: #2130
|
||||||
|
use i3test i3_autostart => 0;
|
||||||
|
use X11::XCB qw(PROP_MODE_REPLACE);
|
||||||
|
|
||||||
|
sub get_marks {
|
||||||
|
return i3(get_socket_path())->get_marks->recv;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $config = <<EOT;
|
||||||
|
# i3 config file (v4)
|
||||||
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
|
||||||
|
# This isn't necessarily what X resources are intended for, but it'll do the
|
||||||
|
# job for the test.
|
||||||
|
set_from_resource \$mark i3wm.mark none
|
||||||
|
for_window [class=worksforme] mark \$mark
|
||||||
|
|
||||||
|
set_from_resource \$othermark i3wm.doesnotexist none
|
||||||
|
for_window [class=doesnotworkforme] mark \$othermark
|
||||||
|
|
||||||
|
EOT
|
||||||
|
|
||||||
|
$x->change_property(
|
||||||
|
PROP_MODE_REPLACE,
|
||||||
|
$x->get_root_window(),
|
||||||
|
$x->atom(name => 'RESOURCE_MANAGER')->id,
|
||||||
|
$x->atom(name => 'STRING')->id,
|
||||||
|
32,
|
||||||
|
length('*mark: works'),
|
||||||
|
'*mark: works');
|
||||||
|
$x->flush;
|
||||||
|
|
||||||
|
my $pid = launch_with_config($config);
|
||||||
|
|
||||||
|
open_window(wm_class => 'worksforme');
|
||||||
|
sync_with_i3;
|
||||||
|
is_deeply(get_marks(), [ 'works' ], 'the resource has loaded correctly');
|
||||||
|
|
||||||
|
cmd 'kill';
|
||||||
|
|
||||||
|
open_window(wm_class => 'doesnotworkforme');
|
||||||
|
sync_with_i3;
|
||||||
|
is_deeply(get_marks(), [ 'none' ], 'the resource fallback was used');
|
||||||
|
|
||||||
|
exit_gracefully($pid);
|
||||||
|
|
||||||
|
done_testing;
|
|
@ -27,3 +27,14 @@ COPY debian/control /usr/src/i3-debian-packaging/control
|
||||||
RUN linux32 apt-get update && \
|
RUN linux32 apt-get update && \
|
||||||
DEBIAN_FRONTEND=noninteractive mk-build-deps --install --remove --tool 'apt-get --no-install-recommends -y' /usr/src/i3-debian-packaging/control && \
|
DEBIAN_FRONTEND=noninteractive mk-build-deps --install --remove --tool 'apt-get --no-install-recommends -y' /usr/src/i3-debian-packaging/control && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install xcb-util-xrm. This is a workaround until it is available in the
|
||||||
|
# distribution packages.
|
||||||
|
RUN apt-get update && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends xutils-dev
|
||||||
|
RUN git clone --recursive https://github.com/Airblader/xcb-util-xrm.git && \
|
||||||
|
cd xcb-util-xrm && \
|
||||||
|
./autogen.sh --prefix=/usr && \
|
||||||
|
make && \
|
||||||
|
make install && \
|
||||||
|
cd -
|
||||||
|
|
|
@ -28,3 +28,14 @@ COPY debian/control /usr/src/i3-debian-packaging/control
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
DEBIAN_FRONTEND=noninteractive mk-build-deps --install --remove --tool 'apt-get --no-install-recommends -y' /usr/src/i3-debian-packaging/control && \
|
DEBIAN_FRONTEND=noninteractive mk-build-deps --install --remove --tool 'apt-get --no-install-recommends -y' /usr/src/i3-debian-packaging/control && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install xcb-util-xrm. This is a workaround until it is available in the
|
||||||
|
# distribution packages.
|
||||||
|
RUN apt-get update && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends xutils-dev
|
||||||
|
RUN git clone --recursive https://github.com/Airblader/xcb-util-xrm.git && \
|
||||||
|
cd xcb-util-xrm && \
|
||||||
|
./autogen.sh --prefix=/usr && \
|
||||||
|
make && \
|
||||||
|
make install && \
|
||||||
|
cd -
|
||||||
|
|
Loading…
Reference in New Issue