commit
5778c59a2f
@ -0,0 +1,52 @@
|
||||
# sway security rules
|
||||
#
|
||||
# Read sway-security(7) for details on how to secure your sway install.
|
||||
#
|
||||
# You MUST read this man page if you intend to attempt to secure your sway
|
||||
# installation.
|
||||
|
||||
# Configures which programs are allowed to use which sway features
|
||||
permit * fullscreen keyboard mouse ipc
|
||||
permit __PREFIX__/bin/swaylock lock
|
||||
permit __PREFIX__/bin/swaybar panel
|
||||
permit __PREFIX__/bin/swaybg background
|
||||
permit __PREFIX__/bin/swaygrab screenshot
|
||||
|
||||
# Configures which IPC features are enabled
|
||||
ipc {
|
||||
command enabled
|
||||
outputs enabled
|
||||
workspaces enabled
|
||||
tree enabled
|
||||
marks enabled
|
||||
bar-config enabled
|
||||
inputs enabled
|
||||
|
||||
events {
|
||||
workspace enabled
|
||||
output enabled
|
||||
mode enabled
|
||||
window enabled
|
||||
modifier enabled
|
||||
input enabled
|
||||
binding disabled
|
||||
}
|
||||
}
|
||||
|
||||
# Limits the contexts from which certain commands are permitted
|
||||
commands {
|
||||
* all
|
||||
|
||||
fullscreen binding criteria
|
||||
bindsym config
|
||||
exit binding
|
||||
kill binding
|
||||
|
||||
# You should not change these unless you know what you're doing - it could
|
||||
# cripple your security
|
||||
reload binding
|
||||
restart binding
|
||||
permit config
|
||||
reject config
|
||||
ipc config
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#ifndef _SWAY_SECURITY_H
|
||||
#define _SWAY_SECURITY_H
|
||||
#include <unistd.h>
|
||||
#include "sway/config.h"
|
||||
|
||||
enum secure_feature get_feature_policy(pid_t pid);
|
||||
enum command_context get_command_policy(const char *cmd);
|
||||
|
||||
const char *command_policy_str(enum command_context context);
|
||||
|
||||
struct feature_policy *alloc_feature_policy(const char *program);
|
||||
struct command_policy *alloc_command_policy(const char *command);
|
||||
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
struct cmd_results *cmd_commands(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "commands", EXPECTED_EQUAL_TO, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (strcmp(argv[0], "{") != 0) {
|
||||
return cmd_results_new(CMD_FAILURE, "commands", "Expected block declaration");
|
||||
}
|
||||
|
||||
if (!config->reading) {
|
||||
return cmd_results_new(CMD_FAILURE, "commands", "Can only be used in config file.");
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_BLOCK_COMMANDS, NULL, NULL);
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "ipc.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
struct cmd_results *cmd_ipc(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (config->reading && strcmp("{", argv[0]) != 0) {
|
||||
return cmd_results_new(CMD_INVALID, "ipc",
|
||||
"Expected '{' at start of IPC config definition.");
|
||||
}
|
||||
|
||||
if (!config->reading) {
|
||||
return cmd_results_new(CMD_FAILURE, "ipc", "Can only be used in config file.");
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_BLOCK_IPC, NULL, NULL);
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_ipc_events(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "events", EXPECTED_EQUAL_TO, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (config->reading && strcmp("{", argv[0]) != 0) {
|
||||
return cmd_results_new(CMD_INVALID, "events",
|
||||
"Expected '{' at start of IPC event config definition.");
|
||||
}
|
||||
|
||||
if (!config->reading) {
|
||||
return cmd_results_new(CMD_FAILURE, "events", "Can only be used in config file.");
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_BLOCK_IPC_EVENTS, NULL, NULL);
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_ipc_cmd(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
bool enabled;
|
||||
if (strcmp(argv[0], "enabled") == 0) {
|
||||
enabled = true;
|
||||
} else if (strcmp(argv[0], "disabled") == 0) {
|
||||
enabled = false;
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID, argv[-1],
|
||||
"Argument must be one of 'enabled' or 'disabled'");
|
||||
}
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
enum ipc_feature type;
|
||||
} types[] = {
|
||||
{ "command", IPC_FEATURE_COMMAND },
|
||||
{ "workspaces", IPC_FEATURE_GET_WORKSPACES },
|
||||
{ "outputs", IPC_FEATURE_GET_OUTPUTS },
|
||||
{ "tree", IPC_FEATURE_GET_TREE },
|
||||
{ "marks", IPC_FEATURE_GET_MARKS },
|
||||
{ "bar-config", IPC_FEATURE_GET_BAR_CONFIG },
|
||||
{ "inputs", IPC_FEATURE_GET_INPUTS },
|
||||
};
|
||||
|
||||
uint32_t type = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); ++i) {
|
||||
if (strcmp(types[i].name, argv[-1]) == 0) {
|
||||
type = types[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
config->ipc_policy |= type;
|
||||
sway_log(L_DEBUG, "Enabled IPC %s feature", argv[-1]);
|
||||
} else {
|
||||
config->ipc_policy &= ~type;
|
||||
sway_log(L_DEBUG, "Disabled IPC %s feature", argv[-1]);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_ipc_event_cmd(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
bool enabled;
|
||||
if (strcmp(argv[0], "enabled") == 0) {
|
||||
enabled = true;
|
||||
} else if (strcmp(argv[0], "disabled") == 0) {
|
||||
enabled = false;
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID, argv[-1],
|
||||
"Argument must be one of 'enabled' or 'disabled'");
|
||||
}
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
enum ipc_feature type;
|
||||
} types[] = {
|
||||
{ "workspace", IPC_FEATURE_EVENT_WORKSPACE },
|
||||
{ "output", IPC_FEATURE_EVENT_OUTPUT },
|
||||
{ "mode", IPC_FEATURE_EVENT_MODE },
|
||||
{ "window", IPC_FEATURE_EVENT_WINDOW },
|
||||
{ "binding", IPC_FEATURE_EVENT_BINDING },
|
||||
{ "input", IPC_FEATURE_EVENT_INPUT },
|
||||
};
|
||||
|
||||
uint32_t type = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); ++i) {
|
||||
if (strcmp(types[i].name, argv[-1]) == 0) {
|
||||
type = types[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
config->ipc_policy |= type;
|
||||
sway_log(L_DEBUG, "Enabled IPC %s event", argv[-1]);
|
||||
} else {
|
||||
config->ipc_policy &= ~type;
|
||||
sway_log(L_DEBUG, "Disabled IPC %s event", argv[-1]);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
#include <string.h>
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/security.h"
|
||||
#include "log.h"
|
||||
|
||||
static enum secure_feature get_features(int argc, char **argv,
|
||||
struct cmd_results **error) {
|
||||
enum secure_feature features = 0;
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
enum secure_feature feature;
|
||||
} feature_names[] = {
|
||||
{ "lock", FEATURE_LOCK },
|
||||
{ "panel", FEATURE_PANEL },
|
||||
{ "background", FEATURE_BACKGROUND },
|
||||
{ "screenshot", FEATURE_SCREENSHOT },
|
||||
{ "fullscreen", FEATURE_FULLSCREEN },
|
||||
{ "keyboard", FEATURE_KEYBOARD },
|
||||
{ "mouse", FEATURE_MOUSE },
|
||||
{ "ipc", FEATURE_IPC },
|
||||
};
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
size_t j;
|
||||
for (j = 0; j < sizeof(feature_names) / sizeof(feature_names[0]); ++j) {
|
||||
if (strcmp(feature_names[j].name, argv[i]) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == sizeof(feature_names) / sizeof(feature_names[0])) {
|
||||
*error = cmd_results_new(CMD_INVALID,
|
||||
"permit", "Invalid feature grant %s", argv[i]);
|
||||
return 0;
|
||||
}
|
||||
features |= feature_names[j].feature;
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
static struct feature_policy *get_policy(const char *name) {
|
||||
struct feature_policy *policy = NULL;
|
||||
for (int i = 0; i < config->feature_policies->length; ++i) {
|
||||
struct feature_policy *p = config->feature_policies->items[i];
|
||||
if (strcmp(p->program, name) == 0) {
|
||||
policy = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!policy) {
|
||||
policy = alloc_feature_policy(name);
|
||||
list_add(config->feature_policies, policy);
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_permit(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "permit", EXPECTED_MORE_THAN, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
struct feature_policy *policy = get_policy(argv[0]);
|
||||
policy->features |= get_features(argc, argv, &error);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sway_log(L_DEBUG, "Permissions granted to %s for features %d",
|
||||
policy->program, policy->features);
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_reject(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "reject", EXPECTED_MORE_THAN, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
struct feature_policy *policy = get_policy(argv[0]);
|
||||
policy->features &= ~get_features(argc, argv, &error);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
sway_log(L_DEBUG, "Permissions granted to %s for features %d",
|
||||
policy->program, policy->features);
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/security.h"
|
||||
#include "log.h"
|
||||
|
||||
struct feature_policy *alloc_feature_policy(const char *program) {
|
||||
uint32_t default_policy = 0;
|
||||
for (int i = 0; i < config->feature_policies->length; ++i) {
|
||||
struct feature_policy *policy = config->feature_policies->items[i];
|
||||
if (strcmp(policy->program, "*") == 0) {
|
||||
default_policy = policy->features;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct feature_policy *policy = malloc(sizeof(struct feature_policy));
|
||||
policy->program = strdup(program);
|
||||
policy->features = default_policy;
|
||||
return policy;
|
||||
}
|
||||
|
||||
struct command_policy *alloc_command_policy(const char *command) {
|
||||
struct command_policy *policy = malloc(sizeof(struct command_policy));
|
||||
policy->command = strdup(command);
|
||||
policy->context = 0;
|
||||
return policy;
|
||||
}
|
||||
|
||||
enum secure_feature get_feature_policy(pid_t pid) {
|
||||
const char *fmt = "/proc/%d/exe";
|
||||
int pathlen = snprintf(NULL, 0, fmt, pid);
|
||||
char *path = malloc(pathlen + 1);
|
||||
snprintf(path, pathlen + 1, fmt, pid);
|
||||
static char link[2048];
|
||||
|
||||
uint32_t default_policy = 0;
|
||||
|
||||
ssize_t len = readlink(path, link, sizeof(link));
|
||||
if (len < 0) {
|
||||
sway_log(L_INFO,
|
||||
"WARNING: unable to read %s for security check. Using default policy.",
|
||||
path);
|
||||
strcpy(link, "*");
|
||||
} else {
|
||||
link[len] = '\0';
|
||||
}
|
||||
free(path);
|
||||
|
||||
for (int i = 0; i < config->feature_policies->length; ++i) {
|
||||
struct feature_policy *policy = config->feature_policies->items[i];
|
||||
if (strcmp(policy->program, "*") == 0) {
|
||||
default_policy = policy->features;
|
||||
}
|
||||
if (strcmp(policy->program, link) == 0) {
|
||||
return policy->features;
|
||||
}
|
||||
}
|
||||
|
||||
return default_policy;
|
||||
}
|
||||
|
||||
enum command_context get_command_policy(const char *cmd) {
|
||||
uint32_t default_policy = 0;
|
||||
|
||||
for (int i = 0; i < config->command_policies->length; ++i) {
|
||||
struct command_policy *policy = config->command_policies->items[i];
|
||||
if (strcmp(policy->command, "*") == 0) {
|
||||
default_policy = policy->context;
|
||||
}
|
||||
if (strcmp(policy->command, cmd) == 0) {
|
||||
return policy->context;
|
||||
}
|
||||
}
|
||||
|
||||
return default_policy;
|
||||
}
|
||||
|
||||
const char *command_policy_str(enum command_context context) {
|
||||
switch (context) {
|
||||
case CONTEXT_ALL:
|
||||
return "all";
|
||||
case CONTEXT_CONFIG:
|
||||
return "config";
|
||||
case CONTEXT_BINDING:
|
||||
return "binding";
|
||||
case CONTEXT_IPC:
|
||||
return "IPC";
|
||||
case CONTEXT_CRITERIA:
|
||||
return "criteria";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
@ -0,0 +1,250 @@
|
||||
/////
|
||||
vim:set ts=4 sw=4 tw=82 noet:
|
||||
/////
|
||||
sway-security (7)
|
||||
=================
|
||||
|
||||
Name
|
||||
----
|
||||
sway-security - Guidelines for securing your sway install
|
||||
|
||||
Security Overview
|
||||
-----------------
|
||||
|
||||
**Sway is NOT secure**. We are working on it but do not trust that we have it all
|
||||
figured out yet. The following man page is provisional.
|
||||
|
||||
Securing sway requires careful configuration of your environment, the sort that's
|
||||
usually best suited to a distro maintainer who wants to ship a secure sway
|
||||
environment in their distro. Sway provides a number of means of securing it but
|
||||
you must make a few changes external to sway first.
|
||||
|
||||
Configuration security
|
||||
----------------------
|
||||
|
||||
Many of Sway's security features are configurable. It's important that a possibly
|
||||
untrusted program is not able to edit this. Security rules are kept in
|
||||
_/etc/sway/config.d/security_ (usually), which should only be writable by root.
|
||||
However, configuration of security rules is not limited to this file - any config
|
||||
file that sway loads (including i.e. _~/.config/sway/config_) should not be editable
|
||||
by the user you intend to run programs as. One simple strategy is to use
|
||||
/etc/sway/config instead of a config file in your home directory, but that doesn't
|
||||
work well for multi-user systems. A more robust strategy is to run untrusted
|
||||
programs as another user, or in a sandbox. Configuring this is up to you.
|
||||
|
||||
Note that _/etc/sway/config.d/*_ must be included explicitly from your config file.
|
||||
This is done by default in /etc/sway/config but you must check your own config if
|
||||
you choose to place it in other locations.
|
||||
|
||||
Environment security
|
||||
--------------------
|
||||
|
||||
LD_PRELOAD is a mechanism designed to ruin the security of your system. There are
|
||||
a number of strategies for dealing with this but they all suck a little. In order
|
||||
of most practical to least practical:
|
||||
|
||||
1. Only run important programs via exec. Sway's exec command will ensure that
|
||||
LD_PRELOAD is unset when running programs.
|
||||
|
||||
2. Remove LD_PRELOAD support from your dynamic loader (requires patching libc).
|
||||
This may break programs that rely on LD_PRELOAD for legitimate functionality,
|
||||
but this is the most effective solution.
|
||||
|
||||
3. Use static linking for important programs. Of course statically linked programs
|
||||
are unaffected by the dynamic linking security dumpster fire.
|
||||
|
||||
Note that should you choose method 1, you MUST ensure that sway itself isn't
|
||||
compromised by LD_PRELOAD. It probably isn't, but you can be sure by setting
|
||||
/usr/bin/sway to a+s (setuid), which will instruct the dynamic linker not to
|
||||
permit LD_PRELOAD for it (and will also run it as root, which sway will shortly
|
||||
drop). You could also statically link sway itself.
|
||||
|
||||
Note that LD_LIBRARY_PATH has all of the same problems, and all of the same
|
||||
solutions.
|
||||
|
||||
Read your log
|
||||
-------------
|
||||
|
||||
Sway does sanity checks and prints big red warnings to stderr if they fail. Read
|
||||
them.
|
||||
|
||||
Feature policies
|
||||
----------------
|
||||
|
||||
Certain sway features are security sensitive and may be configured with security
|
||||
policies. These features are:
|
||||
|
||||
**background**::
|
||||
Permission for a program to become the background.
|
||||
|
||||
**fullscreen**::
|
||||
Permission to become fullscreen. Note that users can always make a window
|
||||
fullscreen themselves with the fullscreen command.
|
||||
|
||||
**ipc**::
|
||||
Permission to connect to sway's IPC socket.
|
||||
|
||||
**keyboard**::
|
||||
Permission to receive keyboard events (only while they are focused).
|
||||
|
||||
**lock**::
|
||||
Permission for a program to act as a screen locker. This involves becoming
|
||||
fullscreen (on all outputs) and receiving _all_ keyboard and mouse input for
|
||||
the duration of the process.
|
||||
|
||||
**mouse**::
|
||||
Permission to receive mouse events (only while the mouse is over them).
|
||||
|
||||
**panel**::
|
||||
Permission for a program to stick its windows to the sides of the screen.
|
||||
|
||||
**screenshot**::
|
||||
Permission to take screenshots or record the screen.
|
||||
|
||||
By default, all programs are granted **fullscreen**, **keyboard**, **mouse**, and
|
||||
**ipc** permissions. You can use the following config commands to control a
|
||||
program's access:
|
||||
|
||||
**permit** <executable> <features...>::
|
||||
Permits <executable> to use <features> (each feature seperated by a space).
|
||||
<executable> may be * to affect the default policy, or the full path to the
|
||||
executable file.
|
||||
|
||||
**reject** <executable> <features...>::
|
||||
Disallows <executable> from using <features> (each feature seperated by a space).
|
||||
<executable> may be * to affect the default policy, or the full path to the
|
||||
executable file.
|
||||
|
||||
Note that policy enforcement requires procfs to be mounted at /proc and the sway
|
||||
process to be able to access _/proc/[pid]/exe_ (see **procfs(5)** for details on
|
||||
this access - setcap cap_sys_ptrace=eip /usr/bin/sway should do the trick). If
|
||||
sway is unable to read _/proc/[pid]/exe_, it will apply the default policy.
|
||||
|
||||
To work correctly, sway's own programs require the following permissions:
|
||||
|
||||
- swaybg: background
|
||||
- swaylock: lock, keyboard
|
||||
- swaybar: panel, mouse, ipc
|
||||
- swaygrab: screenshot, ipc
|
||||
|
||||
When you first declare a policy for an executable, it will inherit the default
|
||||
policy. Further changes to the default policy will not retroactively affect which
|
||||
permissions an earlier policy inherits. You must explicitly reject any features
|
||||
from the default policy that you do not want an executable to receive permission
|
||||
for.
|
||||
|
||||
Command policies
|
||||
----------------
|
||||
|
||||
You can also control the context from which a command may execute. The different
|
||||
contexts you can control are:
|
||||
|
||||
**config**::
|
||||
Can be run from your config file.
|
||||
|
||||
**binding**::
|
||||
Can be run from bindsym or bindcode commands.
|
||||
|
||||
**ipc**::
|
||||
Can be run by IPC clients.
|
||||
|
||||
**criteria**::
|
||||
Can be run when evaluating window criteria.
|
||||
|
||||
**all**::
|
||||
Shorthand for granting permission in all contexts.
|
||||
|
||||
By default a command is allowed to execute in any context. To configure this, open
|
||||
a commands block and fill it with policies:
|
||||
|
||||
commands {
|
||||
<name> <contexts...>
|
||||
...
|
||||
}
|
||||
|
||||
For example, you could do this to limit the use of the focus command to just
|
||||
binding and critiera:
|
||||
|
||||
commands {
|
||||
focus binding criteria
|
||||
}
|
||||
|
||||
Setting a command policy overwrites any previous policy that was in place.
|
||||
|
||||
IPC policies
|
||||
------------
|
||||
|
||||
You may whitelist IPC access like so:
|
||||
|
||||
permit /usr/bin/swaybar ipc
|
||||
permit /usr/bin/swaygrab ipc
|
||||
# etc
|
||||
|
||||
Note that it's suggested you do not enable swaymsg to access IPC if you intend to
|
||||
secure your IPC socket, because any program could just run swaymsg itself instead
|
||||
of connecting to IPC directly.
|
||||
|
||||
You can also configure which features of IPC are available with an IPC block:
|
||||
|
||||
ipc {
|
||||
...
|
||||
}
|
||||
|
||||
The following commands are available within this block:
|
||||
|
||||
**bar-config** <enabled|disabled>::
|
||||
Controls GET_BAR_CONFIG (required for swaybar to work at all).
|
||||
|
||||
**command** <enabled|disabled>::
|
||||
Controls executing sway commands via IPC.
|
||||
|
||||
**inputs** <enabled|disabled>::
|
||||
Controls GET_INPUTS (input device information).
|
||||
|
||||
**marks** <enabled|disabled>::
|
||||
Controls GET_MARKS.
|
||||
|
||||
**outputs** <enabled|disabled>::
|
||||
Controls GET_OUTPUTS.
|
||||
|
||||
**tree** <enabled|disabled>::
|
||||
Controls GET_TREE.
|
||||
|
||||
**workspaces** <enabled|disabled>::
|
||||
Controls GET_WORKSPACES.
|
||||
|
||||
You can also control which IPC events can be raised with an events block:
|
||||
|
||||
ipc {
|
||||
events {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
The following commands are vaild within an ipc events block:
|
||||
|
||||
**binding** <enabled|disabled>::
|
||||
Controls keybinding notifications (disabled by default).
|
||||
|
||||
**input** <enabled|disabled>::
|
||||
Controls input device hotplugging notifications.
|
||||
|
||||
**mode** <enabled|disabled>::
|
||||
Controls output hotplugging notifications.
|
||||
|
||||
**output** <enabled|disabled>::
|
||||
Controls output hotplugging notifications.
|
||||
|
||||
**window** <enabled|disabled>::
|
||||
Controls window event notifications.
|
||||
|
||||
**workspace** <enabled|disabled>::
|
||||
Controls workspace notifications.
|
||||
|
||||
Disabling some of these may cause swaybar to behave incorrectly.
|
||||
|
||||
Authors
|
||||
-------
|
||||
Maintained by Drew DeVault <sir@cmpwn.com>, who is assisted by other open
|
||||
source contributors. For more information about sway development, see
|
||||
<https://github.com/SirCmpwn/sway>.
|
Loading…
Reference in new issue