Time Lord technology: for_window config directive to run arbitrary cmds
An example to set all XTerms floating: for_window [class="XTerm"] mode floating To make all urxvts use a 1-pixel border: for_window [class="urxvt"] border 1pixel A less useful, but rather funny example: for_window [title="x200: ~/work"] mode floating The commands are not completely arbitrary. The commands above were tested, others may need some fixing. Internally, windows are compared against your criteria (class, title, …) when they are initially managed and whenever one of the relevant values change. Then, the specified command is run *once* (per window). It gets prefixed with a criteria to make it match only the specific window that triggered it. So, if you configure "mode floating", i3 runs something like '[id="8393923"] mode floating'.
This commit is contained in:
parent
ca2e4199b5
commit
5ae4620a24
2
Makefile
2
Makefile
|
@ -4,7 +4,7 @@ include $(TOPDIR)/common.mk
|
||||||
|
|
||||||
# Depend on the object files of all source-files in src/*.c and on all header files
|
# Depend on the object files of all source-files in src/*.c and on all header files
|
||||||
AUTOGENERATED:=src/cfgparse.tab.c src/cfgparse.yy.c src/cmdparse.tab.c src/cmdparse.yy.c
|
AUTOGENERATED:=src/cfgparse.tab.c src/cfgparse.yy.c src/cmdparse.tab.c src/cmdparse.yy.c
|
||||||
FILES:=src/ipc.c src/main.c src/log.c src/util.c src/tree.c src/xcb.c src/manage.c src/workspace.c src/x.c src/floating.c src/click.c src/config.c src/handlers.c src/randr.c src/xinerama.c src/con.c src/load_layout.c src/render.c src/window.c src/match.c src/xcursor.c src/resize.c src/sighandler.c src/move.c src/output.c src/ewmh.c
|
FILES:=src/ipc.c src/main.c src/log.c src/util.c src/tree.c src/xcb.c src/manage.c src/workspace.c src/x.c src/floating.c src/click.c src/config.c src/handlers.c src/randr.c src/xinerama.c src/con.c src/load_layout.c src/render.c src/window.c src/match.c src/xcursor.c src/resize.c src/sighandler.c src/move.c src/output.c src/ewmh.c src/assignments.c
|
||||||
FILES:=$(FILES:.c=.o)
|
FILES:=$(FILES:.c=.o)
|
||||||
HEADERS:=$(filter-out include/loglevels.h,$(wildcard include/*.h))
|
HEADERS:=$(filter-out include/loglevels.h,$(wildcard include/*.h))
|
||||||
|
|
||||||
|
|
|
@ -62,5 +62,6 @@
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
#include "ewmh.h"
|
#include "ewmh.h"
|
||||||
|
#include "assignments.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* vim:ts=4:sw=4:expandtab
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef _ASSIGNMENTS_H
|
||||||
|
#define _ASSIGNMENTS_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the list of assignments for the given window and runs all matching
|
||||||
|
* ones (unless they have already been run for this specific window).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void run_assignments(i3Window *window);
|
||||||
|
|
||||||
|
#endif
|
|
@ -33,6 +33,7 @@ typedef struct Rect Rect;
|
||||||
typedef struct xoutput Output;
|
typedef struct xoutput Output;
|
||||||
typedef struct Con Con;
|
typedef struct Con Con;
|
||||||
typedef struct Match Match;
|
typedef struct Match Match;
|
||||||
|
typedef struct Assignment Assignment;
|
||||||
typedef struct Window i3Window;
|
typedef struct Window i3Window;
|
||||||
|
|
||||||
|
|
||||||
|
@ -274,11 +275,14 @@ struct Window {
|
||||||
|
|
||||||
/** Pixels the window reserves. left/right/top/bottom */
|
/** Pixels the window reserves. left/right/top/bottom */
|
||||||
struct reservedpx reserved;
|
struct reservedpx reserved;
|
||||||
|
|
||||||
|
/** Pointers to the Assignments which were already ran for this Window
|
||||||
|
* (assignments run only once) */
|
||||||
|
uint32_t nr_assignments;
|
||||||
|
Assignment **ran_assignments;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Match {
|
struct Match {
|
||||||
enum { M_WINDOW, M_CON } what;
|
|
||||||
|
|
||||||
char *title;
|
char *title;
|
||||||
int title_len;
|
int title_len;
|
||||||
char *application;
|
char *application;
|
||||||
|
@ -296,10 +300,6 @@ struct Match {
|
||||||
Con *con_id;
|
Con *con_id;
|
||||||
enum { M_ANY = 0, M_TILING, M_FLOATING } floating;
|
enum { M_ANY = 0, M_TILING, M_FLOATING } floating;
|
||||||
|
|
||||||
enum { M_GLOBAL = 0, M_OUTPUT, M_WORKSPACE } levels;
|
|
||||||
|
|
||||||
enum { M_USER = 0, M_RESTART } source;
|
|
||||||
|
|
||||||
char *target_ws;
|
char *target_ws;
|
||||||
|
|
||||||
/* Where the window looking for a match should be inserted:
|
/* Where the window looking for a match should be inserted:
|
||||||
|
@ -317,6 +317,29 @@ struct Match {
|
||||||
TAILQ_ENTRY(Match) assignments;
|
TAILQ_ENTRY(Match) assignments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Assignment {
|
||||||
|
/** type of this assignment:
|
||||||
|
*
|
||||||
|
* A_COMMAND = run the specified command for the matching window
|
||||||
|
* A_TO_WORKSPACE = assign the matching window to the specified workspace
|
||||||
|
* A_TO_OUTPUT = assign the matching window to the specified output
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum { A_COMMAND = 0, A_TO_WORKSPACE = 1, A_TO_OUTPUT = 2 } type;
|
||||||
|
|
||||||
|
/** the criteria to check if a window matches */
|
||||||
|
Match match;
|
||||||
|
|
||||||
|
/** destination workspace/output/command, depending on the type */
|
||||||
|
union {
|
||||||
|
char *command;
|
||||||
|
char *workspace;
|
||||||
|
char *output;
|
||||||
|
} dest;
|
||||||
|
|
||||||
|
TAILQ_ENTRY(Assignment) real_assignments;
|
||||||
|
};
|
||||||
|
|
||||||
struct Con {
|
struct Con {
|
||||||
bool mapped;
|
bool mapped;
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -28,6 +28,7 @@ extern TAILQ_HEAD(bindings_head, Binding) *bindings;
|
||||||
extern TAILQ_HEAD(autostarts_head, Autostart) autostarts;
|
extern TAILQ_HEAD(autostarts_head, Autostart) autostarts;
|
||||||
extern TAILQ_HEAD(assignments_head, Match) assignments;
|
extern TAILQ_HEAD(assignments_head, Match) assignments;
|
||||||
extern TAILQ_HEAD(ws_assignments_head, Workspace_Assignment) ws_assignments;
|
extern TAILQ_HEAD(ws_assignments_head, Workspace_Assignment) ws_assignments;
|
||||||
|
extern TAILQ_HEAD(real_assignments_head, Assignment) real_assignments;
|
||||||
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
|
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
|
||||||
extern uint8_t root_depth;
|
extern uint8_t root_depth;
|
||||||
extern bool xcursor_supported, xkb_supported;
|
extern bool xcursor_supported, xkb_supported;
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
* given window.
|
* given window.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void window_update_class(i3Window *win, xcb_get_property_reply_t *prop);
|
void window_update_class(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the name by using _NET_WM_NAME (encoded in UTF-8) for the given
|
* Updates the name by using _NET_WM_NAME (encoded in UTF-8) for the given
|
||||||
* window. Further updates using window_update_name_legacy will be ignored.
|
* window. Further updates using window_update_name_legacy will be ignored.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void window_update_name(i3Window *win, xcb_get_property_reply_t *prop);
|
void window_update_name(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the name by using WM_NAME (encoded in COMPOUND_TEXT). We do not
|
* Updates the name by using WM_NAME (encoded in COMPOUND_TEXT). We do not
|
||||||
|
@ -22,7 +22,7 @@ void window_update_name(i3Window *win, xcb_get_property_reply_t *prop);
|
||||||
* window_update_name()).
|
* window_update_name()).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop);
|
void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the CLIENT_LEADER (logical parent window).
|
* Updates the CLIENT_LEADER (logical parent window).
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* vim:ts=4:sw=4:expandtab
|
||||||
|
*
|
||||||
|
* i3 - an improved dynamic tiling window manager
|
||||||
|
* © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks the list of assignments for the given window and runs all matching
|
||||||
|
* ones (unless they have already been run for this specific window).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void run_assignments(i3Window *window) {
|
||||||
|
DLOG("Checking assignments...\n");
|
||||||
|
|
||||||
|
/* Check if any assignments match */
|
||||||
|
Assignment *current;
|
||||||
|
TAILQ_FOREACH(current, &real_assignments, real_assignments) {
|
||||||
|
if (!match_matches_window(&(current->match), window))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool skip = false;
|
||||||
|
for (int c = 0; c < window->nr_assignments; c++) {
|
||||||
|
if (window->ran_assignments[c] != current)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DLOG("This assignment already ran for the given window, not executing it again.\n");
|
||||||
|
skip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DLOG("matching assignment, would do:\n");
|
||||||
|
if (current->type == A_COMMAND) {
|
||||||
|
DLOG("execute command %s\n", current->dest.command);
|
||||||
|
char *full_command;
|
||||||
|
asprintf(&full_command, "[id=\"%d\"] %s", window->id, current->dest.command);
|
||||||
|
parse_cmd(full_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store that we ran this assignment to not execute it again */
|
||||||
|
window->nr_assignments++;
|
||||||
|
window->ran_assignments = srealloc(window->ran_assignments, sizeof(Assignment*) * window->nr_assignments);
|
||||||
|
window->ran_assignments[window->nr_assignments-1] = current;
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,9 @@ EOL (\r?\n)
|
||||||
%s COLOR_COND
|
%s COLOR_COND
|
||||||
%s OUTPUT_COND
|
%s OUTPUT_COND
|
||||||
%s OUTPUT_AWS_COND
|
%s OUTPUT_AWS_COND
|
||||||
|
%s WANT_QSTRING
|
||||||
|
%s FOR_WINDOW_COND
|
||||||
|
%s REQUIRE_WS
|
||||||
%x BUFFER_LINE
|
%x BUFFER_LINE
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@ -68,6 +71,16 @@ EOL (\r?\n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<FOR_WINDOW_COND>"]" { yy_pop_state(); return ']'; }
|
||||||
|
<REQUIRE_WS>[ \t]* { yy_pop_state(); return WHITESPACE; }
|
||||||
|
<WANT_QSTRING>\"[^\"]+\" {
|
||||||
|
yy_pop_state();
|
||||||
|
/* strip quotes */
|
||||||
|
char *copy = sstrdup(yytext+1);
|
||||||
|
copy[strlen(copy)-1] = '\0';
|
||||||
|
yylval.string = copy;
|
||||||
|
return STR;
|
||||||
|
}
|
||||||
<BIND_A2WS_COND>[^\n]+ { BEGIN(INITIAL); yylval.string = strdup(yytext); return STR; }
|
<BIND_A2WS_COND>[^\n]+ { BEGIN(INITIAL); yylval.string = strdup(yytext); return STR; }
|
||||||
<OUTPUT_AWS_COND>[a-zA-Z0-9_-]+ { yylval.string = strdup(yytext); return OUTPUT; }
|
<OUTPUT_AWS_COND>[a-zA-Z0-9_-]+ { yylval.string = strdup(yytext); return OUTPUT; }
|
||||||
^[ \t]*#[^\n]* { return TOKCOMMENT; }
|
^[ \t]*#[^\n]* { return TOKCOMMENT; }
|
||||||
|
@ -108,6 +121,18 @@ workspace_bar { return TOKWORKSPACEBAR; }
|
||||||
popup_during_fullscreen { return TOK_POPUP_DURING_FULLSCREEN; }
|
popup_during_fullscreen { return TOK_POPUP_DURING_FULLSCREEN; }
|
||||||
ignore { return TOK_IGNORE; }
|
ignore { return TOK_IGNORE; }
|
||||||
leave_fullscreen { return TOK_LEAVE_FULLSCREEN; }
|
leave_fullscreen { return TOK_LEAVE_FULLSCREEN; }
|
||||||
|
for_window {
|
||||||
|
/* Example: for_window [class="urxvt"] border none
|
||||||
|
*
|
||||||
|
* First, we wait for the ']' that finishes a match (FOR_WINDOW_COND)
|
||||||
|
* Then, we require a whitespace (REQUIRE_WS)
|
||||||
|
* And the rest of the line is parsed as a string
|
||||||
|
*/
|
||||||
|
yy_push_state(BIND_A2WS_COND);
|
||||||
|
yy_push_state(REQUIRE_WS);
|
||||||
|
yy_push_state(FOR_WINDOW_COND);
|
||||||
|
return TOK_FOR_WINDOW;
|
||||||
|
}
|
||||||
default { /* yylval.number = MODE_DEFAULT; */return TOK_DEFAULT; }
|
default { /* yylval.number = MODE_DEFAULT; */return TOK_DEFAULT; }
|
||||||
stacking { /* yylval.number = MODE_STACK; */return TOK_STACKING; }
|
stacking { /* yylval.number = MODE_STACK; */return TOK_STACKING; }
|
||||||
stacked { return TOK_STACKING; }
|
stacked { return TOK_STACKING; }
|
||||||
|
@ -134,6 +159,13 @@ control { return TOKCONTROL; }
|
||||||
ctrl { return TOKCONTROL; }
|
ctrl { return TOKCONTROL; }
|
||||||
shift { return TOKSHIFT; }
|
shift { return TOKSHIFT; }
|
||||||
→ { return TOKARROW; }
|
→ { return TOKARROW; }
|
||||||
|
|
||||||
|
class { yy_push_state(WANT_QSTRING); return TOK_CLASS; }
|
||||||
|
id { yy_push_state(WANT_QSTRING); return TOK_ID; }
|
||||||
|
con_id { yy_push_state(WANT_QSTRING); return TOK_CON_ID; }
|
||||||
|
con_mark { yy_push_state(WANT_QSTRING); return TOK_MARK; }
|
||||||
|
title { yy_push_state(WANT_QSTRING); return TOK_TITLE; }
|
||||||
|
|
||||||
{EOL} {
|
{EOL} {
|
||||||
FREE(context->line_copy);
|
FREE(context->line_copy);
|
||||||
context->line_number++;
|
context->line_number++;
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "all.h"
|
#include "all.h"
|
||||||
|
|
||||||
|
static Match current_match;
|
||||||
|
|
||||||
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||||
extern int yylex(struct context *context);
|
extern int yylex(struct context *context);
|
||||||
extern int yyparse(void);
|
extern int yyparse(void);
|
||||||
|
@ -242,6 +245,13 @@ void parse_file(const char *f) {
|
||||||
%token TOK_POPUP_DURING_FULLSCREEN "popup_during_fullscreen"
|
%token TOK_POPUP_DURING_FULLSCREEN "popup_during_fullscreen"
|
||||||
%token TOK_IGNORE "ignore"
|
%token TOK_IGNORE "ignore"
|
||||||
%token TOK_LEAVE_FULLSCREEN "leave_fullscreen"
|
%token TOK_LEAVE_FULLSCREEN "leave_fullscreen"
|
||||||
|
%token TOK_FOR_WINDOW "for_window"
|
||||||
|
|
||||||
|
%token TOK_MARK "mark"
|
||||||
|
%token TOK_CLASS "class"
|
||||||
|
%token TOK_ID "id"
|
||||||
|
%token TOK_CON_ID "con_id"
|
||||||
|
%token TOK_TITLE "title"
|
||||||
|
|
||||||
%type <binding> binding
|
%type <binding> binding
|
||||||
%type <binding> bindcode
|
%type <binding> bindcode
|
||||||
|
@ -272,6 +282,7 @@ lines: /* empty */
|
||||||
|
|
||||||
line:
|
line:
|
||||||
bindline
|
bindline
|
||||||
|
| for_window
|
||||||
| mode
|
| mode
|
||||||
| floating_modifier
|
| floating_modifier
|
||||||
| orientation
|
| orientation
|
||||||
|
@ -292,6 +303,10 @@ line:
|
||||||
| popup_during_fullscreen
|
| popup_during_fullscreen
|
||||||
;
|
;
|
||||||
|
|
||||||
|
optwhitespace:
|
||||||
|
| WHITESPACE
|
||||||
|
;
|
||||||
|
|
||||||
comment:
|
comment:
|
||||||
TOKCOMMENT
|
TOKCOMMENT
|
||||||
;
|
;
|
||||||
|
@ -340,6 +355,90 @@ bindsym:
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
for_window:
|
||||||
|
TOK_FOR_WINDOW WHITESPACE match WHITESPACE command
|
||||||
|
{
|
||||||
|
printf("\t should execute command %s for the criteria mentioned above\n", $5);
|
||||||
|
Assignment *assignment = scalloc(sizeof(Assignment));
|
||||||
|
assignment->type = A_COMMAND;
|
||||||
|
assignment->match = current_match;
|
||||||
|
assignment->dest.command = $5;
|
||||||
|
TAILQ_INSERT_TAIL(&real_assignments, assignment, real_assignments);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
match:
|
||||||
|
| matchstart optwhitespace criteria optwhitespace matchend
|
||||||
|
{
|
||||||
|
printf("match parsed\n");
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
matchstart:
|
||||||
|
'['
|
||||||
|
{
|
||||||
|
printf("start\n");
|
||||||
|
match_init(¤t_match);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
matchend:
|
||||||
|
']'
|
||||||
|
{
|
||||||
|
printf("match specification finished\n");
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
criteria:
|
||||||
|
TOK_CLASS '=' STR
|
||||||
|
{
|
||||||
|
printf("criteria: class = %s\n", $3);
|
||||||
|
current_match.class = $3;
|
||||||
|
}
|
||||||
|
| TOK_CON_ID '=' STR
|
||||||
|
{
|
||||||
|
printf("criteria: id = %s\n", $3);
|
||||||
|
char *end;
|
||||||
|
long parsed = strtol($3, &end, 10);
|
||||||
|
if (parsed == LONG_MIN ||
|
||||||
|
parsed == LONG_MAX ||
|
||||||
|
parsed < 0 ||
|
||||||
|
(end && *end != '\0')) {
|
||||||
|
ELOG("Could not parse con id \"%s\"\n", $3);
|
||||||
|
} else {
|
||||||
|
current_match.con_id = (Con*)parsed;
|
||||||
|
printf("id as int = %p\n", current_match.con_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| TOK_ID '=' STR
|
||||||
|
{
|
||||||
|
printf("criteria: window id = %s\n", $3);
|
||||||
|
char *end;
|
||||||
|
long parsed = strtol($3, &end, 10);
|
||||||
|
if (parsed == LONG_MIN ||
|
||||||
|
parsed == LONG_MAX ||
|
||||||
|
parsed < 0 ||
|
||||||
|
(end && *end != '\0')) {
|
||||||
|
ELOG("Could not parse window id \"%s\"\n", $3);
|
||||||
|
} else {
|
||||||
|
current_match.id = parsed;
|
||||||
|
printf("window id as int = %d\n", current_match.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| TOK_MARK '=' STR
|
||||||
|
{
|
||||||
|
printf("criteria: mark = %s\n", $3);
|
||||||
|
current_match.mark = $3;
|
||||||
|
}
|
||||||
|
| TOK_TITLE '=' STR
|
||||||
|
{
|
||||||
|
printf("criteria: title = %s\n", $3);
|
||||||
|
current_match.title = $3;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
word_or_number:
|
word_or_number:
|
||||||
WORD
|
WORD
|
||||||
| NUMBER
|
| NUMBER
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* vim:ts=4:sw=4:expandtab
|
* vim:ts=4:sw=4:expandtab
|
||||||
*
|
*
|
||||||
* i3 - an improved dynamic tiling window manager
|
* i3 - an improved dynamic tiling window manager
|
||||||
* © 2009-2010 Michael Stapelberg and contributors (see also: LICENSE)
|
* © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
|
||||||
*
|
*
|
||||||
* cmdparse.y: the parser for commands you send to i3 (or bind on keys)
|
* cmdparse.y: the parser for commands you send to i3 (or bind on keys)
|
||||||
*
|
*
|
||||||
|
@ -80,6 +80,7 @@ int cmdyywrap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
char *parse_cmd(const char *new) {
|
char *parse_cmd(const char *new) {
|
||||||
|
LOG("COMMAND: *%s*\n", new);
|
||||||
cmdyy_scan_string(new);
|
cmdyy_scan_string(new);
|
||||||
|
|
||||||
match_init(¤t_match);
|
match_init(¤t_match);
|
||||||
|
@ -512,15 +513,21 @@ direction:
|
||||||
mode:
|
mode:
|
||||||
TOK_MODE WHITESPACE window_mode
|
TOK_MODE WHITESPACE window_mode
|
||||||
{
|
{
|
||||||
if ($3 == TOK_TOGGLE) {
|
HANDLE_EMPTY_MATCH;
|
||||||
printf("should toggle mode\n");
|
|
||||||
toggle_floating_mode(focused, false);
|
owindow *current;
|
||||||
} else {
|
TAILQ_FOREACH(current, &owindows, owindows) {
|
||||||
printf("should switch mode to %s\n", ($3 == TOK_FLOATING ? "floating" : "tiling"));
|
printf("matching: %p / %s\n", current->con, current->con->name);
|
||||||
if ($3 == TOK_FLOATING) {
|
if ($3 == TOK_TOGGLE) {
|
||||||
floating_enable(focused, false);
|
printf("should toggle mode\n");
|
||||||
|
toggle_floating_mode(current->con, false);
|
||||||
} else {
|
} else {
|
||||||
floating_disable(focused, false);
|
printf("should switch mode to %s\n", ($3 == TOK_FLOATING ? "floating" : "tiling"));
|
||||||
|
if ($3 == TOK_FLOATING) {
|
||||||
|
floating_enable(current->con, false);
|
||||||
|
} else {
|
||||||
|
floating_disable(current->con, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -608,11 +615,14 @@ layout:
|
||||||
printf("changing layout to %d\n", $3);
|
printf("changing layout to %d\n", $3);
|
||||||
owindow *current;
|
owindow *current;
|
||||||
|
|
||||||
HANDLE_EMPTY_MATCH;
|
/* check if the match is empty, not if the result is empty */
|
||||||
|
if (match_is_empty(¤t_match))
|
||||||
TAILQ_FOREACH(current, &owindows, owindows) {
|
con_set_layout(focused->parent, $3);
|
||||||
printf("matching: %p / %s\n", current->con, current->con->name);
|
else {
|
||||||
con_set_layout(current->con, $3);
|
TAILQ_FOREACH(current, &owindows, owindows) {
|
||||||
|
printf("matching: %p / %s\n", current->con, current->con->name);
|
||||||
|
con_set_layout(current->con, $3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
@ -541,7 +541,7 @@ static int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t
|
||||||
if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
|
if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
window_update_name(con->window, prop);
|
window_update_name(con->window, prop, false);
|
||||||
|
|
||||||
x_push_changes(croot);
|
x_push_changes(croot);
|
||||||
|
|
||||||
|
@ -559,7 +559,7 @@ static int handle_windowname_change_legacy(void *data, xcb_connection_t *conn, u
|
||||||
if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
|
if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
window_update_name_legacy(con->window, prop);
|
window_update_name_legacy(con->window, prop, false);
|
||||||
|
|
||||||
x_push_changes(croot);
|
x_push_changes(croot);
|
||||||
|
|
||||||
|
@ -576,7 +576,7 @@ static int handle_windowclass_change(void *data, xcb_connection_t *conn, uint8_t
|
||||||
if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
|
if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
window_update_class(con->window, prop);
|
window_update_class(con->window, prop, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,8 @@ struct assignments_head assignments = TAILQ_HEAD_INITIALIZER(assignments);
|
||||||
* output) */
|
* output) */
|
||||||
struct ws_assignments_head ws_assignments = TAILQ_HEAD_INITIALIZER(ws_assignments);
|
struct ws_assignments_head ws_assignments = TAILQ_HEAD_INITIALIZER(ws_assignments);
|
||||||
|
|
||||||
|
struct real_assignments_head real_assignments = TAILQ_HEAD_INITIALIZER(real_assignments);
|
||||||
|
|
||||||
/* We hope that those are supported and set them to true */
|
/* We hope that those are supported and set them to true */
|
||||||
bool xcursor_supported = true;
|
bool xcursor_supported = true;
|
||||||
bool xkb_supported = true;
|
bool xkb_supported = true;
|
||||||
|
|
|
@ -158,9 +158,9 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||||
|
|
||||||
|
|
||||||
/* update as much information as possible so far (some replies may be NULL) */
|
/* update as much information as possible so far (some replies may be NULL) */
|
||||||
window_update_class(cwindow, xcb_get_property_reply(conn, class_cookie, NULL));
|
window_update_class(cwindow, xcb_get_property_reply(conn, class_cookie, NULL), true);
|
||||||
window_update_name_legacy(cwindow, xcb_get_property_reply(conn, title_cookie, NULL));
|
window_update_name_legacy(cwindow, xcb_get_property_reply(conn, title_cookie, NULL), true);
|
||||||
window_update_name(cwindow, xcb_get_property_reply(conn, utf8_title_cookie, NULL));
|
window_update_name(cwindow, xcb_get_property_reply(conn, utf8_title_cookie, NULL), true);
|
||||||
window_update_leader(cwindow, xcb_get_property_reply(conn, leader_cookie, NULL));
|
window_update_leader(cwindow, xcb_get_property_reply(conn, leader_cookie, NULL));
|
||||||
window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL));
|
window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL));
|
||||||
window_update_strut_partial(cwindow, xcb_get_property_reply(conn, strut_cookie, NULL));
|
window_update_strut_partial(cwindow, xcb_get_property_reply(conn, strut_cookie, NULL));
|
||||||
|
@ -330,6 +330,9 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||||
* cleanup) */
|
* cleanup) */
|
||||||
xcb_change_save_set(conn, XCB_SET_MODE_INSERT, window);
|
xcb_change_save_set(conn, XCB_SET_MODE_INSERT, window);
|
||||||
|
|
||||||
|
/* Check if any assignments match */
|
||||||
|
run_assignments(cwindow);
|
||||||
|
|
||||||
tree_render();
|
tree_render();
|
||||||
|
|
||||||
free(geom);
|
free(geom);
|
||||||
|
|
|
@ -66,6 +66,12 @@ bool match_matches_window(Match *match, i3Window *window) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: pcre match */
|
||||||
|
if (match->title != NULL && window->name_json != NULL && strcasecmp(match->title, window->name_json) == 0) {
|
||||||
|
LOG("match made by title (%s)\n", window->name_json);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
LOG("match->dock = %d, window->dock = %d\n", match->dock, window->dock);
|
LOG("match->dock = %d, window->dock = %d\n", match->dock, window->dock);
|
||||||
if (match->dock != -1 &&
|
if (match->dock != -1 &&
|
||||||
((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
|
((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
|
||||||
|
|
23
src/window.c
23
src/window.c
|
@ -2,7 +2,7 @@
|
||||||
* vim:ts=4:sw=4:expandtab
|
* vim:ts=4:sw=4:expandtab
|
||||||
*
|
*
|
||||||
* i3 - an improved dynamic tiling window manager
|
* i3 - an improved dynamic tiling window manager
|
||||||
* © 2009-2010 Michael Stapelberg and contributors (see also: LICENSE)
|
* © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "all.h"
|
#include "all.h"
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
* given window.
|
* given window.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void window_update_class(i3Window *win, xcb_get_property_reply_t *prop) {
|
void window_update_class(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt) {
|
||||||
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
||||||
DLOG("empty property, not updating\n");
|
DLOG("empty property, not updating\n");
|
||||||
return;
|
return;
|
||||||
|
@ -32,6 +32,11 @@ void window_update_class(i3Window *win, xcb_get_property_reply_t *prop) {
|
||||||
else win->class_class = NULL;
|
else win->class_class = NULL;
|
||||||
LOG("WM_CLASS changed to %s (instance), %s (class)\n",
|
LOG("WM_CLASS changed to %s (instance), %s (class)\n",
|
||||||
win->class_instance, win->class_class);
|
win->class_instance, win->class_class);
|
||||||
|
|
||||||
|
if (before_mgmt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
run_assignments(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -39,7 +44,7 @@ void window_update_class(i3Window *win, xcb_get_property_reply_t *prop) {
|
||||||
* window. Further updates using window_update_name_legacy will be ignored.
|
* window. Further updates using window_update_name_legacy will be ignored.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void window_update_name(i3Window *win, xcb_get_property_reply_t *prop) {
|
void window_update_name(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt) {
|
||||||
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
||||||
DLOG("_NET_WM_NAME not specified, not changing\n");
|
DLOG("_NET_WM_NAME not specified, not changing\n");
|
||||||
return;
|
return;
|
||||||
|
@ -70,6 +75,11 @@ void window_update_name(i3Window *win, xcb_get_property_reply_t *prop) {
|
||||||
LOG("_NET_WM_NAME changed to \"%s\"\n", win->name_json);
|
LOG("_NET_WM_NAME changed to \"%s\"\n", win->name_json);
|
||||||
|
|
||||||
win->uses_net_wm_name = true;
|
win->uses_net_wm_name = true;
|
||||||
|
|
||||||
|
if (before_mgmt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
run_assignments(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -79,7 +89,7 @@ void window_update_name(i3Window *win, xcb_get_property_reply_t *prop) {
|
||||||
* window_update_name()).
|
* window_update_name()).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop) {
|
void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt) {
|
||||||
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
||||||
DLOG("prop == NULL\n");
|
DLOG("prop == NULL\n");
|
||||||
return;
|
return;
|
||||||
|
@ -106,6 +116,11 @@ void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop) {
|
||||||
win->name_json = sstrdup(new_name);
|
win->name_json = sstrdup(new_name);
|
||||||
win->name_len = strlen(new_name);
|
win->name_len = strlen(new_name);
|
||||||
win->name_x_changed = true;
|
win->name_x_changed = true;
|
||||||
|
|
||||||
|
if (before_mgmt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
run_assignments(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue