Compare commits

...

52 commits

Author SHA1 Message Date
Brian Ashworth
a1b9aa11d1 Use container under cursor for mouse bindings
This matches i3's behavior of executing mouse bindings in regards to the
container under the cursor instead of what is focused.
2019-02-18 15:11:48 -05:00
Brian Ashworth
0940a46c11 seat_cmd_cursor: fix typo in expected syntax
This just fixes a typo in the expected syntax for seat_cmd_cursor
2019-02-18 15:11:48 -05:00
Brian Ashworth
34f5c1e7c4 workspace_next_name: fallback to next available number
This changes `workspace_next_name` to use the next available number as
the workspace name instead of the number of outputs. This fixes the case
where a number that is already in use could be returned. The workspace
numbers in use have no relation to the number of outputs so it makes
more sense to use the lowest available number
2019-02-18 15:11:48 -05:00
Drew DeVault
f22aef018b Remove refs to unimplemented debuglog command
Closes #3695
2019-02-18 15:11:48 -05:00
emersion
eaec82abd2 Disconnect swaybg instead of killing it
This is much more reliable. This also fixes race conditions when killing swaybg
while it's doing a wl_display_roundtrip.
2019-02-18 15:11:48 -05:00
emersion
c6b43359e7 Fix Meson subproject boolean default options 2019-02-18 15:11:48 -05:00
Brian Ashworth
f120f70f5a sway-input.5: document wildcard and identifier troubleshooting
This documents the wildcard character for both inputs and seats. There
is also a tip added on trying the wildcard to verify a setting if the
identifier does not appear to be working.
2019-02-18 15:11:48 -05:00
emersion
d2456c3b37 Remove unused header include/sway/tree/output.h 2019-02-18 15:11:48 -05:00
Brian Ashworth
19586ab768 Fix reload freeze when not modsetting current mode
This fixes the issue of the display freezing on reload with
wlroots#1545.

On master, all output configs are applied on reload. This may cause an
output to have its config applied up to three times, instead of just
once. The three cases are: output name, output identifier, and wildcard.
Not only is this inefficient, but it can cause swaybg to be spawned and
immediately killed.

However, swaybg requires two roundtrips of wl_display (to obtain needed
globals) before it enters its normal event loop. Modesetting will
roundtrip the wl_display. Without modesetting, waitpid for killing
swaybg could block infinitely due to swaybg being blocked by
wl_display_roundtrip.

This only configured an output once. It either uses the wildcard config
or creates an empty wildcard config and applies that. This also fixes a
bug where an output would not be reset when there is no output config to
apply to it.
2019-02-18 15:11:48 -05:00
Ian Fan
9ff59b7c6b tray: fix memory leaks 2019-02-18 15:11:48 -05:00
Ian Fan
8dbd4b98f7 tray: when a service is lost, remove all matching items
Before, only the first matching item would be removed, which could leave
stale items.
2019-02-18 15:11:48 -05:00
Vincent Vanlaer
c07d91ca96 Check layout before getting pointer surface coords
This fixes issues of clients at the edge of the screen, like swaybar,
ignoring buttons.
2019-02-18 15:11:48 -05:00
emersion
b02198a0d1 Disable unneeded wlroots subproject features 2019-02-18 15:11:48 -05:00
Ian Fan
1a46da7fcf tray: use correct parameter to set bus slot to floating
Counter-intuitively, `sd_bus_slot_set_floating` expects 0 to set it to
floating.
2019-02-18 15:11:48 -05:00
Ian Fan
47abc45e86 swaybar: prevent signal handler from firing during termination
This prevents a heap-use-after-free crash when sway terminates.
2019-02-18 15:11:48 -05:00
Brian Ashworth
8d708b8e1d apply_output_config: dpms on before modeset
On the DRM backend, if an output is dpms'd off and a different output is
hotplugged, the CRTC for the output is reclaimed. When modesetting an
output without a CRTC, a CRTC will not be given to an output that is not
desired to be enabled. This splits setting the dpms state in
apply_output_config. If the output should be dpms on, the it is enabled
before attempting to modeset. Otherwise, it is dpms'd off after setting
everything else.

This also adds DPMS_ON to the default output configs.
2019-02-18 15:11:48 -05:00
Brian Ashworth
f0e8c68ca7 seatop_move_tiling: do not move to descendant
In seatop_move_tiling, it is possible to cause a stack overflow by
dragging a container into one of its descendants. This disables the
ability to move into a descendant.
2019-02-18 15:11:48 -05:00
Brian Ashworth
ee236afb43 seat: allow tree focus changes while layer focused
This allows the focused inactive tree node and visible workspaces to be
changed while a surface layer has focus. The layer temporarily loses
focus, the tree focus changes, and the layer gets refocused.
2019-02-18 15:11:48 -05:00
Brian Ashworth
1d4b995c0f seatop_move_tiling: use tab/stack parent not self
When moving a descendant of a tabbed or stacked container, it is possible
for the target node to be the node being moved. This causes a segfault in
`handle_finish` since the node will be detached and then attempted to be
attached to it own parent, which is NULL due to the detach. In this
case, the target node should not be set to the node being moved, but the
parent of the node. This also allows for a descendant of a tabbed or
stacked container to be dragged out of the tabs/stacks and to be a
sibling of the tabbbed/stacked container, which was not previously
possible.
2019-02-18 15:11:48 -05:00
Brian Ashworth
ad34837dda subsurface_get_root_coords: break on NULL
It is possible for `wlr_surface_is_subsurface` to return true, but
`wlr_surface_from_wlr_surface` to be NULL. This adds a NULL check to the
value returned by `wlr_surface_from_wlr_surface` and breaks out of the
while loop in `subsurface_get_root_coords`.
2019-02-18 15:11:48 -05:00
Brian Ashworth
d126410de1 cursor: relative-pointer-v1 time is usec
In handle_cursor_motion, the timestamp passed to
`wlr_relative_pointer_manager_v1_send_relative_motion` should be
microseconds (not milliseconds) according to relative-pointer-v1 spec.
2019-02-18 15:11:48 -05:00
athrungithub
59b3c4d06e Don't remove from scratchpad on move to workspace
on move container window to another workspace,
not remove from scratchpad.
2019-02-18 15:11:48 -05:00
emersion
e50e1fe058 Fix --version when building from tarball 2019-02-18 15:11:48 -05:00
emersion
06e03ed878 Rebase cursor when a layer surface maps
Also removes an extraneous arrange_outputs call, it's already called if
necessary in arrange_layers.

Updates https://github.com/swaywm/sway/issues/3080
2019-02-18 15:11:48 -05:00
Brian Ashworth
e4e579ea36 workspace_get_initial_output: handle focused layer
When a layer surface is focused, `seat_get_focused_workspace` will be
NULL. This changes `workspace_get_initial_output` to use output of the
focus inactive. If the focus inactive is also NULL, then either the
first output or the noop output will be used as fallbacks.
2019-02-11 10:22:53 -05:00
Brian Ashworth
40023d45a1 Abort early when XDG_RUNTIME_DIR is not set
This aborts sway and displays an error message about XDG_RUNTIME_DIR
not being set without initializing the wl_display or logging any other
information.
2019-02-11 10:22:53 -05:00
Brian Ashworth
a5a189cc73 fix misc memory leaks
This fixes a few misc memory leaks reported by asan:
- Items of `config->config_chain` are now freed instead of just the list
itself
- `bar->swaybar_command` is now freed
- The result returned by a seat subcommand is now returned instead of
leaked
2019-02-11 10:22:53 -05:00
Brian Ashworth
a4d7ee1923 ipc: handle unnamed xkb_active_layout_name
If the active xkb_layout does not have a name, use `NULL` instead of
`json_object_new_string(NULL)`. This also makes it so swaymsg will pretty
print this as `(unnamed)`.
2019-02-11 10:22:53 -05:00
Brian Ashworth
4e27785980 view: remove pointer constraints on unmap
If the view has any pointer constraints, ensure they are removed
before the view is unmapped and the surface is no longer tied to the
view.
2019-02-11 10:22:53 -05:00
Brian Ashworth
062da8eae7 input/keyboard: respect solo repeat_{rate,delay}
If `repeat_rate` or `repeat_delay` is set without the other being set,
the default was being used for both. This changes the logic to respect
the value given and use the default for the other when only one is set.
2019-02-11 10:22:53 -05:00
Rouven Czerwinski
95e16bb744 fix double free for mode toggle if bar was invisible
If the bar was set to "invisible" and subsequently "toggle" was send twice, the
new mode was never set and the bar->mode was double freed.
Fix this by not requiring the bar->mode to be "hide" and instead show it
unconditionally, because it was either hidden or invisible.

Fixes #3637
2019-02-11 10:22:53 -05:00
Brian Ashworth
243d5a3a43 container_at_stacked: skip titles when zero pixels
It is possible to make the title bars have a zero pixel height while
stacked, by using a blank font and no padding. This causes a division by
zero when attempting to calculate the child index in
container_at_stacked, which then results in a segfault when attempting
to access the child at that bad index (INT_MIN). This just skips the
check to see if the cursor is over a title bar of a child of a stacked
container when the title bar height is zero since there will be no title
bars.
2019-02-11 10:22:53 -05:00
Brian Ashworth
4339ba6424 bar_cmd_modifier: add support for none
sway-bar(5) documents `modifier none`, which comes from i3. This
implements the functionality for `modifier none` since it was not
previously implemented. The bar modifier toggles visibility of the bar
when the bar mode is set to hide. When the bar modifier is set to
`none`, the ability to toggle visibility of the bar will be disabled.
2019-02-11 10:22:53 -05:00
Brian Ashworth
32f790bd15 seat_configure_tablet_tool: configure xcursor
Since a tablet tool provides the WL_SEAT_CAPABILITY_POINTER capability,
sway will attempt to use the xcursor manager to set a cursor image. If
the tablet tool was the first (and possibly only) device to provide the
capability for the seat, the xcursor manager was not being configured
before attempting to set a cursor image. This was due to
`seat_configure_xcursor` only being called in `seat_configure_pointer`.
Since the xcursor manager was NULL in this case, it would cause a
segfault when attempting to set a cursor image. This adds a call to
`seat_configure_xcursor` in `seat_configure_tablet_tool` to ensure that
the seat has a xcursor manager.
2019-02-11 10:22:53 -05:00
Brian Ashworth
8229814e7a load_main_config: use given path, store realpath
Since `load_include_config` compares against the realpath of a config
file when checking if a config has already been added, the main config's
realpath has to be added to the config_chain.

However, includes from the main config should be processed relative to
the path given to allow for symbolic links. This stores the realpath in
`config->config_chain`, but uses the given path for all other
operations.
2019-02-11 10:22:53 -05:00
Brian Ashworth
a2f661dceb Clarify error for options and positional args
When both options and positional arguments are given, sway would print
the error `Don't use options with the IPC client`. Over the past
several months, it seems like users are including this error message in
issues instead of a debug log due to not understanding that the error
message means there is an issue with their command.

This makes the error message more verbose and will hopefully make it so
more users understand that the message is not a bug in sway, but with
the command used.
2019-02-11 10:22:53 -05:00
Daniel Eklöf
6ade4bd7dd ipc_has_event_listeners: fix inverted check of subscribed_events
subscribed_events is a bit mask, with each *set* bit representing an
event the client has subscribed to.
2019-02-11 10:22:53 -05:00
Brian Ashworth
d2d2fc545a load_main_config: add realpath to config_chain
Since `load_include_config` compares against the realpath of a config
file when checking if a config has already been added, the main config's
realpath has to be added to the config_chain.
2019-02-11 10:22:53 -05:00
emersion
48511c3b35 Fix close_popups for xdg-shell
wlr_xdg_popup_destroy will destroy popups, so we need to walk the tree
carefully. It's enough to just destroy all direct children, since destroying
the parent will also destroy all children.
2019-02-11 10:22:53 -05:00
Brian Ashworth
d4e49a49eb output_cmd_background: fix no file + valid mode
If output_cmd_background is given a valid mode as the first argument,
then there is no file given and an error should be returned.

join_args should not be called with an argc of zero since it sets the
last character to the null terminator. With an argc of zero, the length
is zero causing a heap buffer overflow when setting the byte before the
start of argv to '\0'. This probably will not ever generate a segfault,
but may cause data corruption to whatever is directly before it in
memory. To make other such cases easier to detect, this also adds a
sway_assert in join_args when argc is zero.
2019-02-11 10:22:53 -05:00
Connor E
cc5139d52a Initialize server so input manager is available. 2019-02-11 10:22:53 -05:00
Connor E
2112f0aa2f If validating the config, do it as early as possible. 2019-02-11 10:22:53 -05:00
Brian Ashworth
0c091bed76 cmd_workspace_gaps: fix double free on bad amount
This fixes a double free in cmd_workspace_gaps when the amount given is
invalid. The end pointer from strtol is part of the argument and should
not be freed. Freeing the end pointer could result in a double free or
bad free depending on whether or not the end pointer was at the start of
the argument
2019-02-11 10:15:00 -05:00
Michael Vetter
9346ed1805 Set version in project file
Let's set the version in the meson file instead of declaring it outside.

In case git is installed we use the git hash as version. Instead it
isn't (like on a clean build system), let's use the version defined in
the project.
2019-02-11 10:15:00 -05:00
Brian Ashworth
41e10db0de IPC_COMMAND: split on newline
This splits commands given in IPC_COMMAND on newline to match i3's
behavior.
2019-02-11 10:15:00 -05:00
emersion
610794d4e3 Fix quote stripping
Let's not use !strcmp(…) anymore.
2019-02-11 10:15:00 -05:00
Brian Ashworth
5d770d028a execute_command: dont strip quotes for exec_always
This removes quote stripping for `exec_always` in `execute_command`.
Since `exec_always` commands will be deferred in the config and
processed by `execute_command`, the quotes need to be left intact
like they are for `exec`.
2019-02-11 10:15:00 -05:00
Brian Ashworth
66062f53de swaynag: remove trailing newlines in config
Now that swaynag uses getline (instead of the old readline), the
trailing newline characters have to be removed when reading the config
2019-02-11 10:15:00 -05:00
Brian Ashworth
df3ea6a55f load_include_configs: fix wordexp fail condition
This fixes the failure condition for the wordexp call in
load_include_configs. The only success value is zero. Since the error
codes are positive, having the check be less than zero was causing
segfaults on failure when accessing the words.
2019-02-11 10:15:00 -05:00
Brian Ashworth
4272bf1274 seat_cmd_cursor: do not create non-existing seat
If a seat does not exist in seat_cmd_cursor, do not create it. A seat
without any attachments is useless since it will have no capabilities.

This changes `input_manager_get_seat` to have an additional argument
that dictates whether or not to create the seat if it does not exist.
2019-02-11 10:15:00 -05:00
vilhalmer
130626a5db Focus ws inactive node with focus_follows_mouse 2019-02-11 10:13:21 -05:00
Brian Ashworth
743d345383 Merge pull request #3563 from vilhalmer/fix-wildcard-seat-constrain-crashes-during-reconfig
Fix wildcard seat constrain crashes during reconfig
2019-02-11 10:12:43 -05:00
47 changed files with 394 additions and 202 deletions

View file

@ -258,6 +258,9 @@ int unescape_string(char *string) {
}
char *join_args(char **argv, int argc) {
if (!sway_assert(argc > 0, "argc should be positive")) {
return NULL;
}
int len = 0, i;
for (i = 0; i < argc; ++i) {
len += strlen(argv[i]) + 1;

View file

@ -112,7 +112,6 @@ sway_cmd cmd_client_placeholder;
sway_cmd cmd_client_background;
sway_cmd cmd_commands;
sway_cmd cmd_create_output;
sway_cmd cmd_debuglog;
sway_cmd cmd_default_border;
sway_cmd cmd_default_floating_border;
sway_cmd cmd_default_orientation;

View file

@ -586,6 +586,8 @@ struct output_config *store_output_config(struct output_config *oc);
void apply_output_config_to_outputs(struct output_config *oc);
void reset_outputs(void);
void free_output_config(struct output_config *oc);
int workspace_output_cmp_workspace(const void *a, const void *b);

View file

@ -72,6 +72,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat);
* This chooses a cursor icon and sends a motion event to the surface.
*/
void cursor_rebase(struct sway_cursor *cursor);
void cursor_rebase_all(void);
void cursor_handle_activity(struct sway_cursor *cursor);
void cursor_unhide(struct sway_cursor *cursor);

View file

@ -45,7 +45,7 @@ void input_manager_apply_seat_config(struct seat_config *seat_config);
struct sway_seat *input_manager_get_default_seat(void);
struct sway_seat *input_manager_get_seat(const char *seat_name);
struct sway_seat *input_manager_get_seat(const char *seat_name, bool create);
/**
* If none of the seat configs have a fallback setting (either true or false),

View file

@ -21,6 +21,7 @@ struct sway_output {
struct sway_node node;
struct wlr_output *wlr_output;
struct sway_server *server;
struct wl_list link;
struct wl_list layers[4]; // sway_layer_surface::link
struct wlr_box usable_area;
@ -36,6 +37,8 @@ struct sway_output {
struct sway_output_state current;
struct wl_client *swaybg_client;
struct wl_listener destroy;
struct wl_listener mode;
struct wl_listener transform;
@ -43,10 +46,7 @@ struct sway_output {
struct wl_listener present;
struct wl_listener damage_destroy;
struct wl_listener damage_frame;
struct wl_list link;
pid_t bg_pid;
struct wl_listener swaybg_client_destroy;
struct {
struct wl_signal destroy;

View file

@ -46,6 +46,8 @@ struct swaybar {
#if HAVE_TRAY
struct swaybar_tray *tray;
#endif
bool running;
};
struct swaybar_output {

View file

@ -1,6 +1,7 @@
project(
'sway',
'c',
version: '1.0',
license: 'MIT',
meson_version: '>=0.48.0',
default_options: [
@ -59,7 +60,11 @@ rt = cc.find_library('rt')
git = find_program('git', required: false)
# Try first to find wlroots as a subproject, then as a system dependency
wlroots_proj = subproject('wlroots', required: false)
wlroots_proj = subproject(
'wlroots',
default_options: ['rootston=false', 'examples=false'],
required: false,
)
if wlroots_proj.found()
wlroots = wlroots_proj.get_variable('wlroots')
wlroots_conf = wlroots_proj.get_variable('conf_data')
@ -127,17 +132,13 @@ endif
add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir)), language : 'c')
version = get_option('sway-version')
if version != ''
version = '"@0@"'.format(version)
else
if not git.found()
error('git is required to make the version string')
version = '"@0@"'.format(meson.project_version())
if git.found()
git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags'])
git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD'])
if git_commit_hash.returncode() == 0 and git_branch.returncode() == 0
version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash.stdout().strip(), git_branch.stdout().strip())
endif
git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']).stdout().strip()
git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip()
version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash, git_branch)
endif
add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c')

View file

@ -1,4 +1,3 @@
option('sway-version', type : 'string', description: 'The version string reported in `sway --version`.')
option('default-wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.')
option('zsh-completions', type: 'boolean', value: true, description: 'Install zsh shell completions.')
option('bash-completions', type: 'boolean', value: true, description: 'Install bash shell completions.')

View file

@ -254,7 +254,8 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
//TODO better handling of argv
int argc;
char **argv = split_args(cmd, &argc);
if (strcmp(argv[0], "exec") != 0) {
if (strcmp(argv[0], "exec") != 0 &&
strcmp(argv[0], "exec_always") != 0) {
int i;
for (i = 1; i < argc; ++i) {
if (*argv[i] == '\"' || *argv[i] == '\'') {

View file

@ -11,7 +11,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode
if (strcasecmp("toggle", mode) == 0 && !config->reading) {
if (strcasecmp("dock", bar->mode) == 0) {
bar->mode = strdup("hide");
} else if (strcasecmp("hide", bar->mode) == 0) {
} else{
bar->mode = strdup("dock");
}
} else if (strcasecmp("dock", mode) == 0) {

View file

@ -15,11 +15,17 @@ struct cmd_results *bar_cmd_modifier(int argc, char **argv) {
}
uint32_t mod = 0;
if (strcmp(argv[0], "none") != 0) {
list_t *split = split_string(argv[0], "+");
for (int i = 0; i < split->length; ++i) {
uint32_t tmp_mod;
if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) {
mod |= tmp_mod;
} else if (strcmp(split->items[i], "none") == 0) {
error = cmd_results_new(CMD_INVALID,
"none cannot be used along with other modifiers");
list_free_items_and_destroy(split);
return error;
} else {
error = cmd_results_new(CMD_INVALID,
"Unknown modifier '%s'", (char *)split->items[i]);
@ -28,6 +34,7 @@ struct cmd_results *bar_cmd_modifier(int argc, char **argv) {
}
}
list_free_items_and_destroy(split);
}
config->current_bar->modifier = mod;
sway_log(SWAY_DEBUG,
"Show/Hide the bar when pressing '%s' in hide mode.", argv[0]);

View file

@ -1,10 +1,11 @@
#define _POSIX_C_SOURCE 200809L
#include <libevdev/libevdev.h>
#include <linux/input-event-codes.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-names.h>
#include <string.h>
#include <strings.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-names.h>
#include <wlr/types/wlr_cursor.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/input/cursor.h"
@ -330,7 +331,20 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) {
void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) {
sway_log(SWAY_DEBUG, "running command for binding: %s", binding->command);
list_t *res_list = execute_command(binding->command, seat, NULL);
struct sway_container *con = NULL;
if (binding->type == BINDING_MOUSESYM
|| binding->type == BINDING_MOUSECODE) {
struct wlr_surface *surface = NULL;
double sx, sy;
struct sway_node *node = node_at_coords(seat,
seat->cursor->cursor->x, seat->cursor->cursor->y,
&surface, &sx, &sy);
if (node && node->type == N_CONTAINER) {
con = node->sway_container;
}
}
list_t *res_list = execute_command(binding->command, seat, con);
bool success = true;
for (int i = 0; i < res_list->length; ++i) {
struct cmd_results *results = res_list->items[i];

View file

@ -516,7 +516,6 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) {
// move container
if (container->scratchpad) {
root_scratchpad_remove_container(container);
root_scratchpad_show(container);
}
switch (destination->type) {

View file

@ -61,6 +61,9 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
return cmd_results_new(CMD_INVALID,
"Missing background scaling mode.");
}
if (j == 0) {
return cmd_results_new(CMD_INVALID, "Missing background file");
}
wordexp_t p = {0};
char *src = join_args(argv, j);

View file

@ -50,5 +50,5 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
}
config->handler_context.seat_config = NULL;
return cmd_results_new(CMD_SUCCESS, NULL);
return res ? res : cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -12,7 +12,7 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor,
static const char expected_syntax[] = "Expected 'cursor <move> <x> <y>' or "
"'cursor <set> <x> <y>' or "
"'curor <press|release> <button[1-9]|event-name-or-code>'";
"'cursor <press|release> <button[1-9]|event-name-or-code>'";
static struct cmd_results *handle_command(struct sway_cursor *cursor,
int argc, char **argv) {
@ -61,9 +61,10 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
}
if (strcmp(sc->name, "*") != 0) {
struct sway_seat *seat = input_manager_get_seat(sc->name);
struct sway_seat *seat = input_manager_get_seat(sc->name, false);
if (!seat) {
return cmd_results_new(CMD_FAILURE, "Failed to get seat");
return cmd_results_new(CMD_FAILURE,
"Seat %s does not exist", sc->name);
}
error = handle_command(seat->cursor, argc, argv);
} else {

View file

@ -76,7 +76,6 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
char *end;
int amount = strtol(argv[gaps_location + 2], &end, 10);
if (strlen(end)) {
free(end);
return cmd_results_new(CMD_FAILURE, expected);
}

View file

@ -118,7 +118,7 @@ void free_config(struct sway_config *config) {
}
list_free(config->no_focus);
list_free(config->active_bar_modifiers);
list_free(config->config_chain);
list_free_items_and_destroy(config->config_chain);
list_free(config->command_policies);
list_free(config->feature_policies);
list_free(config->ipc_policies);
@ -141,13 +141,20 @@ static void destroy_removed_seats(struct sway_config *old_config,
int i;
for (i = 0; i < old_config->seat_configs->length; i++) {
seat_config = old_config->seat_configs->items[i];
// Skip the wildcard seat config, it won't have a matching real seat.
if (strcmp(seat_config->name, "*") == 0) {
continue;
}
/* Also destroy seats that aren't present in new config */
if (new_config && list_seq_find(new_config->seat_configs,
seat_name_cmp, seat_config->name) < 0) {
seat = input_manager_get_seat(seat_config->name);
seat = input_manager_get_seat(seat_config->name, false);
if (seat) {
seat_destroy(seat);
}
}
}
}
static void set_color(float dest[static 4], uint32_t color) {
@ -372,6 +379,13 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
path = get_config_path();
}
char *real_path = realpath(path, NULL);
if (real_path == NULL) {
sway_log(SWAY_DEBUG, "%s not found.", path);
free(path);
return false;
}
struct sway_config *old_config = config;
config = calloc(1, sizeof(struct sway_config));
if (!config) {
@ -395,7 +409,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
}
config->current_config_path = path;
list_add(config->config_chain, path);
list_add(config->config_chain, real_path);
config->reading = true;
@ -457,9 +471,8 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
}
if (is_active) {
for (int i = 0; i < config->output_configs->length; i++) {
apply_output_config_to_outputs(config->output_configs->items[i]);
}
reset_outputs();
config->reloading = false;
if (config->swaynag_config_errors.pid > 0) {
swaynag_show(&config->swaynag_config_errors);
@ -550,7 +563,7 @@ bool load_include_configs(const char *path, struct sway_config *config,
wordexp_t p;
if (wordexp(path, &p, 0) < 0) {
if (wordexp(path, &p, 0) != 0) {
free(parent_path);
free(wd);
return false;

View file

@ -46,6 +46,7 @@ void free_bar_config(struct bar_config *bar) {
free(bar->position);
free(bar->hidden_state);
free(bar->status_command);
free(bar->swaybar_command);
free(bar->font);
free(bar->separator_symbol);
for (int i = 0; i < bar->bindings->length; i++) {

View file

@ -1,16 +1,17 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <fcntl.h>
#include <stdbool.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
#include "log.h"
#include "sway/config.h"
#include "sway/output.h"
#include "sway/tree/root.h"
#include "log.h"
int output_name_cmp(const void *item, const void *data) {
const struct output_config *output = item;
@ -165,14 +166,71 @@ static bool set_mode(struct wlr_output *output, int width, int height,
return wlr_output_set_mode(output, best);
}
void terminate_swaybg(pid_t pid) {
int ret = kill(pid, SIGTERM);
if (ret != 0) {
sway_log(SWAY_ERROR, "Unable to terminate swaybg [pid: %d]", pid);
} else {
int status;
waitpid(pid, &status, 0);
static void handle_swaybg_client_destroy(struct wl_listener *listener,
void *data) {
struct sway_output *output =
wl_container_of(listener, output, swaybg_client_destroy);
wl_list_remove(&output->swaybg_client_destroy.link);
wl_list_init(&output->swaybg_client_destroy.link);
output->swaybg_client = NULL;
}
static bool spawn_swaybg(struct sway_output *output, char *const cmd[]) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sockets) != 0) {
sway_log_errno(SWAY_ERROR, "socketpair failed");
return false;
}
output->swaybg_client = wl_client_create(server.wl_display, sockets[0]);
if (output->swaybg_client == NULL) {
sway_log_errno(SWAY_ERROR, "wl_client_create failed");
return false;
}
output->swaybg_client_destroy.notify = handle_swaybg_client_destroy;
wl_client_add_destroy_listener(output->swaybg_client,
&output->swaybg_client_destroy);
pid_t pid = fork();
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
return false;
} else if (pid == 0) {
pid = fork();
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// Remove the CLOEXEC flag
int flags = fcntl(sockets[1], F_GETFD);
if (flags == -1) {
sway_log_errno(SWAY_ERROR, "fcntl() failed");
exit(EXIT_FAILURE);
}
if (fcntl(sockets[1], F_SETFD, flags & ~FD_CLOEXEC) == -1) {
sway_log_errno(SWAY_ERROR, "fcntl() failed");
exit(EXIT_FAILURE);
}
char wayland_socket_str[16];
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
"%d", sockets[1]);
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
execvp(cmd[0], cmd);
sway_log_errno(SWAY_ERROR, "execvp failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
if (waitpid(pid, NULL, 0) < 0) {
sway_log_errno(SWAY_ERROR, "waitpid failed");
return false;
}
return true;
}
bool apply_output_config(struct output_config *oc, struct sway_output *output) {
@ -199,6 +257,11 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
return true;
}
if (oc && oc->dpms_state == DPMS_ON) {
sway_log(SWAY_DEBUG, "Turning on screen");
wlr_output_enable(wlr_output, true);
}
bool modeset_success;
if (oc && oc->width > 0 && oc->height > 0) {
sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width,
@ -238,8 +301,8 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
wlr_output_layout_add_auto(root->output_layout, wlr_output);
}
if (output->bg_pid != 0) {
terminate_swaybg(output->bg_pid);
if (output->swaybg_client != NULL) {
wl_client_destroy(output->swaybg_client);
}
if (oc && oc->background && config->swaybg_command) {
sway_log(SWAY_DEBUG, "Setting background for output %s to %s",
@ -253,29 +316,14 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
oc->background_fallback ? oc->background_fallback : NULL,
NULL,
};
output->bg_pid = fork();
if (output->bg_pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
} else if (output->bg_pid == 0) {
execvp(cmd[0], cmd);
sway_log_errno(SWAY_ERROR, "Failed to execute swaybg");
if (!spawn_swaybg(output, cmd)) {
return false;
}
}
if (oc) {
switch (oc->dpms_state) {
case DPMS_ON:
sway_log(SWAY_DEBUG, "Turning on screen");
wlr_output_enable(wlr_output, true);
break;
case DPMS_OFF:
if (oc && oc->dpms_state == DPMS_OFF) {
sway_log(SWAY_DEBUG, "Turning off screen");
wlr_output_enable(wlr_output, false);
break;
case DPMS_IGNORE:
break;
}
}
return true;
@ -294,6 +342,7 @@ static void default_output_config(struct output_config *oc,
oc->x = oc->y = -1;
oc->scale = 1;
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
oc->dpms_state = DPMS_ON;
}
static struct output_config *get_output_config(char *identifier,
@ -395,6 +444,17 @@ void apply_output_config_to_outputs(struct output_config *oc) {
}
}
void reset_outputs(void) {
struct output_config *oc = NULL;
int i = list_seq_find(config->output_configs, output_name_cmp, "*");
if (i >= 0) {
oc = config->output_configs->items[i];
} else {
oc = store_output_config(new_output_config("*"));
}
apply_output_config_to_outputs(oc);
}
void free_output_config(struct output_config *oc) {
if (!oc) {
return;

View file

@ -6,7 +6,9 @@
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output.h>
#include "log.h"
#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/layers.h"
@ -14,7 +16,6 @@
#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/workspace.h"
#include "log.h"
static void apply_exclusive(struct wlr_box *usable_area,
uint32_t anchor, int32_t exclusive,
@ -302,6 +303,8 @@ static void unmap(struct sway_layer_surface *sway_layer) {
if (seat->focused_layer == sway_layer->layer_surface) {
seat_set_focus_layer(seat, NULL);
}
cursor_rebase_all();
}
static void handle_destroy(struct wl_listener *listener, void *data) {
@ -321,7 +324,6 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output = sway_layer->layer_surface->output->data;
if (output != NULL) {
arrange_layers(output);
arrange_output(output);
transaction_commit_dirty();
}
wl_list_remove(&sway_layer->output_destroy.link);
@ -339,6 +341,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
// TODO: send enter to subsurfaces and popups
wlr_surface_send_enter(sway_layer->layer_surface->surface,
sway_layer->layer_surface->output);
cursor_rebase_all();
}
static void handle_unmap(struct wl_listener *listener, void *data) {

View file

@ -506,6 +506,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&output->present.link);
wl_list_remove(&output->damage_destroy.link);
wl_list_remove(&output->damage_frame.link);
wl_list_remove(&output->swaybg_client_destroy.link);
transaction_commit_dirty();
}
@ -612,6 +613,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
output->damage_frame.notify = damage_handle_frame;
wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
output->damage_destroy.notify = damage_handle_destroy;
wl_list_init(&output->swaybg_client_destroy.link);
struct output_config *oc = output_find_config(output);
if (!oc || oc->enabled) {

View file

@ -314,14 +314,7 @@ static void transaction_apply(struct sway_transaction *transaction) {
node->instruction = NULL;
}
if (root->outputs->length) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
if (!seat_doing_seatop(seat)) {
cursor_rebase(seat->cursor);
}
}
}
cursor_rebase_all();
}
static void transaction_commit(struct sway_transaction *transaction);

View file

@ -236,19 +236,11 @@ static void _close(struct sway_view *view) {
}
}
static void close_popups_iterator(struct wlr_surface *surface,
int sx, int sy, void *data) {
struct wlr_xdg_surface *xdg_surface =
wlr_xdg_surface_from_wlr_surface(surface);
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP
&& xdg_surface->popup) {
wlr_xdg_popup_destroy(xdg_surface);
}
}
static void close_popups(struct sway_view *view) {
wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface,
close_popups_iterator, NULL);
struct wlr_xdg_popup *popup, *tmp;
wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_surface->popups, link) {
wlr_xdg_popup_destroy(popup->base);
}
}
static void destroy(struct sway_view *view) {

View file

@ -283,6 +283,19 @@ void cursor_rebase(struct sway_cursor *cursor) {
cursor_do_rebase(cursor, time_msec, cursor->previous.node, surface, sx, sy);
}
void cursor_rebase_all(void) {
if (!root->outputs->length) {
return;
}
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
if (!seat_doing_seatop(seat)) {
cursor_rebase(seat->cursor);
}
}
}
static int hide_notify(void *data) {
struct sway_cursor *cursor = data;
wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
@ -362,7 +375,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
struct sway_output *focused_output = node_get_output(focus);
struct sway_output *output = node_get_output(node);
if (output != focused_output) {
seat_set_focus(seat, node);
seat_set_focus(seat, seat_get_focus_inactive(seat, node));
}
} else if (node->type == N_CONTAINER && node->sway_container->view) {
// Focus node if the following are true:
@ -408,15 +421,16 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) {
wlr_relative_pointer_manager_v1_send_relative_motion(
server.relative_pointer_manager,
cursor->seat->wlr_seat, event->time_msec, dx, dy,
dx_unaccel, dy_unaccel);
cursor->seat->wlr_seat, (uint64_t)event->time_msec * 1000,
dx, dy, dx_unaccel, dy_unaccel);
struct wlr_surface *surface = NULL;
struct sway_node *node = NULL;
double sx, sy;
struct sway_node *node = node_at_coords(cursor->seat,
if (cursor->active_constraint) {
node = node_at_coords(cursor->seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
if (cursor->active_constraint) {
if (cursor->active_constraint->surface != surface) {
return;
}
@ -432,8 +446,13 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) {
}
wlr_cursor_move(cursor->cursor, event->device, dx, dy);
// Recalculate pointer location after layout checks
node = node_at_coords(cursor->seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
cursor_send_pointer_motion(cursor, event->time_msec, node, surface,
sx + dx, sy + dy);
sx, sy);
transaction_commit_dirty();
}
@ -1459,7 +1478,11 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data) {
void sway_cursor_constrain(struct sway_cursor *cursor,
struct wlr_pointer_constraint_v1 *constraint) {
struct seat_config *config = seat_get_config(cursor->seat);
if (config->allow_constrain == CONSTRAIN_DISABLE) {
if (!config) {
config = seat_get_config_by_name("*");
}
if (!config || config->allow_constrain == CONSTRAIN_DISABLE) {
return;
}

View file

@ -31,10 +31,10 @@ struct sway_seat *input_manager_current_seat(void) {
}
struct sway_seat *input_manager_get_default_seat(void) {
return input_manager_get_seat(DEFAULT_SEAT);
return input_manager_get_seat(DEFAULT_SEAT, true);
}
struct sway_seat *input_manager_get_seat(const char *seat_name) {
struct sway_seat *input_manager_get_seat(const char *seat_name, bool create) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
if (strcmp(seat->wlr_seat->name, seat_name) == 0) {
@ -42,7 +42,7 @@ struct sway_seat *input_manager_get_seat(const char *seat_name) {
}
}
return seat_create(seat_name);
return create ? seat_create(seat_name) : NULL;
}
char *input_device_get_identifier(struct wlr_input_device *device) {
@ -674,7 +674,8 @@ void input_manager_apply_seat_config(struct seat_config *seat_config) {
seat_apply_config(seat, sc);
}
} else {
struct sway_seat *seat = input_manager_get_seat(seat_config->name);
struct sway_seat *seat =
input_manager_get_seat(seat_config->name, true);
if (!seat) {
return;
}

View file

@ -425,7 +425,8 @@ static void determine_bar_visibility(uint32_t modifiers) {
for (int i = 0; i < config->bars->length; ++i) {
struct bar_config *bar = config->bars->items[i];
if (strcmp(bar->mode, bar->hidden_state) == 0) { // both are "hide"
bool should_be_visible = (~modifiers & bar->modifier) == 0;
bool should_be_visible =
bar->modifier != 0 && (~modifiers & bar->modifier) == 0;
if (bar->visible_by_modifier != should_be_visible) {
bar->visible_by_modifier = should_be_visible;
ipc_event_bar_state_update(bar);
@ -548,13 +549,17 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
wlr_keyboard_led_update(wlr_device->keyboard, leds);
}
if (input_config && input_config->repeat_delay != INT_MIN
&& input_config->repeat_rate != INT_MIN) {
wlr_keyboard_set_repeat_info(wlr_device->keyboard,
input_config->repeat_rate, input_config->repeat_delay);
} else {
wlr_keyboard_set_repeat_info(wlr_device->keyboard, 25, 600);
int repeat_rate = 25;
if (input_config && input_config->repeat_rate != INT_MIN) {
repeat_rate = input_config->repeat_rate;
}
int repeat_delay = 600;
if (input_config && input_config->repeat_delay != INT_MIN) {
repeat_delay = input_config->repeat_delay;
}
wlr_keyboard_set_repeat_info(wlr_device->keyboard, repeat_rate,
repeat_delay);
xkb_context_unref(context);
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
wlr_seat_set_keyboard(seat, wlr_device);

View file

@ -525,6 +525,7 @@ static void seat_configure_touch(struct sway_seat *seat,
static void seat_configure_tablet_tool(struct sway_seat *seat,
struct sway_seat_device *sway_device) {
seat_configure_xcursor(seat);
wlr_cursor_attach_input_device(seat->cursor->cursor,
sway_device->input_device->wlr_device);
seat_apply_input_config(seat, sway_device);
@ -724,6 +725,10 @@ void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node) {
void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
if (seat->focused_layer) {
struct wlr_layer_surface_v1 *layer = seat->focused_layer;
seat_set_focus_layer(seat, NULL);
seat_set_focus(seat, node);
seat_set_focus_layer(seat, layer);
return;
}

View file

@ -150,6 +150,9 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
}
if (edge) {
e->target_node = node_get_parent(&con->node);
if (e->target_node == &e->con->node) {
e->target_node = node_get_parent(e->target_node);
}
e->target_edge = edge;
node_get_box(e->target_node, &e->drop_box);
resize_box(&e->drop_box, edge, DROP_LAYOUT_BORDER);
@ -161,7 +164,8 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
// Use the hovered view - but we must be over the actual surface
con = node->sway_container;
if (!con->view->surface || node == &e->con->node) {
if (!con->view->surface || node == &e->con->node
|| node_has_ancestor(node, &e->con->node)) {
e->target_node = NULL;
e->target_edge = WLR_EDGE_NONE;
return;

View file

@ -597,7 +597,7 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
const char *layout =
xkb_keymap_layout_get_name(keymap, layout_idx);
json_object_object_add(object, "xkb_active_layout_name",
json_object_new_string(layout));
layout ? json_object_new_string(layout) : NULL);
break;
}
}

View file

@ -264,7 +264,7 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
static bool ipc_has_event_listeners(enum ipc_command_type event) {
for (int i = 0; i < ipc_client_list->length; i++) {
struct ipc_client *client = ipc_client_list->items[i];
if ((client->subscribed_events & event_mask(event)) == 0) {
if ((client->subscribed_events & event_mask(event)) != 0) {
return true;
}
}
@ -595,6 +595,16 @@ void ipc_client_handle_command(struct ipc_client *client) {
switch (client->current_command) {
case IPC_COMMAND:
{
char *line = strtok(buf, "\n");
while (line) {
size_t line_length = strlen(line);
if (line + line_length >= buf + client->payload_length) {
break;
}
line[line_length] = ';';
line = strtok(NULL, "\n");
}
list_t *res_list = execute_command(buf, NULL, NULL);
transaction_commit_dirty();
char *json = cmd_results_to_json(res_list);

View file

@ -299,6 +299,14 @@ int main(int argc, char **argv) {
}
}
// Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the
// clear error message (when not running as an IPC client).
if (!getenv("XDG_RUNTIME_DIR") && optind == argc) {
fprintf(stderr,
"XDG_RUNTIME_DIR is not set in the environment. Aborting.\n");
exit(EXIT_FAILURE);
}
// As the 'callback' function for wlr_log is equivalent to that for
// sway, we do not need to override it.
if (debug) {
@ -312,9 +320,21 @@ int main(int argc, char **argv) {
wlr_log_init(WLR_ERROR, NULL);
}
log_kernel();
log_distro();
log_env();
detect_proprietary(allow_unsupported_gpu);
detect_raspi();
if (optind < argc) { // Behave as IPC client
if (optind != 1) {
sway_log(SWAY_ERROR, "Don't use options with the IPC client");
sway_log(SWAY_ERROR,
"Detected both options and positional arguments. If you "
"are trying to use the IPC client, options are not "
"supported. Otherwise, check the provided arguments for "
"issues. See `man 1 sway` or `sway -h` for usage. If you "
"are trying to generate a debug log, use "
"`sway -d 2>sway.log`.");
exit(EXIT_FAILURE);
}
if (!drop_permissions()) {
@ -334,11 +354,6 @@ int main(int argc, char **argv) {
return 1;
}
log_kernel();
log_distro();
detect_proprietary(allow_unsupported_gpu);
detect_raspi();
if (!drop_permissions()) {
server_fini(&server);
exit(EXIT_FAILURE);
@ -358,14 +373,14 @@ int main(int argc, char **argv) {
return 1;
}
ipc_init(&server);
log_env();
if (validate) {
bool valid = load_main_config(config_path, false, true);
free(config_path);
return valid ? 0 : 1;
}
ipc_init(&server);
setenv("WAYLAND_DISPLAY", server.socket, true);
if (!load_main_config(config_path, false, false)) {
sway_terminate(EXIT_FAILURE);

View file

@ -8,6 +8,13 @@ sway-input - input configuration file and commands
Sway allows for configuration of devices within the sway configuration file.
To obtain a list of available device identifiers, run *swaymsg -t get_inputs*.
Settings can also be applied to all input devices by using the wildcard, _\*_,
in place of _\<identifier\>_ in the commands below.
Tip: If the configuration settings do not appear to be taking effect, you could
try using _\*_ instead of _\<identifier\>_. If it works with the wildcard, try
using a different identifier from *swaymsg -t get_inputs* until you find the
correct input device.
# INPUT COMMANDS
@ -144,7 +151,13 @@ configured. While sway is running, _-_ (hyphen) can be used as an alias for the
current seat. Each seat has an independent keyboard focus and a separate cursor
that is controlled by the pointer devices of the seat. This is useful for
multiple people using the desktop at the same time with their own devices (each
sitting in their own "seat").
sitting in their own "seat"). The wildcard character, _\*_, can also be used in
place of _\<identifier\>_ to change settings for all seats.
Tip: If the configuration settings do not appear to be taking effect, you could
try using _\*_ instead of _\<identifier\>_. If it works with the wildcard, try
using a different identifier from *swaymsg -t get_seats* until you find the
correct seat.
*seat* <name> attach <input_identifier>
Attach an input device to this seat by its input identifier. A special

View file

@ -293,12 +293,13 @@ runtime.
overwrite a binding, swaynag will give you a warning. To silence this, use
the _--no-warn_ flag.
Mouse buttons can either be specified in the form _button[1-9]_ or by using
the name of the event code (ex _BTN\_LEFT_ or _BTN\_RIGHT_). For the former
option, the buttons will be mapped to their values in X11 (1=left, 2=middle,
3=right, 4=scroll up, 5=scroll down, 6=scroll left, 7=scroll right, 8=back,
9=forward). For the latter option, you can find the event names using
_libinput debug-events_.
Mouse bindings operate on the container under the cursor instead of the
container that has focus. Mouse buttons can either be specified in the form
_button[1-9]_ or by using the name of the event code (ex _BTN\_LEFT_ or
_BTN\_RIGHT_). For the former option, the buttons will be mapped to their
values in X11 (1=left, 2=middle, 3=right, 4=scroll up, 5=scroll down,
6=scroll left, 7=scroll right, 8=back, 9=forward). For the latter option,
you can find the event names using _libinput debug-events_.
_--whole-window_, _--border_, and _--exclude-titlebar_ are mouse-only options
which affect the region in which the mouse bindings can be triggered. By
@ -413,10 +414,6 @@ The default colors are:
: #0c0c0c
*debuglog* on|off|toggle
Enables, disables or toggles debug logging. _toggle_ cannot be used in the
configuration file.
*default_border* normal|none|pixel [<n>]
Set default border style for new tiled windows.

View file

@ -251,11 +251,13 @@ static struct sway_container *container_at_stacked(struct sway_node *parent,
// Title bars
int title_height = container_titlebar_height();
if (title_height > 0) {
int child_index = (ly - box.y) / title_height;
if (child_index < children->length) {
struct sway_container *child = children->items[child_index];
return child;
}
}
// Surfaces
struct sway_node *current = seat_get_active_tiling_child(seat, parent);

View file

@ -8,7 +8,6 @@
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/output.h"
#include "sway/tree/workspace.h"
#include "log.h"
#include "util.h"
@ -234,9 +233,8 @@ void output_disable(struct sway_output *output) {
root_for_each_container(untrack_output, output);
if (output->bg_pid) {
terminate_swaybg(output->bg_pid);
output->bg_pid = 0;
if (output->swaybg_client != NULL) {
wl_client_destroy(output->swaybg_client);
}
int index = list_find(root->outputs, output);

View file

@ -664,6 +664,13 @@ void view_unmap(struct sway_view *view) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
seat->cursor->image_surface = NULL;
if (seat->cursor->active_constraint) {
struct wlr_surface *constrain_surface =
seat->cursor->active_constraint->surface;
if (view_from_wlr_surface(constrain_surface) == view) {
sway_cursor_constrain(seat->cursor, NULL);
}
}
seat_consider_warp_to_focus(seat);
}
@ -701,6 +708,9 @@ static void subsurface_get_root_coords(struct sway_view_child *child,
while (surface && wlr_surface_is_subsurface(surface)) {
struct wlr_subsurface *subsurface =
wlr_subsurface_from_wlr_surface(surface);
if (subsurface == NULL) {
break;
}
*root_sx += subsurface->current.x;
*root_sy += subsurface->current.y;
surface = subsurface->parent;

View file

@ -42,10 +42,16 @@ struct sway_output *workspace_get_initial_output(const char *name) {
}
}
}
// Otherwise put it on the focused output
// Otherwise try to put it on the focused output
struct sway_seat *seat = input_manager_current_seat();
struct sway_workspace *focus = seat_get_focused_workspace(seat);
return focus->output;
struct sway_node *focus = seat_get_focus_inactive(seat, &root->node);
if (focus && focus->type == N_WORKSPACE) {
return focus->sway_workspace->output;
} else if (focus && focus->type == N_CONTAINER) {
return focus->sway_container->workspace->output;
}
// Fallback to the first output or noop output for headless
return root->outputs->length ? root->outputs->items[0] : root->noop_output;
}
static void prevent_invalid_outer_gaps(struct sway_workspace *ws) {
@ -328,16 +334,13 @@ char *workspace_next_name(const char *output_name) {
if (target != NULL) {
return target;
}
// As a fall back, get the current number of active workspaces
// and return that + 1 for the next workspace's name
int ws_num = root->outputs->length;
int l = snprintf(NULL, 0, "%d", ws_num);
char *name = malloc(l + 1);
if (!sway_assert(name, "Could not allocate workspace name")) {
return NULL;
}
sprintf(name, "%d", ws_num++);
return name;
// As a fall back, use the next available number
char name[12] = "";
unsigned int ws_num = 1;
do {
snprintf(name, sizeof(name), "%u", ws_num++);
} while (workspace_by_number(name));
return strdup(name);
}
static bool _workspace_by_number(struct sway_workspace *ws, void *data) {
@ -445,9 +448,15 @@ struct sway_workspace *workspace_prev(struct sway_workspace *current) {
bool workspace_switch(struct sway_workspace *workspace,
bool no_auto_back_and_forth) {
struct sway_seat *seat = input_manager_current_seat();
struct sway_workspace *active_ws = seat_get_focused_workspace(seat);
struct sway_workspace *active_ws = NULL;
struct sway_node *focus = seat_get_focus_inactive(seat, &root->node);
if (focus && focus->type == N_WORKSPACE) {
active_ws = focus->sway_workspace;
} else if (focus && focus->type == N_CONTAINER) {
active_ws = focus->sway_container->workspace;
}
if (!no_auto_back_and_forth && config->auto_back_and_forth
if (!no_auto_back_and_forth && config->auto_back_and_forth && active_ws
&& active_ws == workspace && seat->prev_workspace_name) {
struct sway_workspace *new_ws =
workspace_by_name(seat->prev_workspace_name);
@ -456,9 +465,9 @@ bool workspace_switch(struct sway_workspace *workspace,
workspace_create(NULL, seat->prev_workspace_name);
}
if (!seat->prev_workspace_name ||
if (active_ws && (!seat->prev_workspace_name ||
(strcmp(seat->prev_workspace_name, active_ws->name)
&& active_ws != workspace)) {
&& active_ws != workspace))) {
free(seat->prev_workspace_name);
seat->prev_workspace_name = malloc(strlen(active_ws->name) + 1);
if (!seat->prev_workspace_name) {

View file

@ -4,6 +4,7 @@
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
@ -403,8 +404,7 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) {
static void display_in(int fd, short mask, void *data) {
struct swaybar *bar = data;
if (wl_display_dispatch(bar->display) == -1) {
bar_teardown(bar);
exit(0);
bar->running = false;
}
}
@ -439,7 +439,7 @@ void bar_run(struct swaybar *bar) {
loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar->tray->bus);
}
#endif
while (1) {
while (bar->running) {
errno = 0;
if (wl_display_flush(bar->display) == -1 && errno != EAGAIN) {
break;

View file

@ -11,13 +11,7 @@
static struct swaybar swaybar;
void sig_handler(int signal) {
bar_teardown(&swaybar);
exit(0);
}
void sway_terminate(int code) {
bar_teardown(&swaybar);
exit(code);
swaybar.running = false;
}
int main(int argc, char **argv) {
@ -93,8 +87,6 @@ int main(int argc, char **argv) {
}
}
signal(SIGTERM, sig_handler);
if (!bar_setup(&swaybar, socket_path)) {
free(socket_path);
return 1;
@ -102,6 +94,10 @@ int main(int argc, char **argv) {
free(socket_path);
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
swaybar.running = true;
bar_run(&swaybar);
bar_teardown(&swaybar);
return 0;

View file

@ -189,9 +189,9 @@ bool init_host(struct swaybar_host *host, char *protocol,
goto error;
}
sd_bus_slot_set_floating(reg_slot, 1);
sd_bus_slot_set_floating(unreg_slot, 1);
sd_bus_slot_set_floating(watcher_slot, 1);
sd_bus_slot_set_floating(reg_slot, 0);
sd_bus_slot_set_floating(unreg_slot, 0);
sd_bus_slot_set_floating(watcher_slot, 0);
sway_log(SWAY_DEBUG, "Registered %s", host->service);
return true;

View file

@ -299,6 +299,8 @@ void destroy_sni(struct swaybar_sni *sni) {
return;
}
cairo_surface_destroy(sni->icon);
sd_bus_slot_unref(sni->new_icon_slot);
sd_bus_slot_unref(sni->new_attention_icon_slot);
sd_bus_slot_unref(sni->new_status_slot);
@ -308,9 +310,11 @@ void destroy_sni(struct swaybar_sni *sni) {
free(sni->path);
free(sni->status);
free(sni->icon_name);
free(sni->icon_pixmap);
list_free_items_and_destroy(sni->icon_pixmap);
free(sni->attention_icon_name);
list_free_items_and_destroy(sni->attention_icon_pixmap);
free(sni->menu);
free(sni->icon_theme_path);
free(sni);
}

View file

@ -18,10 +18,6 @@ static int cmp_id(const void *item, const void *cmp_to) {
return strcmp(item, cmp_to);
}
static int cmp_service(const void *item, const void *cmp_to) {
return strncmp(item, cmp_to, strlen(cmp_to));
}
static int handle_lost_service(sd_bus_message *msg,
void *data, sd_bus_error *error) {
char *service, *old_owner, *new_owner;
@ -33,18 +29,23 @@ static int handle_lost_service(sd_bus_message *msg,
if (!*new_owner) {
struct swaybar_watcher *watcher = data;
int idx = list_seq_find(watcher->items,
using_standard_protocol(watcher) ? cmp_id : cmp_service, service);
if (idx != -1) {
for (int idx = 0; idx < watcher->items->length; ++idx) {
char *id = watcher->items->items[idx];
int cmp_res = using_standard_protocol(watcher) ?
cmp_id(id, service) : strncmp(id, service, strlen(service));
if (cmp_res == 0) {
sway_log(SWAY_DEBUG, "Unregistering Status Notifier Item '%s'", id);
list_del(watcher->items, idx);
list_del(watcher->items, idx--);
sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface,
"StatusNotifierItemUnregistered", "s", id);
free(id);
if (using_standard_protocol(watcher)) {
break;
}
}
}
idx = list_seq_find(watcher->hosts, cmp_id, service);
int idx = list_seq_find(watcher->hosts, cmp_id, service);
if (idx != -1) {
sway_log(SWAY_DEBUG, "Unregistering Status Notifier Host '%s'", service);
free(watcher->hosts->items[idx]);
@ -185,8 +186,8 @@ struct swaybar_watcher *create_watcher(char *protocol, sd_bus *bus) {
goto error;
}
sd_bus_slot_set_floating(signal_slot, 1);
sd_bus_slot_set_floating(vtable_slot, 1);
sd_bus_slot_set_floating(signal_slot, 0);
sd_bus_slot_set_floating(vtable_slot, 0);
watcher->bus = bus;
watcher->hosts = create_list();

View file

@ -135,8 +135,8 @@ static void pretty_print_input(json_object *i) {
json_object_get_int(vendor));
if (json_object_object_get_ex(i, "xkb_active_layout_name", &kbdlayout)) {
printf(" Active Keyboard Layout: %s\n",
json_object_get_string(kbdlayout));
const char *layout = json_object_get_string(kbdlayout);
printf(" Active Keyboard Layout: %s\n", layout ? layout : "(unnamed)");
}
if (json_object_object_get_ex(i, "libinput_send_events", &events)) {

View file

@ -348,6 +348,10 @@ int swaynag_load_config(char *path, struct swaynag *swaynag, list_t *types) {
continue;
}
if (line[nread - 1] == '\n') {
line[nread - 1] = '\0';
}
if (line[0] == '[') {
char *close = strchr(line, ']');
if (!close) {