Merge branch 'wlroots' into multibackend

This commit is contained in:
Tony Crisci 2018-02-24 21:03:58 -05:00
commit 9a50972577
186 changed files with 2893 additions and 16072 deletions

View file

@ -79,7 +79,7 @@ struct ipc_response *ipc_recv_response(int socketfd) {
error_2:
free(response);
error_1:
sway_log(L_ERROR, "Unable to allocate memory for IPC response");
wlr_log(L_ERROR, "Unable to allocate memory for IPC response");
return NULL;
}

View file

@ -1,167 +1,26 @@
#define _POSIX_C_SOURCE 199506L
#include <errno.h>
#include <libgen.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include "log.h"
#include "readline.h"
static int colored = 1;
static log_importance_t loglevel_default = L_ERROR;
static log_importance_t v = L_SILENT;
static const char *verbosity_colors[] = {
[L_SILENT] = "",
[L_ERROR ] = "\x1B[1;31m",
[L_INFO ] = "\x1B[1;34m",
[L_DEBUG ] = "\x1B[1;30m",
};
static const char verbosity_chars[] = {
[L_SILENT] = '\0',
[L_ERROR ] = 'E',
[L_INFO ] = 'I',
[L_DEBUG ] = 'D',
};
void init_log(log_importance_t verbosity) {
if (verbosity != L_DEBUG) {
// command "debuglog" needs to know the user specified log level when
// turning off debug logging.
loglevel_default = verbosity;
}
v = verbosity;
}
void set_log_level(log_importance_t verbosity) {
v = verbosity;
}
log_importance_t get_log_level(void) {
return v;
}
void reset_log_level(void) {
v = loglevel_default;
}
bool toggle_debug_logging(void) {
v = (v == L_DEBUG) ? loglevel_default : L_DEBUG;
return (v == L_DEBUG);
}
void sway_log_colors(int mode) {
colored = (mode == 1) ? 1 : 0;
}
void _sway_vlog(const char *filename, int line, log_importance_t verbosity,
const char *format, va_list args) {
if (verbosity <= v) {
// prefix the time to the log message
static struct tm result;
static time_t t;
static struct tm *tm_info;
char buffer[26];
unsigned int c = verbosity;
if (c > sizeof(verbosity_colors) / sizeof(char *) - 1) {
c = sizeof(verbosity_colors) / sizeof(char *) - 1;
}
// First, if not printing color, show the log level
if (!(colored && isatty(STDERR_FILENO)) && c != L_SILENT) {
fprintf(stderr, "%c: ", verbosity_chars[c]);
}
// get current time
t = time(NULL);
// convert time to local time (determined by the locale)
tm_info = localtime_r(&t, &result);
// generate time prefix
strftime(buffer, sizeof(buffer), "%x %X - ", tm_info);
fprintf(stderr, "%s", buffer);
if (colored && isatty(STDERR_FILENO)) {
fprintf(stderr, "%s", verbosity_colors[c]);
}
if (filename && line) {
const char *file = filename + strlen(filename);
while (file != filename && *file != '/') {
--file;
}
if (*file == '/') {
++file;
}
fprintf(stderr, "[%s:%d] ", file, line);
}
vfprintf(stderr, format, args);
if (colored && isatty(STDERR_FILENO)) {
fprintf(stderr, "\x1B[0m");
}
fprintf(stderr, "\n");
}
}
void _sway_log(const char *filename, int line, log_importance_t verbosity, const char* format, ...) {
va_list args;
va_start(args, format);
_sway_vlog(filename, line, verbosity, format, args);
va_end(args);
}
void sway_terminate(int code);
void _sway_abort(const char *filename, int line, const char* format, ...) {
void _sway_abort(const char *format, ...) {
va_list args;
va_start(args, format);
_sway_vlog(filename, line, L_ERROR, format, args);
_wlr_vlog(L_ERROR, format, args);
va_end(args);
sway_terminate(EXIT_FAILURE);
}
void sway_log_errno(log_importance_t verbosity, char* format, ...) {
if (verbosity <= v) {
unsigned int c = verbosity;
if (c > sizeof(verbosity_colors) / sizeof(char *) - 1) {
c = sizeof(verbosity_colors) / sizeof(char *) - 1;
}
if (colored && isatty(STDERR_FILENO)) {
fprintf(stderr, "%s", verbosity_colors[c]);
} else if (c != L_SILENT) {
fprintf(stderr, "%c: ", verbosity_chars[c]);
}
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, ": ");
fprintf(stderr, "%s", strerror(errno));
if (colored && isatty(STDERR_FILENO)) {
fprintf(stderr, "\x1B[0m");
}
fprintf(stderr, "\n");
}
}
bool _sway_assert(bool condition, const char *filename, int line, const char* format, ...) {
bool _sway_assert(bool condition, const char *format, ...) {
if (condition) {
return true;
}
va_list args;
va_start(args, format);
_sway_vlog(filename, line, L_ERROR, format, args);
_wlr_vlog(L_ERROR, format, args);
va_end(args);
#ifndef NDEBUG

View file

@ -8,7 +8,7 @@ char *read_line(FILE *file) {
char *string = malloc(size);
char lastChar = '\0';
if (!string) {
sway_log(L_ERROR, "Unable to allocate memory for read_line");
wlr_log(L_ERROR, "Unable to allocate memory for read_line");
return NULL;
}
while (1) {
@ -29,7 +29,7 @@ char *read_line(FILE *file) {
char *new_string = realloc(string, size *= 2);
if (!new_string) {
free(string);
sway_log(L_ERROR, "Unable to allocate memory for read_line");
wlr_log(L_ERROR, "Unable to allocate memory for read_line");
return NULL;
}
string = new_string;

View file

@ -113,7 +113,7 @@ uint32_t parse_color(const char *color) {
int len = strlen(color);
if (len != 6 && len != 8) {
sway_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color);
wlr_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color);
return 0xFFFFFFFF;
}
uint32_t res = (uint32_t)strtoul(color, NULL, 16);

View file

@ -1,38 +1,15 @@
#ifndef _SWAY_LOG_H
#define _SWAY_LOG_H
#include <stdbool.h>
#include <wlr/util/log.h>
typedef enum {
L_SILENT = 0,
L_ERROR = 1,
L_INFO = 2,
L_DEBUG = 3,
} log_importance_t;
void init_log(log_importance_t verbosity);
void set_log_level(log_importance_t verbosity);
log_importance_t get_log_level(void);
void reset_log_level(void);
// returns whether debug logging is on after switching.
bool toggle_debug_logging(void);
void sway_log_colors(int mode);
void sway_log_errno(log_importance_t verbosity, char* format, ...) __attribute__((format(printf,2,3)));
void _sway_abort(const char *filename, int line, const char* format, ...) __attribute__((format(printf,3,4)));
void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2);
#define sway_abort(FMT, ...) \
_sway_abort(__FILE__, __LINE__, FMT, ##__VA_ARGS__)
_sway_abort("[%s:%d] " FMT, wlr_strip_path(__FILE__), __LINE__, ##__VA_ARGS__)
bool _sway_assert(bool condition, const char *filename, int line, const char* format, ...) __attribute__((format(printf,4,5)));
bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3);
#define sway_assert(COND, FMT, ...) \
_sway_assert(COND, __FILE__, __LINE__, "%s:" FMT, __PRETTY_FUNCTION__, ##__VA_ARGS__)
void _sway_log(const char *filename, int line, log_importance_t verbosity, const char* format, ...) __attribute__((format(printf,4,5)));
#define sway_log(VERBOSITY, FMT, ...) \
_sway_log(__FILE__, __LINE__, VERBOSITY, FMT, ##__VA_ARGS__)
#define sway_vlog(VERBOSITY, FMT, VA_ARGS) \
_sway_vlog(__FILE__, __LINE__, VERBOSITY, FMT, VA_ARGS)
_sway_assert(COND, "[%s:%d] %s:" FMT, wlr_strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
void error_handler(int sig);

View file

@ -46,9 +46,9 @@ struct cmd_results *checkarg(int argc, const char *name,
enum expected_args type, int val);
/**
* Parse and handles a command.
* Parse and executes a command.
*/
struct cmd_results *handle_command(char *command);
struct cmd_results *execute_command(char *command, struct sway_seat *seat);
/**
* Parse and handles a command during config file loading.
*

View file

@ -46,7 +46,8 @@ struct sway_mouse_binding {
*/
struct sway_mode {
char *name;
list_t *bindings;
list_t *keysym_bindings;
list_t *keycode_bindings;
};
/**
@ -349,6 +350,14 @@ struct sway_config {
list_t *command_policies;
list_t *feature_policies;
list_t *ipc_policies;
// Context for command handlers
struct {
struct input_config *input_config;
struct seat_config *seat_config;
struct sway_seat *seat;
swayc_t *current_container;
} handler_context;
};
void pid_workspace_add(struct pid_workspace *pw);
@ -374,6 +383,10 @@ bool read_config(FILE *file, struct sway_config *config);
* Free config struct
*/
void free_config(struct sway_config *config);
void config_clear_handler_context(struct sway_config *config);
void free_sway_variable(struct sway_variable *var);
/**
* Does variable replacement for a string based on the config's currently loaded variables.
*/
@ -384,12 +397,14 @@ struct cmd_results *check_security_config();
int input_identifier_cmp(const void *item, const void *data);
struct input_config *new_input_config(const char* identifier);
void merge_input_config(struct input_config *dst, struct input_config *src);
struct input_config *copy_input_config(struct input_config *ic);
void free_input_config(struct input_config *ic);
void apply_input_config(struct input_config *input);
int seat_name_cmp(const void *item, const void *data);
struct seat_config *new_seat_config(const char* name);
void merge_seat_config(struct seat_config *dst, struct seat_config *src);
struct seat_config *copy_seat_config(struct seat_config *seat);
void free_seat_config(struct seat_config *ic);
struct seat_attachment_config *seat_attachment_config_new();
struct seat_attachment_config *seat_config_get_attachment(
@ -397,6 +412,8 @@ struct seat_attachment_config *seat_config_get_attachment(
void apply_seat_config(struct seat_config *seat);
int output_name_cmp(const void *item, const void *data);
void output_get_identifier(char *identifier, size_t len,
struct sway_output *output);
struct output_config *new_output_config(const char *name);
void merge_output_config(struct output_config *dst, struct output_config *src);
void apply_output_config(struct output_config *oc, swayc_t *output);

View file

@ -11,6 +11,7 @@ typedef struct sway_container swayc_t;
extern swayc_t root_container;
struct sway_view;
struct sway_seat;
/**
* Different kinds of containers.
@ -105,10 +106,6 @@ struct sway_container {
* The parent of this container. NULL for the root container.
*/
struct sway_container *parent;
/**
* Which of this container's children has focus.
*/
struct sway_container *focused;
/**
* Number of master views in auto layouts.
@ -140,9 +137,33 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view);
swayc_t *destroy_output(swayc_t *output);
swayc_t *destroy_view(swayc_t *view);
swayc_t *next_view_sibling(struct sway_seat *seat);
/**
* Finds a container based on test criteria. Returns the first container that
* passes the test.
*/
swayc_t *swayc_by_test(swayc_t *container,
bool (*test)(swayc_t *view, void *data), void *data);
/**
* Finds a parent container with the given swayc_type.
*/
swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type);
/**
* Maps a container's children over a function.
*/
void container_map(swayc_t *container,
void (*f)(swayc_t *view, void *data), void *data);
swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy);
/**
* Apply the function for each child of the container breadth first.
*/
void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data),
void *data);
swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout);
#endif

View file

@ -34,7 +34,7 @@ char *extract_crit_tokens(list_t *tokens, const char *criteria);
list_t *criteria_for(swayc_t *cont);
// Returns a list of all containers that match the given list of tokens.
list_t *container_for(list_t *tokens);
list_t *container_for_crit_tokens(list_t *tokens);
// Returns true if any criteria in the given list matches this container
bool criteria_any(swayc_t *cont, list_t *criteria);

View file

@ -25,6 +25,7 @@ struct sway_cursor {
struct wl_listener request_set_cursor;
};
void sway_cursor_destroy(struct sway_cursor *cursor);
struct sway_cursor *sway_cursor_create(struct sway_seat *seat);
#endif

View file

@ -5,9 +5,6 @@
#include "sway/config.h"
#include "list.h"
extern struct input_config *current_input_config;
extern struct seat_config *current_seat_config;
/**
* The global singleton input manager
* TODO: make me not a global
@ -19,14 +16,15 @@ struct sway_input_device {
struct wlr_input_device *wlr_device;
struct input_config *config;
struct wl_list link;
struct wl_listener device_destroy;
};
struct sway_input_manager {
struct wl_listener input_add;
struct wl_listener input_remove;
struct sway_server *server;
struct wl_list devices;
struct wl_list seats;
struct wl_listener new_input;
};
struct sway_input_manager *sway_input_manager_create(
@ -46,4 +44,13 @@ void sway_input_manager_apply_input_config(struct sway_input_manager *input,
void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
struct seat_config *seat_config);
struct sway_seat *sway_input_manager_get_default_seat(
struct sway_input_manager *input);
struct sway_seat *input_manager_get_seat(struct sway_input_manager *input,
const char *seat_name);
/** Gets the last seat the user interacted with */
struct sway_seat *input_manager_current_seat(struct sway_input_manager *input);
#endif

View file

@ -3,6 +3,8 @@
#include "sway/input/seat.h"
#define SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP 32
struct sway_keyboard {
struct sway_seat_device *seat_device;
@ -10,6 +12,12 @@ struct sway_keyboard {
struct wl_listener keyboard_key;
struct wl_listener keyboard_modifiers;
xkb_keysym_t pressed_keysyms_translated[SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP];
uint32_t modifiers_translated;
xkb_keysym_t pressed_keysyms_raw[SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP];
uint32_t modifiers_raw;
};
struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,

View file

@ -12,14 +12,26 @@ struct sway_seat_device {
struct wl_list link; // sway_seat::devices
};
struct sway_seat_container {
struct sway_seat *seat;
swayc_t *container;
struct wl_list link; // sway_seat::focus_stack
struct wl_listener destroy;
};
struct sway_seat {
struct wlr_seat *wlr_seat;
struct seat_config *config;
struct sway_cursor *cursor;
struct sway_input_manager *input;
swayc_t *focus;
bool has_focus;
struct wl_list focus_stack; // list of containers in focus order
struct wl_listener focus_destroy;
struct wl_listener new_container;
struct wl_list devices; // sway_seat_device::link
@ -29,6 +41,8 @@ struct sway_seat {
struct sway_seat *sway_seat_create(struct sway_input_manager *input,
const char *seat_name);
void sway_seat_destroy(struct sway_seat *seat);
void sway_seat_add_device(struct sway_seat *seat,
struct sway_input_device *device);
@ -42,6 +56,22 @@ void sway_seat_configure_xcursor(struct sway_seat *seat);
void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container);
swayc_t *sway_seat_get_focus(struct sway_seat *seat);
/**
* Return the last container to be focused for the seat (or the most recently
* opened if no container has received focused) that is a child of the given
* container. The focus-inactive container of the root window is the focused
* container for the seat (if the seat does have focus). This function can be
* used to determine what container gets focused next if the focused container
* is destroyed, or focus moves to a container with children and we need to
* descend into the next leaf in focus order.
*/
swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container);
swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat,
enum swayc_types type);
void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config);
#endif

View file

@ -2,6 +2,19 @@
#define _SWAY_LAYOUT_H
#include <wlr/types/wlr_output_layout.h>
#include "sway/container.h"
enum movement_direction {
MOVE_LEFT,
MOVE_RIGHT,
MOVE_UP,
MOVE_DOWN,
MOVE_PARENT,
MOVE_CHILD,
MOVE_NEXT,
MOVE_PREV,
MOVE_FIRST
};
struct sway_container;
@ -9,13 +22,22 @@ struct sway_root {
struct wlr_output_layout *output_layout;
struct wl_listener output_layout_change;
struct wl_list unmanaged_views; // sway_view::unmanaged_view_link
struct {
struct wl_signal new_container;
} events;
};
void init_layout(void);
void add_child(struct sway_container *parent, struct sway_container *child);
swayc_t *add_sibling(swayc_t *parent, swayc_t *child);
struct sway_container *remove_child(struct sway_container *child);
enum swayc_layouts default_layout(struct sway_container *output);
void sort_workspaces(struct sway_container *output);
void arrange_windows(struct sway_container *container, double width, double height);
swayc_t *get_swayc_in_direction(swayc_t *container,
struct sway_seat *seat, enum movement_direction dir);
#endif

View file

@ -1,28 +0,0 @@
#ifndef _SWAY_BORDER_H
#define _SWAY_BORDER_H
#include <wlc/wlc.h>
#include "container.h"
/**
* Border pixel buffer and corresponding geometry.
*/
struct border {
unsigned char *buffer;
struct wlc_geometry geometry;
};
/**
* Clear border buffer.
*/
void border_clear(struct border *border);
/**
* Recursively update all of the borders within a container.
*/
void update_container_border(swayc_t *container);
void render_view_borders(wlc_handle view);
int get_font_text_height(const char *font);
bool should_hide_top_border(swayc_t *con, double y);
#endif

View file

@ -1,214 +0,0 @@
#ifndef _SWAY_COMMANDS_H
#define _SWAY_COMMANDS_H
#include <stdbool.h>
#include <json-c/json.h>
#include <wlc/wlc.h>
#include "config.h"
// Container that a called command should act upon. Only valid in command functions.
extern swayc_t *current_container;
/**
* Indicates the result of a command's execution.
*/
enum cmd_status {
CMD_SUCCESS, /**< The command was successful */
CMD_FAILURE, /**< The command resulted in an error */
CMD_INVALID, /**< Unknown command or parser error */
CMD_DEFER, /**< Command execution deferred */
// Config Blocks
CMD_BLOCK_END,
CMD_BLOCK_MODE,
CMD_BLOCK_BAR,
CMD_BLOCK_BAR_COLORS,
CMD_BLOCK_INPUT,
CMD_BLOCK_COMMANDS,
CMD_BLOCK_IPC,
CMD_BLOCK_IPC_EVENTS,
};
/**
* Stores the result of executing a command.
*/
struct cmd_results {
enum cmd_status status;
char *input;
/**
* Human friendly error message, or NULL on success
*/
char *error;
};
enum expected_args {
EXPECTED_MORE_THAN,
EXPECTED_AT_LEAST,
EXPECTED_LESS_THAN,
EXPECTED_EQUAL_TO
};
struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val);
struct cmd_results *add_color(const char*, char*, const char*);
void input_cmd_apply(struct input_config *input);
void hide_view_in_scratchpad(swayc_t *sp_view);
swayc_t *sp_view;
int sp_index;
/**
* Parse and handles a command.
*/
struct cmd_results *handle_command(char *command, enum command_context context);
/**
* Parse and handles a command during config file loading.
*
* Do not use this under normal conditions.
*/
struct cmd_results *config_command(char *command, enum cmd_status block);
/*
* Parses a command policy rule.
*/
struct cmd_results *config_commands_command(char *exec);
/**
* Allocates a cmd_results object.
*/
struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, const char *error, ...);
/**
* Frees a cmd_results object.
*/
void free_cmd_results(struct cmd_results *results);
/**
* Serializes cmd_results to a JSON string.
*
* Free the JSON string later on.
*/
const char *cmd_results_to_json(struct cmd_results *results);
void remove_view_from_scratchpad(swayc_t *);
/**
* Actual command function signatures for individual .c files in commands/ directory.
*/
typedef struct cmd_results *sway_cmd(int argc, char **argv);
sway_cmd cmd_assign;
sway_cmd cmd_bar;
sway_cmd cmd_bindcode;
sway_cmd cmd_bindsym;
sway_cmd cmd_border;
sway_cmd cmd_client_focused;
sway_cmd cmd_client_focused_inactive;
sway_cmd cmd_client_unfocused;
sway_cmd cmd_client_urgent;
sway_cmd cmd_client_placeholder;
sway_cmd cmd_client_background;
sway_cmd cmd_clipboard;
sway_cmd cmd_commands;
sway_cmd cmd_debuglog;
sway_cmd cmd_default_border;
sway_cmd cmd_default_floating_border;
sway_cmd cmd_exec;
sway_cmd cmd_exec_always;
sway_cmd cmd_exit;
sway_cmd cmd_floating;
sway_cmd cmd_floating_maximum_size;
sway_cmd cmd_floating_minimum_size;
sway_cmd cmd_floating_mod;
sway_cmd cmd_floating_scroll;
sway_cmd cmd_focus;
sway_cmd cmd_focus_follows_mouse;
sway_cmd cmd_font;
sway_cmd cmd_for_window;
sway_cmd cmd_force_focus_wrapping;
sway_cmd cmd_fullscreen;
sway_cmd cmd_gaps;
sway_cmd cmd_hide_edge_borders;
sway_cmd cmd_include;
sway_cmd cmd_input;
sway_cmd cmd_ipc;
sway_cmd cmd_kill;
sway_cmd cmd_layout;
sway_cmd cmd_log_colors;
sway_cmd cmd_mark;
sway_cmd cmd_mode;
sway_cmd cmd_mouse_warping;
sway_cmd cmd_move;
sway_cmd cmd_new_float;
sway_cmd cmd_new_window;
sway_cmd cmd_no_focus;
sway_cmd cmd_orientation;
sway_cmd cmd_output;
sway_cmd cmd_permit;
sway_cmd cmd_reject;
sway_cmd cmd_reload;
sway_cmd cmd_resize;
sway_cmd cmd_scratchpad;
sway_cmd cmd_seamless_mouse;
sway_cmd cmd_set;
sway_cmd cmd_show_marks;
sway_cmd cmd_smart_gaps;
sway_cmd cmd_split;
sway_cmd cmd_splith;
sway_cmd cmd_splitt;
sway_cmd cmd_splitv;
sway_cmd cmd_sticky;
sway_cmd cmd_unmark;
sway_cmd cmd_workspace;
sway_cmd cmd_ws_auto_back_and_forth;
sway_cmd cmd_workspace_layout;
sway_cmd bar_cmd_activate_button;
sway_cmd bar_cmd_binding_mode_indicator;
sway_cmd bar_cmd_bindsym;
sway_cmd bar_cmd_colors;
sway_cmd bar_cmd_context_button;
sway_cmd bar_cmd_font;
sway_cmd bar_cmd_mode;
sway_cmd bar_cmd_modifier;
sway_cmd bar_cmd_output;
sway_cmd bar_cmd_height;
sway_cmd bar_cmd_hidden_state;
sway_cmd bar_cmd_icon_theme;
sway_cmd bar_cmd_id;
sway_cmd bar_cmd_position;
sway_cmd bar_cmd_secondary_button;
sway_cmd bar_cmd_separator_symbol;
sway_cmd bar_cmd_status_command;
sway_cmd bar_cmd_pango_markup;
sway_cmd bar_cmd_strip_workspace_numbers;
sway_cmd bar_cmd_swaybar_command;
sway_cmd bar_cmd_tray_output;
sway_cmd bar_cmd_tray_padding;
sway_cmd bar_cmd_wrap_scroll;
sway_cmd bar_cmd_workspace_buttons;
sway_cmd bar_colors_cmd_active_workspace;
sway_cmd bar_colors_cmd_background;
sway_cmd bar_colors_cmd_focused_background;
sway_cmd bar_colors_cmd_binding_mode;
sway_cmd bar_colors_cmd_focused_workspace;
sway_cmd bar_colors_cmd_inactive_workspace;
sway_cmd bar_colors_cmd_separator;
sway_cmd bar_colors_cmd_focused_separator;
sway_cmd bar_colors_cmd_statusline;
sway_cmd bar_colors_cmd_focused_statusline;
sway_cmd bar_colors_cmd_urgent_workspace;
sway_cmd input_cmd_accel_profile;
sway_cmd input_cmd_click_method;
sway_cmd input_cmd_drag_lock;
sway_cmd input_cmd_dwt;
sway_cmd input_cmd_events;
sway_cmd input_cmd_left_handed;
sway_cmd input_cmd_middle_emulation;
sway_cmd input_cmd_natural_scroll;
sway_cmd input_cmd_pointer_accel;
sway_cmd input_cmd_scroll_method;
sway_cmd input_cmd_tap;
sway_cmd cmd_ipc_cmd;
sway_cmd cmd_ipc_events;
sway_cmd cmd_ipc_event_cmd;
#endif

View file

@ -1,406 +0,0 @@
#ifndef _SWAY_CONFIG_H
#define _SWAY_CONFIG_H
#define PID_WORKSPACE_TIMEOUT 60
#include <libinput.h>
#include <stdint.h>
#include <wlc/geometry.h>
#include <wlc/wlc.h>
#include <xkbcommon/xkbcommon.h>
#include <time.h>
#include "wayland-desktop-shell-server-protocol.h"
#include "list.h"
#include "layout.h"
#include "container.h"
/**
* Describes a variable created via the `set` command.
*/
struct sway_variable {
char *name;
char *value;
};
/**
* A key binding and an associated command.
*/
struct sway_binding {
int order;
bool release;
bool bindcode;
list_t *keys;
uint32_t modifiers;
char *command;
};
/**
* A mouse binding and an associated command.
*/
struct sway_mouse_binding {
uint32_t button;
char *command;
};
/**
* A "mode" of keybindings created via the `mode` command.
*/
struct sway_mode {
char *name;
list_t *bindings;
};
/**
* libinput options for input devices
*/
struct input_config {
char *identifier;
int accel_profile;
int click_method;
int drag_lock;
int dwt;
int left_handed;
int middle_emulation;
int natural_scroll;
float pointer_accel;
int scroll_method;
int send_events;
int tap;
bool capturable;
struct wlc_geometry region;
};
/**
* Size and position configuration for a particular output.
*
* This is set via the `output` command.
*/
struct output_config {
char *name;
int enabled;
int width, height;
int x, y;
int scale;
char *background;
char *background_option;
};
/**
* Maps a workspace name to an output name.
*
* Set via `workspace <x> output <y>`
*/
struct workspace_output {
char *output;
char *workspace;
};
struct pid_workspace {
pid_t *pid;
char *workspace;
time_t *time_added;
};
struct bar_config {
/**
* One of "dock", "hide", "invisible"
*
* Always visible in dock mode. Visible only when modifier key is held in hide mode.
* Never visible in invisible mode.
*/
char *mode;
/**
* One of "show" or "hide".
*
* In "show" mode, it will always be shown on top of the active workspace.
*/
char *hidden_state;
/**
* Id name used to identify the bar through IPC.
*
* Defaults to bar-x, where x corresponds to the position of the
* embedding bar block in the config file (bar-0, bar-1, ...).
*/
char *id;
uint32_t modifier;
list_t *outputs;
enum desktop_shell_panel_position position;
list_t *bindings;
char *status_command;
bool pango_markup;
char *swaybar_command;
char *font;
int height; // -1 not defined
#ifdef ENABLE_TRAY
// Tray
char *tray_output;
char *icon_theme;
uint32_t tray_padding;
uint32_t activate_button;
uint32_t context_button;
uint32_t secondary_button;
#endif
bool workspace_buttons;
bool wrap_scroll;
char *separator_symbol;
bool strip_workspace_numbers;
bool binding_mode_indicator;
bool verbose;
pid_t pid;
struct {
char *background;
char *statusline;
char *separator;
char *focused_background;
char *focused_statusline;
char *focused_separator;
char *focused_workspace_border;
char *focused_workspace_bg;
char *focused_workspace_text;
char *active_workspace_border;
char *active_workspace_bg;
char *active_workspace_text;
char *inactive_workspace_border;
char *inactive_workspace_bg;
char *inactive_workspace_text;
char *urgent_workspace_border;
char *urgent_workspace_bg;
char *urgent_workspace_text;
char *binding_mode_border;
char *binding_mode_bg;
char *binding_mode_text;
} colors;
};
struct border_colors {
uint32_t border;
uint32_t background;
uint32_t text;
uint32_t indicator;
uint32_t child_border;
};
enum edge_border_types {
E_NONE, /**< Don't hide edge borders */
E_VERTICAL, /**< hide vertical edge borders */
E_HORIZONTAL, /**< hide horizontal edge borders */
E_BOTH, /**< hide vertical and horizontal edge borders */
E_SMART /**< hide both if precisely one window is present in workspace */
};
enum command_context {
CONTEXT_CONFIG = 1,
CONTEXT_BINDING = 2,
CONTEXT_IPC = 4,
CONTEXT_CRITERIA = 8,
CONTEXT_ALL = 0xFFFFFFFF,
};
struct command_policy {
char *command;
uint32_t context;
};
enum secure_feature {
FEATURE_LOCK = 1,
FEATURE_PANEL = 2,
FEATURE_BACKGROUND = 4,
FEATURE_SCREENSHOT = 8,
FEATURE_FULLSCREEN = 16,
FEATURE_KEYBOARD = 32,
FEATURE_MOUSE = 64,
};
struct feature_policy {
char *program;
uint32_t features;
};
enum ipc_feature {
IPC_FEATURE_COMMAND = 1,
IPC_FEATURE_GET_WORKSPACES = 2,
IPC_FEATURE_GET_OUTPUTS = 4,
IPC_FEATURE_GET_TREE = 8,
IPC_FEATURE_GET_MARKS = 16,
IPC_FEATURE_GET_BAR_CONFIG = 32,
IPC_FEATURE_GET_VERSION = 64,
IPC_FEATURE_GET_INPUTS = 128,
IPC_FEATURE_EVENT_WORKSPACE = 256,
IPC_FEATURE_EVENT_OUTPUT = 512,
IPC_FEATURE_EVENT_MODE = 1024,
IPC_FEATURE_EVENT_WINDOW = 2048,
IPC_FEATURE_EVENT_BINDING = 4096,
IPC_FEATURE_EVENT_INPUT = 8192,
IPC_FEATURE_GET_CLIPBOARD = 16384,
IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384,
IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192,
IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS,
};
struct ipc_policy {
char *program;
uint32_t features;
};
/**
* The configuration struct. The result of loading a config file.
*/
struct sway_config {
list_t *symbols;
list_t *modes;
list_t *bars;
list_t *cmd_queue;
list_t *workspace_outputs;
list_t *pid_workspaces;
list_t *output_configs;
list_t *input_configs;
list_t *criteria;
list_t *no_focus;
list_t *active_bar_modifiers;
struct sway_mode *current_mode;
struct bar_config *current_bar;
uint32_t floating_mod;
uint32_t dragging_key;
uint32_t resizing_key;
char *floating_scroll_up_cmd;
char *floating_scroll_down_cmd;
char *floating_scroll_left_cmd;
char *floating_scroll_right_cmd;
enum swayc_layouts default_orientation;
enum swayc_layouts default_layout;
char *font;
int font_height;
// Flags
bool focus_follows_mouse;
bool mouse_warping;
bool force_focus_wrapping;
bool active;
bool failed;
bool reloading;
bool reading;
bool auto_back_and_forth;
bool seamless_mouse;
bool show_marks;
bool edge_gaps;
bool smart_gaps;
int gaps_inner;
int gaps_outer;
list_t *config_chain;
const char *current_config;
enum swayc_border_types border;
enum swayc_border_types floating_border;
int border_thickness;
int floating_border_thickness;
enum edge_border_types hide_edge_borders;
// border colors
struct {
struct border_colors focused;
struct border_colors focused_inactive;
struct border_colors unfocused;
struct border_colors urgent;
struct border_colors placeholder;
uint32_t background;
} border_colors;
// floating view
int32_t floating_maximum_width;
int32_t floating_maximum_height;
int32_t floating_minimum_width;
int32_t floating_minimum_height;
// Security
list_t *command_policies;
list_t *feature_policies;
list_t *ipc_policies;
};
void pid_workspace_add(struct pid_workspace *pw);
void free_pid_workspace(struct pid_workspace *pw);
/**
* Loads the main config from the given path. is_active should be true when
* reloading the config.
*/
bool load_main_config(const char *path, bool is_active);
/**
* Loads an included config. Can only be used after load_main_config.
*/
bool load_include_configs(const char *path, struct sway_config *config);
/**
* Reads the config from the given FILE.
*/
bool read_config(FILE *file, struct sway_config *config);
/**
* Free config struct
*/
void free_config(struct sway_config *config);
/**
* Does variable replacement for a string based on the config's currently loaded variables.
*/
char *do_var_replacement(char *str);
struct cmd_results *check_security_config();
int input_identifier_cmp(const void *item, const void *data);
void merge_input_config(struct input_config *dst, struct input_config *src);
void apply_input_config(struct input_config *ic, struct libinput_device *dev);
void free_input_config(struct input_config *ic);
int output_name_cmp(const void *item, const void *data);
void merge_output_config(struct output_config *dst, struct output_config *src);
/** Sets up a WLC output handle based on a given output_config.
*/
void apply_output_config(struct output_config *oc, swayc_t *output);
void free_output_config(struct output_config *oc);
/**
* Updates the list of active bar modifiers
*/
void update_active_bar_modifiers(void);
int workspace_output_cmp_workspace(const void *a, const void *b);
int sway_binding_cmp(const void *a, const void *b);
int sway_binding_cmp_qsort(const void *a, const void *b);
int sway_binding_cmp_keys(const void *a, const void *b);
void free_sway_binding(struct sway_binding *sb);
struct sway_binding *sway_binding_dup(struct sway_binding *sb);
int sway_mouse_binding_cmp(const void *a, const void *b);
int sway_mouse_binding_cmp_qsort(const void *a, const void *b);
int sway_mouse_binding_cmp_buttons(const void *a, const void *b);
void free_sway_mouse_binding(struct sway_mouse_binding *smb);
void load_swaybars();
void terminate_swaybg(pid_t pid);
/**
* Allocate and initialize default bar configuration.
*/
struct bar_config *default_bar_config(void);
/**
* Global config singleton.
*/
extern struct sway_config *config;
/**
* Config file currently being read.
*/
extern const char *current_config_path;
#endif

View file

@ -1,362 +0,0 @@
#ifndef _SWAY_CONTAINER_H
#define _SWAY_CONTAINER_H
#include <sys/types.h>
#include <wlc/wlc.h>
#include <wlr/types/wlr_output.h>
#include <stdint.h>
#include "list.h"
typedef struct sway_container swayc_t;
extern swayc_t root_container;
extern swayc_t *current_focus;
struct sway_view;
/**
* Different kinds of containers.
*
* This enum is in order. A container will never be inside of a container below
* it on this list.
*/
enum swayc_types {
C_ROOT, /**< The root container. Only one of these ever exists. */
C_OUTPUT, /**< An output (aka monitor, head, etc). */
C_WORKSPACE, /**< A workspace. */
C_CONTAINER, /**< A manually created container. */
C_VIEW, /**< A view (aka window). */
// Keep last
C_TYPES,
};
/**
* Different ways to arrange a container.
*/
enum swayc_layouts {
L_NONE, /**< Used for containers that have no layout (views, root) */
L_HORIZ,
L_VERT,
L_STACKED,
L_TABBED,
L_FLOATING, /**< A psuedo-container, removed from the tree, to hold floating windows */
/* Awesome/Monad style auto layouts */
L_AUTO_LEFT,
L_AUTO_RIGHT,
L_AUTO_TOP,
L_AUTO_BOTTOM,
L_AUTO_FIRST = L_AUTO_LEFT,
L_AUTO_LAST = L_AUTO_BOTTOM,
// Keep last
L_LAYOUTS,
};
enum swayc_border_types {
B_NONE, /**< No border */
B_PIXEL, /**< 1px border */
B_NORMAL /**< Normal border with title bar */
};
/**
* Stores information about a container.
*
* The tree is made of these. Views are containers that cannot have children.
*/
struct sway_container {
// TODO WLR: reconcile these
wlc_handle handle;
union {
struct sway_output *output;
struct sway_view *view;
} _handle;
/**
* A unique ID to identify this container. Primarily used in the
* get_tree JSON output.
*/
size_t id;
enum swayc_types type;
enum swayc_layouts layout;
enum swayc_layouts prev_layout;
enum swayc_layouts workspace_layout;
/**
* Width and height of this container, without borders or gaps.
*/
double width, height;
/**
* Views may request geometry, which is stored in this and ignored until
* the views are floated.
*/
int desired_width, desired_height;
/**
* The coordinates that this view appear at, relative to the output they
* are located on (output containers have absolute coordinates).
*/
double x, y;
/**
* Cached geometry used to store view/container geometry when switching
* between tabbed/stacked and horizontal/vertical layouts.
*/
struct wlc_geometry cached_geometry;
/**
* False if this view is invisible. It could be in the scratchpad or on a
* workspace that is not shown.
*/
bool visible;
bool is_floating;
bool is_focused;
bool sticky; // floating view always visible on its output
// Attributes that mostly views have.
char *name;
char *class;
char *instance;
char *app_id;
// Used by output containers to keep track of swaybg child processes.
pid_t bg_pid;
int gaps;
list_t *children;
/**
* Children of this container that are floated.
*/
list_t *floating;
/**
* Unmanaged view handles in this container.
*/
list_t *unmanaged;
/**
* The parent of this container. NULL for the root container.
*/
struct sway_container *parent;
/**
* Which of this container's children has focus.
*/
struct sway_container *focused;
/**
* If this container's children include a fullscreen view, this is that view.
*/
struct sway_container *fullscreen;
/**
* If this container is a view, this may be set to the window's decoration
* buffer (or NULL).
*/
struct border *border;
enum swayc_border_types border_type;
struct wlc_geometry border_geometry;
struct wlc_geometry title_bar_geometry;
struct wlc_geometry actual_geometry;
int border_thickness;
/**
* Number of master views in auto layouts.
*/
size_t nb_master;
/**
* Number of slave groups (e.g. columns) in auto layouts.
*/
size_t nb_slave_groups;
/**
* Marks applied to the container, list_t of char*.
*/
list_t *marks;
};
enum visibility_mask {
VISIBLE = true
} visible;
struct sway_output;
/**
* Allocates a new output container.
*/
swayc_t *new_output(struct sway_output *sway_output);
/**
* Allocates a new workspace container.
*/
swayc_t *new_workspace(swayc_t *output, const char *name);
/**
* Allocates a new container and places a child into it.
*
* This is used from the split command, which creates a new container with the
* requested layout and replaces the focused container in the tree with the new
* one. Then the removed container is added as a child of the new container.
*/
swayc_t *new_container(swayc_t *child, enum swayc_layouts layout);
/**
* Allocates a new view container.
*
* Pass in a sibling view, or a workspace to become this container's parent.
*/
swayc_t *new_view(swayc_t *sibling, struct sway_view *view);
/**
* Allocates a new floating view in the active workspace.
*/
swayc_t *new_floating_view(wlc_handle handle);
void floating_view_sane_size(swayc_t *view);
/**
* Frees an output's container.
*/
swayc_t *destroy_output(swayc_t *output);
/**
* Destroys a workspace container and returns the parent pointer, or NULL.
*/
swayc_t *destroy_workspace(swayc_t *workspace);
/**
* Destroys a container and all empty parents. Returns the topmost non-empty
* parent container, or NULL.
*/
swayc_t *destroy_container(swayc_t *container);
/**
* Destroys a view container and all empty parents. Returns the topmost
* non-empty parent container, or NULL.
*/
swayc_t *destroy_view(swayc_t *view);
/**
* Finds a container based on test criteria. Returns the first container that
* passes the test.
*/
swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data);
/**
* Finds a parent container with the given swayc_type.
*/
swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types);
/**
* Finds a parent with the given swayc_layout.
*/
swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts);
/**
* Finds the bottom-most focused container of a type.
*/
swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types);
/**
* Finds the bottom-most focused container of a layout.
*/
swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts);
/**
* Gets the swayc_t associated with a wlc_handle.
*/
swayc_t *swayc_by_handle(wlc_handle handle);
/**
* Gets the named swayc_t.
*/
swayc_t *swayc_by_name(const char *name);
/**
* Gets the active output's container.
*/
swayc_t *swayc_active_output(void);
/**
* Gets the active workspace's container.
*/
swayc_t *swayc_active_workspace(void);
/**
* Gets the workspace for the given view container.
*/
swayc_t *swayc_active_workspace_for(swayc_t *view);
/**
* Finds the container currently underneath the pointer.
*/
swayc_t *container_under_pointer(void);
/**
* Finds the first container following a callback.
*/
swayc_t *container_find(swayc_t *container, bool (*f)(swayc_t *, const void *), const void *data);
/**
* Returns true if a container is fullscreen.
*/
bool swayc_is_fullscreen(swayc_t *view);
/**
* Returns true if this view is focused.
*/
bool swayc_is_active(swayc_t *view);
/**
* Returns true if the parent is an ancestor of the child.
*/
bool swayc_is_parent_of(swayc_t *parent, swayc_t *child);
/**
* Returns true if the child is a desecendant of the parent.
*/
bool swayc_is_child_of(swayc_t *child, swayc_t *parent);
/**
* Returns true if this container is an empty workspace.
*/
bool swayc_is_empty_workspace(swayc_t *container);
/**
* Returns the top most tabbed or stacked parent container. Returns NULL if
* view is not in a tabbed/stacked layout.
*/
swayc_t *swayc_tabbed_stacked_ancestor(swayc_t *view);
/**
* Returns the immediate tabbed or stacked parent container. Returns NULL if
* view is not directly in a tabbed/stacked layout.
*/
swayc_t *swayc_tabbed_stacked_parent(swayc_t *view);
/**
* Returns the gap (padding) of the container.
*
* This returns the inner gaps for a view, the outer gaps for a workspace, and
* 0 otherwise.
*/
int swayc_gap(swayc_t *container);
/**
* Maps a container's children over a function.
*/
void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
/**
* Set a view as visible or invisible.
*
* This will perform the required wlc calls as well; it is not sufficient to
* simply toggle the boolean in swayc_t.
*/
void set_view_visibility(swayc_t *view, void *data);
/**
* Set the gaps value for a view.
*/
void set_gaps(swayc_t *view, void *amount);
/**
* Add to the gaps value for a view.
*/
void add_gaps(swayc_t *view, void *amount);
/**
* Issue wlc calls to make the visibility of a container consistent.
*/
void update_visibility(swayc_t *container);
/**
* Close all child views of container
*/
void close_views(swayc_t *container);
/**
* Assign layout to a container. Needed due to workspace container specifics.
* Workspace should always have either L_VERT or L_HORIZ layout.
*/
swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout);
#endif

View file

@ -1,45 +0,0 @@
#ifndef _SWAY_FOCUS_H
#define _SWAY_FOCUS_H
enum movement_direction {
MOVE_LEFT,
MOVE_RIGHT,
MOVE_UP,
MOVE_DOWN,
MOVE_PARENT,
MOVE_CHILD,
MOVE_NEXT,
MOVE_PREV,
MOVE_FIRST
};
#include "container.h"
// focused_container - the container found by following the `focused` pointer
// from a given container to a container with `is_focused` boolean set
// ---
// focused_view - the container found by following the `focused` pointer from a
// given container to a view.
// ---
swayc_t *get_focused_container(swayc_t *parent);
swayc_t *get_focused_view(swayc_t *parent);
swayc_t *get_focused_float(swayc_t *ws);
// a special-case function to get the focused view, regardless
// of whether it's tiled or floating
swayc_t *get_focused_view_include_floating(swayc_t *parent);
bool set_focused_container(swayc_t *container);
bool set_focused_container_for(swayc_t *ancestor, swayc_t *container);
// lock focused container/view. locked by windows with OVERRIDE attribute
// and unlocked when they are destroyed
extern bool locked_container_focus;
// Prevents wss from being destroyed on focus switch
extern bool suspend_workspace_cleanup;
bool move_focus(enum movement_direction direction);
#endif

View file

@ -1,24 +0,0 @@
#ifndef _SWAY_INPUT_H
#define _SWAY_INPUT_H
#include <libinput.h>
#include "sway/server.h"
#include "config.h"
#include "list.h"
struct sway_input {
list_t *input_devices;
};
struct input_config *new_input_config(const char* identifier);
char* libinput_dev_unique_id(struct libinput_device *dev);
struct sway_input *sway_input_create(struct sway_server *server);
/**
* Pointer used when reading input blocked.
* Shared so that it can be cleared from commands.c when closing the block
*/
extern struct input_config *current_input_config;
#endif

View file

@ -1,102 +0,0 @@
#ifndef _SWAY_KEY_STATE_H
#define _SWAY_KEY_STATE_H
#include <stdbool.h>
#include <stdint.h>
#include "container.h"
/* Keyboard state */
// returns true if key has been pressed, otherwise false
bool check_key(uint32_t key_sym, uint32_t key_code);
// returns true if key_sym matches latest released key.
bool check_released_key(uint32_t key_sym);
// sets a key as pressed
void press_key(uint32_t key_sym, uint32_t key_code);
// unsets a key as pressed
void release_key(uint32_t key_sym, uint32_t key_code);
/* Pointer state */
enum pointer_values {
M_LEFT_CLICK = 272,
M_RIGHT_CLICK = 273,
M_SCROLL_CLICK = 274,
M_SCROLL_UP = 275,
M_SCROLL_DOWN = 276,
};
enum pointer_mode {
// Target
M_FLOATING = 1,
M_TILING = 2,
// Action
M_DRAGGING = 4,
M_RESIZING = 8,
};
struct pointer_button_state {
bool held;
// state at the point it was pressed
int x, y;
swayc_t *view;
};
extern struct pointer_state {
// mouse clicks
struct pointer_button_state left;
struct pointer_button_state right;
struct pointer_button_state scroll;
// change in pointer position
struct {
int x, y;
} delta;
// view pointer is currently over
swayc_t *view;
// Pointer mode
int mode;
} pointer_state;
enum modifier_state {
MOD_STATE_UNCHANGED = 0,
MOD_STATE_PRESSED = 1,
MOD_STATE_RELEASED = 2
};
void pointer_position_set(double new_x, double new_y, bool force_focus);
void center_pointer_on(swayc_t *view);
// on button release unset mode depending on the button.
// on button press set mode conditionally depending on the button
void pointer_mode_set(uint32_t button, bool condition);
// Update mode in mouse motion
void pointer_mode_update(void);
// Reset mode on any keypress;
void pointer_mode_reset(void);
void input_init(void);
/**
* Check if state of mod changed from current state to new_state.
*
* Returns MOD_STATE_UNCHANGED if the state didn't change, MOD_STATE_PRESSED if
* the state changed to pressed and MOD_STATE_RELEASED if the state changed to
* released.
*/
uint32_t modifier_state_changed(uint32_t new_state, uint32_t mod);
/**
* Update the current modifiers state to new_state.
*/
void modifiers_state_update(uint32_t new_state);
#endif

View file

@ -1,15 +0,0 @@
#ifndef _SWAY_IPC_JSON_H
#define _SWAY_IPC_JSON_H
#include <json-c/json.h>
#include "config.h"
#include "container.h"
json_object *ipc_json_get_version();
json_object *ipc_json_describe_bar_config(struct bar_config *bar);
json_object *ipc_json_describe_container(swayc_t *c);
json_object *ipc_json_describe_container_recursive(swayc_t *c);
json_object *ipc_json_describe_window(swayc_t *c);
json_object *ipc_json_describe_input(struct libinput_device *device);
#endif

View file

@ -1,33 +0,0 @@
#ifndef _SWAY_IPC_SERVER_H
#define _SWAY_IPC_SERVER_H
#include "container.h"
#include "config.h"
#include "ipc.h"
void ipc_init(void);
void ipc_terminate(void);
struct sockaddr_un *ipc_user_sockaddr(void);
void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change);
void ipc_event_barconfig_update(struct bar_config *bar);
/**
* Send IPC mode event to all listening clients
*/
void ipc_event_mode(const char *mode);
/**
* Send IPC window change event
*/
void ipc_event_window(swayc_t *window, const char *change);
/**
* Sends an IPC modifier event to all listening clients. The modifier event
* includes a key 'change' with the value of state and a key 'modifier' with
* the name of that modifier.
*/
void ipc_event_modifier(uint32_t modifier, const char *state);
/**
* Send IPC keyboard binding event.
*/
void ipc_event_binding_keyboard(struct sway_binding *sb);
const char *swayc_type_string(enum swayc_types type);
#endif

View file

@ -1,85 +0,0 @@
#ifndef _SWAY_LAYOUT_H
#define _SWAY_LAYOUT_H
#include <wlc/wlc.h>
#include "log.h"
#include "list.h"
#include "container.h"
#include "focus.h"
extern list_t *scratchpad;
extern int min_sane_w;
extern int min_sane_h;
// Set initial values for root_container
void init_layout(void);
// Returns the index of child for its parent
int index_child(const swayc_t *child);
// Adds child to parent, if parent has no focus, it is set to child
// parent must be of type C_WORKSPACE or C_CONTAINER
void add_child(swayc_t *parent, swayc_t *child);
// Adds child to parent at index, if parent has no focus, it is set to child
// parent must be of type C_WORKSPACE or C_CONTAINER
void insert_child(swayc_t *parent, swayc_t *child, int index);
// Adds child as floating window to ws, if there is no focus it is set to child.
// ws must be of type C_WORKSPACE
void add_floating(swayc_t *ws, swayc_t *child);
// insert child after sibling in parents children.
swayc_t *add_sibling(swayc_t *sibling, swayc_t *child);
// Replace child with new_child in parents children
// new_child will inherit childs geometry, childs geometry will be reset
// if parents focus is on child, it will be changed to new_child
swayc_t *replace_child(swayc_t *child, swayc_t *new_child);
// Remove child from its parent, if focus is on child, focus will be changed to
// a sibling, or to a floating window, or NULL
swayc_t *remove_child(swayc_t *child);
// 2 containers are swapped, they inherit eachothers focus
void swap_container(swayc_t *a, swayc_t *b);
// 2 Containers geometry are swapped, used with `swap_container`
void swap_geometry(swayc_t *a, swayc_t *b);
void move_container(swayc_t* container, enum movement_direction direction, int move_amt);
void move_container_to(swayc_t* container, swayc_t* destination);
void move_workspace_to(swayc_t* workspace, swayc_t* destination);
// Layout
/**
* Update child container geometries when switching between layouts.
*/
void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout);
void update_geometry(swayc_t *view);
void arrange_windows(swayc_t *container, double width, double height);
void arrange_backgrounds(void);
swayc_t *get_focused_container(swayc_t *parent);
swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir);
swayc_t *get_swayc_in_direction_under(swayc_t *container, enum movement_direction dir, swayc_t *limit);
void recursive_resize(swayc_t *container, double amount, enum wlc_resize_edge edge);
void layout_log(const swayc_t *c, int depth);
void swayc_log(log_importance_t verbosity, swayc_t *cont, const char* format, ...) __attribute__((format(printf,3,4)));
/**
* Get default layout.
*/
enum swayc_layouts default_layout(swayc_t *output);
bool is_auto_layout(enum swayc_layouts layout);
int auto_group_start_index(const swayc_t *container, int index);
int auto_group_end_index(const swayc_t *container, int index);
size_t auto_group_count(const swayc_t *container);
size_t auto_group_index(const swayc_t *container, int index);
bool auto_group_bounds(const swayc_t *container, size_t group_index, int *start, int *end);
#endif

View file

@ -1,36 +0,0 @@
#ifndef _SWAY_OUTPUT_H
#define _SWAY_OUTPUT_H
#include <time.h>
#include <wayland-server.h>
#include <wlr/types/wlr_output.h>
#include "container.h"
#include "focus.h"
struct sway_server;
struct sway_output {
struct wlr_output *wlr_output;
struct wl_listener frame;
struct sway_server *server;
struct timespec last_frame;
};
// Position is absolute coordinates on the edge where the adjacent output
// should be searched for.
swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos);
swayc_t *swayc_opposite_output(enum movement_direction dir, const struct wlc_point *abs_pos);
swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir, const struct wlc_point *abs_pos, bool pick_closest);
// Place absolute coordinates for given container into given wlc_point.
void get_absolute_position(swayc_t *container, struct wlc_point *point);
// Place absolute coordinates for the center point of given container into
// given wlc_point.
void get_absolute_center_position(swayc_t *container, struct wlc_point *point);
// stable sort workspaces on this output
void sort_workspaces(swayc_t *output);
void output_get_scaled_size(wlc_handle handle, struct wlc_size *size);
#endif

View file

@ -1,22 +0,0 @@
#ifndef _SWAY_WORKSPACE_H
#define _SWAY_WORKSPACE_H
#include <wlc/wlc.h>
#include <unistd.h>
#include "list.h"
#include "layout.h"
extern char *prev_workspace_name;
char *workspace_next_name(const char *output_name);
swayc_t *workspace_create(const char*);
swayc_t *workspace_by_name(const char*);
swayc_t *workspace_by_number(const char*);
bool workspace_switch(swayc_t*);
swayc_t *workspace_output_next();
swayc_t *workspace_next();
swayc_t *workspace_output_prev();
swayc_t *workspace_prev();
swayc_t *workspace_for_pid(pid_t pid);
#endif

View file

@ -14,6 +14,7 @@ struct sway_output {
struct timespec last_frame;
struct wl_listener frame;
struct wl_listener output_destroy;
};
#endif

View file

@ -47,8 +47,7 @@ struct sway_server {
struct sway_input_manager *input;
struct wl_listener output_add;
struct wl_listener output_remove;
struct wl_listener new_output;
struct wl_listener output_frame;
struct wlr_xdg_shell_v6 *xdg_shell_v6;
@ -56,6 +55,7 @@ struct sway_server {
struct wlr_xwayland *xwayland;
struct wl_listener xwayland_surface;
struct wl_listener xwayland_ready;
struct wlr_wl_shell *wl_shell;
struct wl_listener wl_shell_surface;
@ -67,8 +67,7 @@ bool server_init(struct sway_server *server);
void server_fini(struct sway_server *server);
void server_run(struct sway_server *server);
void output_add_notify(struct wl_listener *listener, void *data);
void output_remove_notify(struct wl_listener *listener, void *data);
void handle_new_output(struct wl_listener *listener, void *data);
void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data);
void handle_xwayland_surface(struct wl_listener *listener, void *data);

View file

@ -28,6 +28,8 @@ struct sway_xwayland_surface {
struct wl_listener request_resize;
struct wl_listener request_maximize;
struct wl_listener request_configure;
struct wl_listener unmap_notify;
struct wl_listener map_notify;
struct wl_listener destroy;
int pending_width, pending_height;
@ -90,7 +92,27 @@ struct sway_view {
void (*set_position)(struct sway_view *view,
double ox, double oy);
void (*set_activated)(struct sway_view *view, bool activated);
void (*close)(struct sway_view *view);
} iface;
// only used for unmanaged views (shell specific)
struct wl_list unmanaged_view_link; // sway_root::unmanaged views
};
const char *view_get_title(struct sway_view *view);
const char *view_get_app_id(struct sway_view *view);
const char *view_get_class(struct sway_view *view);
const char *view_get_instance(struct sway_view *view);
void view_set_size(struct sway_view *view, int width, int height);
void view_set_position(struct sway_view *view, double ox, double oy);
void view_set_activated(struct sway_view *view, bool activated);
void view_close(struct sway_view *view);
#endif

View file

@ -1,6 +1,20 @@
#ifndef _SWAY_WORKSPACE_H
#define _SWAY_WORKSPACE_H
#include "sway/container.h"
extern char *prev_workspace_name;
char *workspace_next_name(const char *output_name);
swayc_t *workspace_create(const char *name);
bool workspace_switch(swayc_t *workspace);
struct sway_container *workspace_by_number(const char* name);
swayc_t *workspace_by_name(const char*);
struct sway_container *workspace_output_next(swayc_t *current);
struct sway_container *workspace_next(swayc_t *current);
struct sway_container *workspace_output_prev(swayc_t *current);
struct sway_container *workspace_prev(swayc_t *current);
#endif

View file

@ -10,6 +10,7 @@ project(
)
add_project_arguments('-Wno-unused-parameter', language: 'c')
add_project_arguments('-Wno-unused-function', language: 'c')
cc = meson.get_compiler('c')
@ -18,7 +19,7 @@ datadir = get_option('datadir')
sysconfdir = get_option('sysconfdir')
prefix = get_option('prefix')
jsonc = dependency('json-c', version: '>=0.12.1')
jsonc = dependency('json-c', version: '>=0.13')
pcre = dependency('libpcre')
wlroots = dependency('wlroots')
wayland_server = dependency('wayland-server')

View file

@ -8,8 +8,10 @@
#include <json-c/json.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/criteria.h"
#include "sway/security.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "stringop.h"
#include "log.h"
@ -70,7 +72,6 @@ void apply_input_config(struct input_config *input) {
list_add(config->input_configs, input);
}
current_input_config = input;
sway_input_manager_apply_input_config(input_manager, input);
}
@ -87,7 +88,6 @@ void apply_seat_config(struct seat_config *seat) {
list_add(config->seat_configs, seat);
}
current_seat_config = seat;
sway_input_manager_apply_seat_config(input_manager, seat);
}
@ -125,16 +125,41 @@ struct cmd_results *add_color(const char *name, char *buffer, const char *color)
return NULL;
}
/* Keep alphabetized */
/**
* handlers that can run in either config or command context
* Keep alphabetized
*/
static struct cmd_handler handlers[] = {
{ "backend", cmd_backend },
{ "bindcode", cmd_bindcode },
{ "bindsym", cmd_bindsym },
{ "exec", cmd_exec },
{ "exec_always", cmd_exec_always },
{ "exit", cmd_exit },
{ "include", cmd_include },
{ "input", cmd_input },
{ "output", cmd_output },
{ "seat", cmd_seat },
{ "workspace", cmd_workspace },
};
/**
* Commands that can *only* run in the config loading context
* Keep alphabetized
*/
static struct cmd_handler config_handlers[] = {
{ "set", cmd_set },
};
/**
* Commands that can *not* run in the config loading context
* Keep alphabetized
*/
static struct cmd_handler command_handlers[] = {
{ "exit", cmd_exit },
{ "focus", cmd_focus },
{ "kill", cmd_kill },
{ "layout", cmd_layout },
{ "reload", cmd_reload },
};
static int handler_compare(const void *_a, const void *_b) {
@ -172,37 +197,103 @@ static struct cmd_handler seat_handlers[] = {
static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
struct cmd_handler d = { .command=line };
struct cmd_handler *res = NULL;
sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT);
wlr_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT);
bool config_loading = config->reading || !config->active;
if (block == CMD_BLOCK_INPUT) {
res = bsearch(&d, input_handlers,
// input commands can run in either context
return bsearch(&d, input_handlers,
sizeof(input_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
} else if (block == CMD_BLOCK_SEAT) {
res = bsearch(&d, seat_handlers,
// seat commands can run in either context
return bsearch(&d, seat_handlers,
sizeof(seat_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
} else {
res = bsearch(&d, handlers,
sizeof(handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
}
if (!config_loading) {
res = bsearch(&d, command_handlers,
sizeof(command_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
if (res) {
return res;
}
}
if (config->reading) {
res = bsearch(&d, config_handlers,
sizeof(config_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
if (res) {
return res;
}
}
res = bsearch(&d, handlers,
sizeof(handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
return res;
}
struct cmd_results *handle_command(char *_exec) {
struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
// Even though this function will process multiple commands we will only
// return the last error, if any (for now). (Since we have access to an
// error string we could e.g. concatonate all errors there.)
// error string we could e.g. concatenate all errors there.)
struct cmd_results *results = NULL;
char *exec = strdup(_exec);
char *head = exec;
char *cmdlist;
char *cmd;
list_t *containers = NULL;
if (seat == NULL) {
// passing a NULL seat means we just pick the default seat
seat = sway_input_manager_get_default_seat(input_manager);
if (!sway_assert(seat, "could not find a seat to run the command on")) {
return NULL;
}
}
config->handler_context.seat = seat;
head = exec;
do {
// Extract criteria (valid for this command list only).
bool has_criteria = false;
if (*head == '[') {
has_criteria = true;
++head;
char *criteria_string = argsep(&head, "]");
if (head) {
++head;
list_t *tokens = create_list();
char *error;
if ((error = extract_crit_tokens(tokens, criteria_string))) {
wlr_log(L_DEBUG, "criteria string parse error: %s", error);
results = cmd_results_new(CMD_INVALID, criteria_string,
"Can't parse criteria string: %s", error);
free(error);
free(tokens);
goto cleanup;
}
containers = container_for_crit_tokens(tokens);
free(tokens);
} else {
if (!results) {
results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched [");
}
goto cleanup;
}
// Skip leading whitespace
head += strspn(head, whitespace);
}
// Split command list
cmdlist = argsep(&head, ";");
cmdlist += strspn(cmdlist, whitespace);
@ -211,10 +302,10 @@ struct cmd_results *handle_command(char *_exec) {
cmd = argsep(&cmdlist, ",");
cmd += strspn(cmd, whitespace);
if (strcmp(cmd, "") == 0) {
sway_log(L_INFO, "Ignoring empty command.");
wlr_log(L_INFO, "Ignoring empty command.");
continue;
}
sway_log(L_INFO, "Handling command '%s'", cmd);
wlr_log(L_INFO, "Handling command '%s'", cmd);
//TODO better handling of argv
int argc;
char **argv = split_args(cmd, &argc);
@ -235,16 +326,41 @@ struct cmd_results *handle_command(char *_exec) {
free_argv(argc, argv);
goto cleanup;
}
struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status != CMD_SUCCESS) {
free_argv(argc, argv);
if (results) {
free_cmd_results(results);
if (!has_criteria) {
// without criteria, the command acts upon the focused
// container
config->handler_context.current_container =
sway_seat_get_focus_inactive(seat, &root_container);
if (!sway_assert(config->handler_context.current_container,
"could not get focus-inactive for root container")) {
return NULL;
}
struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status != CMD_SUCCESS) {
free_argv(argc, argv);
if (results) {
free_cmd_results(results);
}
results = res;
goto cleanup;
}
free_cmd_results(res);
} else {
for (int i = 0; i < containers->length; ++i) {
config->handler_context.current_container = containers->items[i];
struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status != CMD_SUCCESS) {
free_argv(argc, argv);
if (results) {
free_cmd_results(results);
}
results = res;
goto cleanup;
}
free_cmd_results(res);
}
results = res;
goto cleanup;
}
free_cmd_results(res);
free_argv(argc, argv);
} while(cmdlist);
} while(head);
@ -256,13 +372,13 @@ cleanup:
return results;
}
// this is like handle_command above, except:
// this is like execute_command above, except:
// 1) it ignores empty commands (empty lines)
// 2) it does variable substitution
// 3) it doesn't split commands (because the multiple commands are supposed to
// be chained together)
// 4) handle_command handles all state internally while config_command has some
// state handled outside (notably the block mode, in read_config)
// 4) execute_command handles all state internally while config_command has
// some state handled outside (notably the block mode, in read_config)
struct cmd_results *config_command(char *exec, enum cmd_status block) {
struct cmd_results *results = NULL;
int argc;
@ -272,7 +388,7 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) {
goto cleanup;
}
sway_log(L_INFO, "handling config command '%s'", exec);
wlr_log(L_INFO, "handling config command '%s'", exec);
// Endblock
if (**argv == '}') {
results = cmd_results_new(CMD_BLOCK_END, NULL, NULL);
@ -287,7 +403,7 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) {
int i;
// Var replacement, for all but first argument of set
// TODO commands
for (i = /*handler->handle == cmd_set ? 2 :*/ 1; i < argc; ++i) {
for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
argv[i] = do_var_replacement(argv[i]);
unescape_string(argv[i]);
}
@ -376,7 +492,7 @@ struct cmd_results *config_commands_command(char *exec) {
}
policy->context = context;
sway_log(L_INFO, "Set command policy for %s to %d",
wlr_log(L_INFO, "Set command policy for %s to %d",
policy->command, policy->context);
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
@ -390,7 +506,7 @@ struct cmd_results *cmd_results_new(enum cmd_status status,
const char *input, const char *format, ...) {
struct cmd_results *results = malloc(sizeof(struct cmd_results));
if (!results) {
sway_log(L_ERROR, "Unable to allocate command results");
wlr_log(L_ERROR, "Unable to allocate command results");
return NULL;
}
results->status = status;

View file

@ -1,9 +1,13 @@
#ifdef __linux__
#include <linux/input-event-codes.h>
#elif __FreeBSD__
#include <dev/evdev/input-event-codes.h>
#endif
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-names.h>
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/input_state.h"
#include "list.h"
#include "log.h"
#include "stringop.h"
@ -11,13 +15,67 @@
int binding_order = 0;
void free_sway_binding(struct sway_binding *binding) {
if (!binding) {
return;
}
if (binding->keys) {
free_flat_list(binding->keys);
}
free(binding->command);
free(binding);
}
/**
* Returns true if the bindings have the same key and modifier combinations.
* Note that keyboard layout is not considered, so the bindings might actually
* not be equivalent on some layouts.
*/
bool binding_key_compare(struct sway_binding *binding_a,
struct sway_binding *binding_b) {
if (binding_a->release != binding_b->release) {
return false;
}
if (binding_a->bindcode != binding_b->bindcode) {
return false;
}
if (binding_a->modifiers ^ binding_b->modifiers) {
return false;
}
if (binding_a->keys->length != binding_b->keys->length) {
return false;
}
int keys_len = binding_a->keys->length;
for (int i = 0; i < keys_len; ++i) {
uint32_t key_a = *(uint32_t*)binding_a->keys->items[i];
bool found = false;
for (int j = 0; j < keys_len; ++j) {
uint32_t key_b = *(uint32_t*)binding_b->keys->items[j];
if (key_b == key_a) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
struct cmd_results *cmd_bindsym(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) {
return error;
}
struct sway_binding *binding = malloc(sizeof(struct sway_binding));
struct sway_binding *binding = calloc(1, sizeof(struct sway_binding));
if (!binding) {
return cmd_results_new(CMD_FAILURE, "bindsym",
"Unable to allocate binding");
@ -58,7 +116,7 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
// Check for mouse binding
if (strncasecmp(split->items[i], "button", strlen("button")) == 0 &&
strlen(split->items[i]) == strlen("button0")) {
sym = ((char *)split->items[i])[strlen("button")] - '1' + M_LEFT_CLICK;
sym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT;
}
if (!sym) {
struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym",
@ -67,7 +125,7 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
free_flat_list(split);
return ret;
}
xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t));
xkb_keysym_t *key = calloc(1, sizeof(xkb_keysym_t));
if (!key) {
free_sway_binding(binding);
free_flat_list(split);
@ -78,20 +136,29 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
list_add(binding->keys, key);
}
free_flat_list(split);
struct sway_mode *mode = config->current_mode;
int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding);
if (i > -1) {
sway_log(L_DEBUG, "bindsym - '%s' already exists, overwriting", argv[0]);
struct sway_binding *dup = mode->bindings->items[i];
free_sway_binding(dup);
list_del(mode->bindings, i);
}
binding->order = binding_order++;
list_add(mode->bindings, binding);
list_qsort(mode->bindings, sway_binding_cmp_qsort);
sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command);
list_t *mode_bindings = config->current_mode->keysym_bindings;
// overwrite the binding if it already exists
bool overwritten = false;
for (int i = 0; i < mode_bindings->length; ++i) {
struct sway_binding *config_binding = mode_bindings->items[i];
if (binding_key_compare(binding, config_binding)) {
wlr_log(L_DEBUG, "overwriting old binding with command '%s'",
config_binding->command);
free_sway_binding(config_binding);
mode_bindings->items[i] = binding;
overwritten = true;
}
}
if (!overwritten) {
list_add(mode_bindings, binding);
}
wlr_log(L_DEBUG, "bindsym - Bound %s to command %s",
argv[0], binding->command);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
@ -101,7 +168,7 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) {
return error;
}
struct sway_binding *binding = malloc(sizeof(struct sway_binding));
struct sway_binding *binding = calloc(1, sizeof(struct sway_binding));
if (!binding) {
return cmd_results_new(CMD_FAILURE, "bindsym",
"Unable to allocate binding");
@ -138,33 +205,41 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) {
// parse keycode
xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10);
if (!xkb_keycode_is_legal_ext(keycode)) {
error = cmd_results_new(CMD_INVALID, "bindcode", "Invalid keycode '%s'", (char *)split->items[i]);
error =
cmd_results_new(CMD_INVALID, "bindcode",
"Invalid keycode '%s'", (char *)split->items[i]);
free_sway_binding(binding);
list_free(split);
return error;
}
xkb_keycode_t *key = malloc(sizeof(xkb_keycode_t));
xkb_keycode_t *key = calloc(1, sizeof(xkb_keycode_t));
*key = keycode - 8;
list_add(binding->keys, key);
}
free_flat_list(split);
struct sway_mode *mode = config->current_mode;
int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding);
if (i > -1) {
struct sway_binding *dup = mode->bindings->items[i];
if (dup->bindcode) {
sway_log(L_DEBUG, "bindcode - '%s' already exists, overwriting", argv[0]);
} else {
sway_log(L_DEBUG, "bindcode - '%s' already exists as bindsym, overwriting", argv[0]);
}
free_sway_binding(dup);
list_del(mode->bindings, i);
}
binding->order = binding_order++;
list_add(mode->bindings, binding);
list_qsort(mode->bindings, sway_binding_cmp_qsort);
sway_log(L_DEBUG, "bindcode - Bound %s to command %s", argv[0], binding->command);
list_t *mode_bindings = config->current_mode->keycode_bindings;
// overwrite the binding if it already exists
bool overwritten = false;
for (int i = 0; i < mode_bindings->length; ++i) {
struct sway_binding *config_binding = mode_bindings->items[i];
if (binding_key_compare(binding, config_binding)) {
wlr_log(L_DEBUG, "overwriting old binding with command '%s'",
config_binding->command);
free_sway_binding(config_binding);
mode_bindings->items[i] = binding;
overwritten = true;
}
}
if (!overwritten) {
list_add(mode_bindings, binding);
}
wlr_log(L_DEBUG, "bindcode - Bound %s to command %s",
argv[0], binding->command);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -8,7 +8,7 @@ struct cmd_results *cmd_exec(int argc, char **argv) {
if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL);
if (config->reloading) {
char *args = join_args(argv, argc);
sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
wlr_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
free(args);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -20,7 +20,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
char *tmp = NULL;
if (strcmp((char*)*argv, "--no-startup-id") == 0) {
sway_log(L_INFO, "exec switch '--no-startup-id' not supported, ignored.");
wlr_log(L_INFO, "exec switch '--no-startup-id' not supported, ignored.");
if ((error = checkarg(argc - 1, "exec_always", EXPECTED_MORE_THAN, 0))) {
return error;
}
@ -35,11 +35,11 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
strncpy(cmd, tmp, sizeof(cmd));
cmd[sizeof(cmd) - 1] = 0;
free(tmp);
sway_log(L_DEBUG, "Executing %s", cmd);
wlr_log(L_DEBUG, "Executing %s", cmd);
int fd[2];
if (pipe(fd) != 0) {
sway_log(L_ERROR, "Unable to create pipe for fork");
wlr_log(L_ERROR, "Unable to create pipe for fork");
}
pid_t pid;
@ -75,7 +75,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
// cleanup child process
wait(0);
if (*child > 0) {
sway_log(L_DEBUG, "Child process created with pid %d", *child);
wlr_log(L_DEBUG, "Child process created with pid %d", *child);
// TODO: add PID to active workspace
} else {
free(child);

View file

@ -6,9 +6,6 @@ void sway_terminate(int exit_code);
struct cmd_results *cmd_exit(int argc, char **argv) {
struct cmd_results *error = NULL;
if (config->reading) {
return cmd_results_new(CMD_FAILURE, "exit", "Can't be used in config file.");
}
if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) {
return error;
}

59
sway/commands/focus.c Normal file
View file

@ -0,0 +1,59 @@
#include <strings.h>
#include <wlr/util/log.h>
#include "log.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/view.h"
#include "sway/commands.h"
static bool parse_movement_direction(const char *name, enum movement_direction *out) {
if (strcasecmp(name, "left") == 0) {
*out = MOVE_LEFT;
} else if (strcasecmp(name, "right") == 0) {
*out = MOVE_RIGHT;
} else if (strcasecmp(name, "up") == 0) {
*out = MOVE_UP;
} else if (strcasecmp(name, "down") == 0) {
*out = MOVE_DOWN;
} else if (strcasecmp(name, "parent") == 0) {
*out = MOVE_PARENT;
} else if (strcasecmp(name, "child") == 0) {
*out = MOVE_CHILD;
} else if (strcasecmp(name, "next") == 0) {
*out = MOVE_NEXT;
} else if (strcasecmp(name, "prev") == 0) {
*out = MOVE_PREV;
} else {
return false;
}
return true;
}
struct cmd_results *cmd_focus(int argc, char **argv) {
swayc_t *con = config->handler_context.current_container;
struct sway_seat *seat = config->handler_context.seat;
if (con->type < C_WORKSPACE) {
return cmd_results_new(CMD_FAILURE, "focus",
"Command 'focus' cannot be used above the workspace level");
}
if (argc == 0) {
sway_seat_set_focus(seat, con);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
// TODO mode_toggle
enum movement_direction direction = 0;
if (!parse_movement_direction(argv[0], &direction)) {
return cmd_results_new(CMD_INVALID, "focus",
"Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'");
}
swayc_t *next_focus = get_swayc_in_direction(con, seat, direction);
if (next_focus) {
sway_seat_set_focus(seat, next_focus);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -11,8 +11,12 @@ struct cmd_results *cmd_input(int argc, char **argv) {
}
if (config->reading && strcmp("{", argv[1]) == 0) {
current_input_config = new_input_config(argv[0]);
sway_log(L_DEBUG, "entering input block: %s", current_input_config->identifier);
free_input_config(config->handler_context.input_config);
config->handler_context.input_config = new_input_config(argv[0]);
if (!config->handler_context.input_config) {
return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
}
wlr_log(L_DEBUG, "entering input block: %s", argv[0]);
return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL);
}
@ -20,11 +24,19 @@ struct cmd_results *cmd_input(int argc, char **argv) {
return error;
}
bool has_context = (config->handler_context.input_config != NULL);
if (!has_context) {
// caller did not give a context so create one just for this command
config->handler_context.input_config = new_input_config(argv[0]);
if (!config->handler_context.input_config) {
return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
}
}
int argc_new = argc-2;
char **argv_new = argv+2;
struct cmd_results *res;
current_input_config = new_input_config(argv[0]);
if (strcasecmp("accel_profile", argv[1]) == 0) {
res = input_cmd_accel_profile(argc_new, argv_new);
} else if (strcasecmp("click_method", argv[1]) == 0) {
@ -60,6 +72,12 @@ struct cmd_results *cmd_input(int argc, char **argv) {
} else {
res = cmd_results_new(CMD_INVALID, "input <device>", "Unknown command %s", argv[1]);
}
current_input_config = NULL;
if (!has_context) {
// clean up the context we created earlier
free_input_config(config->handler_context.input_config);
config->handler_context.input_config = NULL;
}
return res;
}

View file

@ -9,6 +9,8 @@ struct cmd_results *input_cmd_accel_profile(int argc, char **argv) {
if ((error = checkarg(argc, "accel_profile", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "accel_profile",
"No input device defined.");

View file

@ -6,12 +6,12 @@
#include "log.h"
struct cmd_results *input_cmd_click_method(int argc, char **argv) {
sway_log(L_DEBUG, "click_method for device: %d %s",
current_input_config==NULL, current_input_config->identifier);
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "click_method",
"No input device defined.");

View file

@ -9,6 +9,8 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE,
"drag_lock", "No input device defined.");

View file

@ -9,6 +9,8 @@ struct cmd_results *input_cmd_dwt(int argc, char **argv) {
if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined.");
}

View file

@ -6,16 +6,18 @@
#include "log.h"
struct cmd_results *input_cmd_events(int argc, char **argv) {
sway_log(L_DEBUG, "events for device: %s",
current_input_config->identifier);
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "events",
"No input device defined.");
}
wlr_log(L_DEBUG, "events for device: %s",
current_input_config->identifier);
struct input_config *new_config =
new_input_config(current_input_config->identifier);

View file

@ -9,6 +9,8 @@ struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "left_handed",
"No input device defined.");

View file

@ -9,6 +9,8 @@ struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "middle_emulation",
"No input device defined.");

View file

@ -9,6 +9,8 @@ struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "natural_scoll",
"No input device defined.");

View file

@ -9,6 +9,8 @@ struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) {
if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE,
"pointer_accel", "No input device defined.");

View file

@ -9,6 +9,8 @@ struct cmd_results *input_cmd_scroll_method(int argc, char **argv) {
if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "scroll_method",
"No input device defined.");

View file

@ -6,11 +6,12 @@
#include "log.h"
struct cmd_results *input_cmd_tap(int argc, char **argv) {
sway_log(L_DEBUG, "tap for device: %s", current_input_config->identifier);
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "tap", "No input device defined.");
}
@ -26,7 +27,7 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) {
"Expected 'tap <enabled|disabled>'");
}
sway_log(L_DEBUG, "apply-tap for device: %s",
wlr_log(L_DEBUG, "apply-tap for device: %s",
current_input_config->identifier);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

View file

@ -5,11 +5,12 @@
#include "log.h"
struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) {
sway_log(L_DEBUG, "xkb layout for device: %s", current_input_config->identifier);
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "xkb_layout", EXPECTED_EQUAL_TO, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "xkb_layout", "No input device defined.");
}
@ -18,7 +19,7 @@ struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) {
new_config->xkb_layout = strdup(argv[0]);
sway_log(L_DEBUG, "apply-xkb_layout for device: %s layout: %s",
wlr_log(L_DEBUG, "apply-xkb_layout for device: %s layout: %s",
current_input_config->identifier, new_config->xkb_layout);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

View file

@ -5,11 +5,12 @@
#include "log.h"
struct cmd_results *input_cmd_xkb_model(int argc, char **argv) {
sway_log(L_DEBUG, "xkb model for device: %s", current_input_config->identifier);
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "xkb_model", EXPECTED_EQUAL_TO, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "xkb_model", "No input device defined.");
}
@ -18,7 +19,7 @@ struct cmd_results *input_cmd_xkb_model(int argc, char **argv) {
new_config->xkb_model = strdup(argv[0]);
sway_log(L_DEBUG, "apply-xkb_model for device: %s model: %s",
wlr_log(L_DEBUG, "apply-xkb_model for device: %s model: %s",
current_input_config->identifier, new_config->xkb_model);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

View file

@ -5,11 +5,12 @@
#include "log.h"
struct cmd_results *input_cmd_xkb_options(int argc, char **argv) {
sway_log(L_DEBUG, "xkb options for device: %s", current_input_config->identifier);
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "xkb_options", EXPECTED_EQUAL_TO, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "xkb_options", "No input device defined.");
}
@ -18,7 +19,7 @@ struct cmd_results *input_cmd_xkb_options(int argc, char **argv) {
new_config->xkb_options = strdup(argv[0]);
sway_log(L_DEBUG, "apply-xkb_options for device: %s options: %s",
wlr_log(L_DEBUG, "apply-xkb_options for device: %s options: %s",
current_input_config->identifier, new_config->xkb_options);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

View file

@ -5,11 +5,12 @@
#include "log.h"
struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) {
sway_log(L_DEBUG, "xkb rules for device: %s", current_input_config->identifier);
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "xkb_rules", EXPECTED_EQUAL_TO, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "xkb_rules", "No input device defined.");
}
@ -18,7 +19,7 @@ struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) {
new_config->xkb_rules = strdup(argv[0]);
sway_log(L_DEBUG, "apply-xkb_rules for device: %s rules: %s",
wlr_log(L_DEBUG, "apply-xkb_rules for device: %s rules: %s",
current_input_config->identifier, new_config->xkb_rules);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

View file

@ -5,11 +5,12 @@
#include "log.h"
struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) {
sway_log(L_DEBUG, "xkb variant for device: %s", current_input_config->identifier);
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "xkb_variant", EXPECTED_EQUAL_TO, 1))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "xkb_variant", "No input device defined.");
}
@ -18,7 +19,7 @@ struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) {
new_config->xkb_variant = strdup(argv[0]);
sway_log(L_DEBUG, "apply-xkb_variant for device: %s variant: %s",
wlr_log(L_DEBUG, "apply-xkb_variant for device: %s variant: %s",
current_input_config->identifier, new_config->xkb_variant);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

24
sway/commands/kill.c Normal file
View file

@ -0,0 +1,24 @@
#include <wlr/util/log.h>
#include "log.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/view.h"
#include "sway/commands.h"
struct cmd_results *cmd_kill(int argc, char **argv) {
enum swayc_types type = config->handler_context.current_container->type;
if (type != C_VIEW && type != C_CONTAINER) {
return cmd_results_new(CMD_INVALID, NULL,
"Can only kill views and containers with this command");
}
// TODO close arbitrary containers without a view
struct sway_view *view =
config->handler_context.current_container->sway_view;
if (view) {
view_close(view);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

56
sway/commands/layout.c Normal file
View file

@ -0,0 +1,56 @@
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "sway/container.h"
#include "sway/layout.h"
#include "log.h"
struct cmd_results *cmd_layout(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) {
return error;
}
swayc_t *parent = config->handler_context.current_container;
// TODO: floating
/*
if (parent->is_floating) {
return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows");
}
*/
while (parent->type == C_VIEW) {
parent = parent->parent;
}
// TODO: stacks and tabs
if (strcasecmp(argv[0], "default") == 0) {
swayc_change_layout(parent, parent->prev_layout);
if (parent->layout == L_NONE) {
swayc_t *output = swayc_parent_by_type(parent, C_OUTPUT);
swayc_change_layout(parent, default_layout(output));
}
} else {
if (parent->layout != L_TABBED && parent->layout != L_STACKED) {
parent->prev_layout = parent->layout;
}
if (strcasecmp(argv[0], "splith") == 0) {
swayc_change_layout(parent, L_HORIZ);
} else if (strcasecmp(argv[0], "splitv") == 0) {
swayc_change_layout(parent, L_VERT);
} else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE
|| parent->workspace_layout == L_HORIZ)) {
swayc_change_layout(parent, L_VERT);
} else {
swayc_change_layout(parent, L_HORIZ);
}
}
}
arrange_windows(parent, parent->width, parent->height);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -203,12 +203,12 @@ static struct cmd_results *cmd_output_background(struct output_config *output,
if (src) {
sprintf(src, "%s/%s", conf_path, p.we_wordv[0]);
} else {
sway_log(L_ERROR,
wlr_log(L_ERROR,
"Unable to allocate background source");
}
free(conf);
} else {
sway_log(L_ERROR, "Unable to allocate background source");
wlr_log(L_ERROR, "Unable to allocate background source");
}
}
if (!src || access(src, F_OK) == -1) {
@ -231,14 +231,14 @@ static struct cmd_results *cmd_output_background(struct output_config *output,
}
struct cmd_results *cmd_output(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) {
struct cmd_results *error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1);
if (error != NULL) {
return error;
}
struct output_config *output = new_output_config(argv[0]);
if (!output) {
sway_log(L_ERROR, "Failed to allocate output config");
wlr_log(L_ERROR, "Failed to allocate output config");
return NULL;
}
@ -275,37 +275,41 @@ struct cmd_results *cmd_output(int argc, char **argv) {
int i = list_seq_find(config->output_configs, output_name_cmp, output->name);
if (i >= 0) {
// merge existing config
struct output_config *oc = config->output_configs->items[i];
merge_output_config(oc, output);
// Merge existing config
struct output_config *current = config->output_configs->items[i];
merge_output_config(current, output);
free_output_config(output);
output = oc;
output = current;
} else {
list_add(config->output_configs, output);
}
sway_log(L_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
wlr_log(L_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
"position %d,%d scale %f transform %d) (bg %s %s)",
output->name, output->enabled, output->width, output->height,
output->refresh_rate, output->x, output->y, output->scale,
output->transform, output->background, output->background_option);
if (output->name) {
// Try to find the output container and apply configuration now. If
// this is during startup then there will be no container and config
// will be applied during normal "new output" event from wlroots.
swayc_t *cont = NULL;
for (int i = 0; i < root_container.children->length; ++i) {
cont = root_container.children->items[i];
if (cont->name && ((strcmp(cont->name, output->name) == 0) ||
(strcmp(output->name, "*") == 0))) {
apply_output_config(output, cont);
// Try to find the output container and apply configuration now. If
// this is during startup then there will be no container and config
// will be applied during normal "new output" event from wlroots.
char identifier[128];
bool all = strcmp(output->name, "*") == 0;
for (int i = 0; i < root_container.children->length; ++i) {
swayc_t *cont = root_container.children->items[i];
if (cont->type != C_OUTPUT) {
continue;
}
if (strcmp(output->name, "*") != 0) {
// Stop looking if the output config isn't applicable to all
// outputs
break;
}
output_get_identifier(identifier, sizeof(identifier), cont->sway_output);
if (all || strcmp(cont->name, output->name) == 0 ||
strcmp(identifier, output->name) == 0) {
apply_output_config(output, cont);
if (!all) {
// Stop looking if the output config isn't applicable to all
// outputs
break;
}
}
}

View file

@ -4,7 +4,6 @@
struct cmd_results *cmd_reload(int argc, char **argv) {
struct cmd_results *error = NULL;
if (config->reading) return cmd_results_new(CMD_FAILURE, "reload", "Can't be used in config file.");
if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
return error;
}
@ -12,7 +11,7 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
}
load_swaybars();
/* load_swaybars(); -- for when it's implemented */
arrange_windows(&root_container, -1, -1);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

View file

@ -11,8 +11,12 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
}
if (config->reading && strcmp("{", argv[1]) == 0) {
current_seat_config = new_seat_config(argv[0]);
sway_log(L_DEBUG, "entering seat block: %s", current_seat_config->name);
free_seat_config(config->handler_context.seat_config);
config->handler_context.seat_config = new_seat_config(argv[0]);
if (!config->handler_context.seat_config) {
return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
}
wlr_log(L_DEBUG, "entering seat block: %s", argv[0]);
return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL);
}
@ -20,11 +24,18 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
return error;
}
bool has_context = (config->handler_context.seat_config != NULL);
if (!has_context) {
config->handler_context.seat_config = new_seat_config(argv[0]);
if (!config->handler_context.seat_config) {
return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
}
}
int argc_new = argc-2;
char **argv_new = argv+2;
struct cmd_results *res;
current_seat_config = new_seat_config(argv[0]);
if (strcasecmp("attach", argv[1]) == 0) {
res = seat_cmd_attach(argc_new, argv_new);
} else if (strcasecmp("fallback", argv[1]) == 0) {
@ -32,6 +43,12 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
} else {
res = cmd_results_new(CMD_INVALID, "seat <name>", "Unknown command %s", argv[1]);
}
current_seat_config = NULL;
if (!has_context) {
// clean up the context we created earlier
free_seat_config(config->handler_context.seat_config);
config->handler_context.seat_config = NULL;
}
return res;
}

View file

@ -12,6 +12,8 @@ struct cmd_results *seat_cmd_attach(int argc, char **argv) {
if ((error = checkarg(argc, "attach", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct seat_config *current_seat_config =
config->handler_context.seat_config;
if (!current_seat_config) {
return cmd_results_new(CMD_FAILURE, "attach", "No seat defined");
}

View file

@ -9,6 +9,8 @@ struct cmd_results *seat_cmd_fallback(int argc, char **argv) {
if ((error = checkarg(argc, "fallback", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct seat_config *current_seat_config =
config->handler_context.seat_config;
if (!current_seat_config) {
return cmd_results_new(CMD_FAILURE, "fallback", "No seat defined");
}
@ -20,6 +22,7 @@ struct cmd_results *seat_cmd_fallback(int argc, char **argv) {
} else if (strcasecmp(argv[0], "false") == 0) {
new_config->fallback = 0;
} else {
free_seat_config(new_config);
return cmd_results_new(CMD_INVALID, "fallback",
"Expected 'fallback <true|false>'");
}

View file

@ -5,6 +5,7 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "list.h"
#include "log.h"
#include "stringop.h"
// sort in order of longest->shortest
@ -14,16 +15,24 @@ static int compare_set_qsort(const void *_l, const void *_r) {
return strlen(r->name) - strlen(l->name);
}
void free_sway_variable(struct sway_variable *var) {
if (!var) {
return;
}
free(var->name);
free(var->value);
free(var);
}
struct cmd_results *cmd_set(int argc, char **argv) {
char *tmp;
struct cmd_results *error = NULL;
if (!config->reading) return cmd_results_new(CMD_FAILURE, "set", "Can only be used in config file.");
if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) {
return error;
}
if (argv[0][0] != '$') {
sway_log(L_INFO, "Warning: variable '%s' doesn't start with $", argv[0]);
wlr_log(L_INFO, "Warning: variable '%s' doesn't start with $", argv[0]);
size_t size = snprintf(NULL, 0, "$%s", argv[0]);
tmp = malloc(size + 1);

View file

@ -3,7 +3,7 @@
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/input_state.h"
#include "sway/input/seat.h"
#include "sway/workspace.h"
#include "list.h"
#include "log.h"
@ -17,6 +17,17 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
int output_location = -1;
swayc_t *current_container = config->handler_context.current_container;
swayc_t *old_workspace = NULL, *old_output = NULL;
if (current_container) {
if (current_container->type == C_WORKSPACE) {
old_workspace = current_container;
} else {
old_workspace = swayc_parent_by_type(current_container, C_WORKSPACE);
}
old_output = swayc_parent_by_type(current_container, C_OUTPUT);
}
for (int i = 0; i < argc; ++i) {
if (strcasecmp(argv[i], "output") == 0) {
output_location = i;
@ -40,7 +51,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
free(old); // workspaces can only be assigned to a single output
list_del(config->workspace_outputs, i);
}
sway_log(L_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output);
wlr_log(L_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output);
list_add(config->workspace_outputs, wso);
} else {
if (config->reading || !config->active) {
@ -54,20 +65,21 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
free(name);
}
} else if (strcasecmp(argv[0], "next") == 0) {
ws = workspace_next();
ws = workspace_next(old_workspace);
} else if (strcasecmp(argv[0], "prev") == 0) {
ws = workspace_prev();
ws = workspace_prev(old_workspace);
} else if (strcasecmp(argv[0], "next_on_output") == 0) {
ws = workspace_output_next();
ws = workspace_output_next(old_output);
} else if (strcasecmp(argv[0], "prev_on_output") == 0) {
ws = workspace_output_prev();
ws = workspace_output_prev(old_output);
} else if (strcasecmp(argv[0], "back_and_forth") == 0) {
// if auto_back_and_forth is enabled, workspace_switch will swap
// the workspaces. If we created prev_workspace here, workspace_switch
// would put us back on original workspace.
if (config->auto_back_and_forth) {
ws = swayc_active_workspace();
} else if (prev_workspace_name && !(ws = workspace_by_name(prev_workspace_name))) {
ws = old_workspace;
} else if (prev_workspace_name
&& !(ws = workspace_by_name(prev_workspace_name))) {
ws = workspace_create(prev_workspace_name);
}
} else {
@ -77,15 +89,13 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
}
free(name);
}
swayc_t *old_output = swayc_active_output();
workspace_switch(ws);
swayc_t *new_output = swayc_active_output();
current_container =
sway_seat_get_focus(config->handler_context.seat);
swayc_t *new_output = swayc_parent_by_type(current_container, C_OUTPUT);
if (config->mouse_warping && old_output != new_output) {
swayc_t *focused = get_focused_view(ws);
if (focused && focused->type == C_VIEW) {
center_pointer_on(focused);
}
// TODO: Warp mouse
}
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

View file

@ -21,6 +21,7 @@
#endif
#include <wlr/types/wlr_output.h>
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/layout.h"
@ -31,8 +32,99 @@
struct sway_config *config = NULL;
static void free_mode(struct sway_mode *mode) {
int i;
if (!mode) {
return;
}
free(mode->name);
if (mode->keysym_bindings) {
for (i = 0; i < mode->keysym_bindings->length; i++) {
free_sway_binding(mode->keysym_bindings->items[i]);
}
list_free(mode->keysym_bindings);
}
if (mode->keycode_bindings) {
for (i = 0; i < mode->keycode_bindings->length; i++) {
free_sway_binding(mode->keycode_bindings->items[i]);
}
list_free(mode->keycode_bindings);
}
free(mode);
}
void free_config(struct sway_config *config) {
// TODO
config_clear_handler_context(config);
int i;
if (!config) {
return;
}
// TODO: handle all currently unhandled lists as we add implementations
if (config->symbols) {
for (i = 0; i < config->symbols->length; i++) {
free_sway_variable(config->symbols->items[i]);
}
list_free(config->symbols);
}
if (config->modes) {
for (i = 0; i < config->modes->length; i++) {
free_mode(config->modes->items[i]);
}
list_free(config->modes);
}
list_free(config->bars);
list_free(config->cmd_queue);
list_free(config->workspace_outputs);
list_free(config->pid_workspaces);
list_free(config->output_configs);
if (config->input_configs) {
for (i = 0; i < config->input_configs->length; i++) {
free_input_config(config->input_configs->items[i]);
}
list_free(config->input_configs);
}
if (config->seat_configs) {
for (i = 0; i < config->seat_configs->length; i++) {
free_seat_config(config->seat_configs->items[i]);
}
list_free(config->seat_configs);
}
list_free(config->criteria);
list_free(config->no_focus);
list_free(config->active_bar_modifiers);
list_free(config->config_chain);
list_free(config->command_policies);
list_free(config->feature_policies);
list_free(config->ipc_policies);
free(config->current_bar);
free(config->floating_scroll_up_cmd);
free(config->floating_scroll_down_cmd);
free(config->floating_scroll_left_cmd);
free(config->floating_scroll_right_cmd);
free(config->font);
free((char *)config->current_config);
free(config);
}
static void destroy_removed_seats(struct sway_config *old_config,
struct sway_config *new_config) {
struct seat_config *seat_config;
struct sway_seat *seat;
int i;
for (i = 0; i < old_config->seat_configs->length; i++) {
seat_config = old_config->seat_configs->items[i];
/* 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(input_manager,
seat_config->name);
sway_seat_destroy(seat);
}
}
}
static void config_defaults(struct sway_config *config) {
@ -53,7 +145,8 @@ static void config_defaults(struct sway_config *config) {
goto cleanup;
if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup;
strcpy(config->current_mode->name, "default");
if (!(config->current_mode->bindings = create_list())) goto cleanup;
if (!(config->current_mode->keysym_bindings = create_list())) goto cleanup;
if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup;
list_add(config->modes, config->current_mode);
config->floating_mod = 0;
@ -164,12 +257,12 @@ static char *get_config_path(void) {
char *home = getenv("HOME");
char *config_home = malloc(strlen(home) + strlen("/.config") + 1);
if (!config_home) {
sway_log(L_ERROR, "Unable to allocate $HOME/.config");
wlr_log(L_ERROR, "Unable to allocate $HOME/.config");
} else {
strcpy(config_home, home);
strcat(config_home, "/.config");
setenv("XDG_CONFIG_HOME", config_home, 1);
sway_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
wlr_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
free(config_home);
}
}
@ -185,6 +278,7 @@ static char *get_config_path(void) {
if (file_exists(path)) {
return path;
}
free(path);
}
}
@ -194,7 +288,7 @@ static char *get_config_path(void) {
const char *current_config_path;
static bool load_config(const char *path, struct sway_config *config) {
sway_log(L_INFO, "Loading config from %s", path);
wlr_log(L_INFO, "Loading config from %s", path);
current_config_path = path;
struct stat sb;
@ -203,13 +297,13 @@ static bool load_config(const char *path, struct sway_config *config) {
}
if (path == NULL) {
sway_log(L_ERROR, "Unable to find a config file!");
wlr_log(L_ERROR, "Unable to find a config file!");
return false;
}
FILE *f = fopen(path, "r");
if (!f) {
sway_log(L_ERROR, "Unable to open %s for reading", path);
wlr_log(L_ERROR, "Unable to open %s for reading", path);
return false;
}
@ -217,17 +311,13 @@ static bool load_config(const char *path, struct sway_config *config) {
fclose(f);
if (!config_load_success) {
sway_log(L_ERROR, "Error(s) loading config!");
wlr_log(L_ERROR, "Error(s) loading config!");
}
current_config_path = NULL;
return true;
}
static int qstrcmp(const void* a, const void* b) {
return strcmp(*((char**) a), *((char**) b));
}
bool load_main_config(const char *file, bool is_active) {
char *path;
if (file != NULL) {
@ -244,7 +334,7 @@ bool load_main_config(const char *file, bool is_active) {
config_defaults(config);
if (is_active) {
sway_log(L_DEBUG, "Performing configuration file reload");
wlr_log(L_DEBUG, "Performing configuration file reload");
config->reloading = true;
config->active = true;
}
@ -255,10 +345,12 @@ bool load_main_config(const char *file, bool is_active) {
config->reading = true;
// Read security configs
// TODO: Security
bool success = true;
/*
DIR *dir = opendir(SYSCONFDIR "/sway/security.d");
if (!dir) {
sway_log(L_ERROR,
wlr_log(L_ERROR,
"%s does not exist, sway will have no security configuration"
" and will probably be broken", SYSCONFDIR "/sway/security.d");
} else {
@ -287,7 +379,7 @@ bool load_main_config(const char *file, bool is_active) {
if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 ||
(((s.st_mode & 0777) != 0644) &&
(s.st_mode & 0777) != 0444)) {
sway_log(L_ERROR,
wlr_log(L_ERROR,
"Refusing to load %s - it must be owned by root "
"and mode 644 or 444", _path);
success = false;
@ -298,6 +390,7 @@ bool load_main_config(const char *file, bool is_active) {
free_flat_list(secconfigs);
}
*/
success = success && load_config(path, config);
@ -306,6 +399,7 @@ bool load_main_config(const char *file, bool is_active) {
}
if (old_config) {
destroy_removed_seats(old_config, config);
free_config(old_config);
}
config->reading = false;
@ -329,7 +423,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
len = len + strlen(parent_dir) + 2;
full_path = malloc(len * sizeof(char));
if (!full_path) {
sway_log(L_ERROR,
wlr_log(L_ERROR,
"Unable to allocate full path to included config");
return false;
}
@ -340,7 +434,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
free(full_path);
if (real_path == NULL) {
sway_log(L_DEBUG, "%s not found.", path);
wlr_log(L_DEBUG, "%s not found.", path);
return false;
}
@ -349,7 +443,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
for (j = 0; j < config->config_chain->length; ++j) {
char *old_path = config->config_chain->items[j];
if (strcmp(real_path, old_path) == 0) {
sway_log(L_DEBUG,
wlr_log(L_DEBUG,
"%s already included once, won't be included again.",
real_path);
free(real_path);
@ -403,7 +497,7 @@ bool load_include_configs(const char *path, struct sway_config *config) {
// restore wd
if (chdir(wd) < 0) {
free(wd);
sway_log(L_ERROR, "failed to restore working directory");
wlr_log(L_ERROR, "failed to restore working directory");
return false;
}
@ -411,6 +505,12 @@ bool load_include_configs(const char *path, struct sway_config *config) {
return true;
}
void config_clear_handler_context(struct sway_config *config) {
free_input_config(config->handler_context.input_config);
free_seat_config(config->handler_context.seat_config);
memset(&config->handler_context, 0, sizeof(config->handler_context));
}
bool read_config(FILE *file, struct sway_config *config) {
bool success = true;
@ -439,13 +539,13 @@ bool read_config(FILE *file, struct sway_config *config) {
switch(res->status) {
case CMD_FAILURE:
case CMD_INVALID:
sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number,
wlr_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number,
line, res->error, config->current_config);
success = false;
break;
case CMD_DEFER:
sway_log(L_DEBUG, "Defferring command `%s'", line);
wlr_log(L_DEBUG, "Deferring command `%s'", line);
list_add(config->cmd_queue, strdup(line));
break;
@ -453,7 +553,7 @@ bool read_config(FILE *file, struct sway_config *config) {
if (block == CMD_BLOCK_END) {
block = CMD_BLOCK_MODE;
} else {
sway_log(L_ERROR, "Invalid block '%s'", line);
wlr_log(L_ERROR, "Invalid block '%s'", line);
}
break;
@ -461,7 +561,7 @@ bool read_config(FILE *file, struct sway_config *config) {
if (block == CMD_BLOCK_END) {
block = CMD_BLOCK_INPUT;
} else {
sway_log(L_ERROR, "Invalid block '%s'", line);
wlr_log(L_ERROR, "Invalid block '%s'", line);
}
break;
@ -469,7 +569,7 @@ bool read_config(FILE *file, struct sway_config *config) {
if (block == CMD_BLOCK_END) {
block = CMD_BLOCK_SEAT;
} else {
sway_log(L_ERROR, "Invalid block '%s'", line);
wlr_log(L_ERROR, "Invalid block '%s'", line);
}
break;
@ -477,7 +577,7 @@ bool read_config(FILE *file, struct sway_config *config) {
if (block == CMD_BLOCK_END) {
block = CMD_BLOCK_BAR;
} else {
sway_log(L_ERROR, "Invalid block '%s'", line);
wlr_log(L_ERROR, "Invalid block '%s'", line);
}
break;
@ -485,7 +585,7 @@ bool read_config(FILE *file, struct sway_config *config) {
if (block == CMD_BLOCK_BAR) {
block = CMD_BLOCK_BAR_COLORS;
} else {
sway_log(L_ERROR, "Invalid block '%s'", line);
wlr_log(L_ERROR, "Invalid block '%s'", line);
}
break;
@ -493,7 +593,7 @@ bool read_config(FILE *file, struct sway_config *config) {
if (block == CMD_BLOCK_END) {
block = CMD_BLOCK_COMMANDS;
} else {
sway_log(L_ERROR, "Invalid block '%s'", line);
wlr_log(L_ERROR, "Invalid block '%s'", line);
}
break;
@ -501,7 +601,7 @@ bool read_config(FILE *file, struct sway_config *config) {
if (block == CMD_BLOCK_END) {
block = CMD_BLOCK_IPC;
} else {
sway_log(L_ERROR, "Invalid block '%s'", line);
wlr_log(L_ERROR, "Invalid block '%s'", line);
}
break;
@ -509,62 +609,61 @@ bool read_config(FILE *file, struct sway_config *config) {
if (block == CMD_BLOCK_IPC) {
block = CMD_BLOCK_IPC_EVENTS;
} else {
sway_log(L_ERROR, "Invalid block '%s'", line);
wlr_log(L_ERROR, "Invalid block '%s'", line);
}
break;
case CMD_BLOCK_END:
switch(block) {
case CMD_BLOCK_MODE:
sway_log(L_DEBUG, "End of mode block");
wlr_log(L_DEBUG, "End of mode block");
config->current_mode = config->modes->items[0];
block = CMD_BLOCK_END;
break;
case CMD_BLOCK_INPUT:
sway_log(L_DEBUG, "End of input block");
current_input_config = NULL;
wlr_log(L_DEBUG, "End of input block");
block = CMD_BLOCK_END;
break;
case CMD_BLOCK_SEAT:
sway_log(L_DEBUG, "End of seat block");
current_seat_config = NULL;
wlr_log(L_DEBUG, "End of seat block");
block = CMD_BLOCK_END;
break;
case CMD_BLOCK_BAR:
sway_log(L_DEBUG, "End of bar block");
wlr_log(L_DEBUG, "End of bar block");
config->current_bar = NULL;
block = CMD_BLOCK_END;
break;
case CMD_BLOCK_BAR_COLORS:
sway_log(L_DEBUG, "End of bar colors block");
wlr_log(L_DEBUG, "End of bar colors block");
block = CMD_BLOCK_BAR;
break;
case CMD_BLOCK_COMMANDS:
sway_log(L_DEBUG, "End of commands block");
wlr_log(L_DEBUG, "End of commands block");
block = CMD_BLOCK_END;
break;
case CMD_BLOCK_IPC:
sway_log(L_DEBUG, "End of IPC block");
wlr_log(L_DEBUG, "End of IPC block");
block = CMD_BLOCK_END;
break;
case CMD_BLOCK_IPC_EVENTS:
sway_log(L_DEBUG, "End of IPC events block");
wlr_log(L_DEBUG, "End of IPC events block");
block = CMD_BLOCK_IPC;
break;
case CMD_BLOCK_END:
sway_log(L_ERROR, "Unmatched }");
wlr_log(L_ERROR, "Unmatched }");
break;
default:;
}
config_clear_handler_context(config);
default:;
}
free(line);
@ -593,7 +692,7 @@ char *do_var_replacement(char *str) {
int vvlen = strlen(var->value);
char *newstr = malloc(strlen(str) - vnlen + vvlen + 1);
if (!newstr) {
sway_log(L_ERROR,
wlr_log(L_ERROR,
"Unable to allocate replacement "
"during variable expansion");
break;
@ -617,3 +716,11 @@ char *do_var_replacement(char *str) {
}
return str;
}
// the naming is intentional (albeit long): a workspace_output_cmp function
// would compare two structs in full, while this method only compares the
// workspace.
int workspace_output_cmp_workspace(const void *a, const void *b) {
const struct workspace_output *wsa = a, *wsb = b;
return lenient_strcmp(wsa->workspace, wsb->workspace);
}

View file

@ -8,13 +8,13 @@
struct input_config *new_input_config(const char* identifier) {
struct input_config *input = calloc(1, sizeof(struct input_config));
if (!input) {
sway_log(L_DEBUG, "Unable to allocate input config");
wlr_log(L_DEBUG, "Unable to allocate input config");
return NULL;
}
sway_log(L_DEBUG, "new_input_config(%s)", identifier);
wlr_log(L_DEBUG, "new_input_config(%s)", identifier);
if (!(input->identifier = strdup(identifier))) {
free(input);
sway_log(L_DEBUG, "Unable to allocate input config");
wlr_log(L_DEBUG, "Unable to allocate input config");
return NULL;
}
@ -90,6 +90,16 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
}
}
struct input_config *copy_input_config(struct input_config *ic) {
struct input_config *copy = calloc(1, sizeof(struct input_config));
if (copy == NULL) {
wlr_log(L_ERROR, "could not allocate input config");
return NULL;
}
merge_input_config(copy, ic);
return copy;
}
void free_input_config(struct input_config *ic) {
if (!ic) {
return;

View file

@ -1,4 +1,5 @@
#define _XOPEN_SOURCE 700
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <wlr/types/wlr_output.h>
@ -14,6 +15,13 @@ int output_name_cmp(const void *item, const void *data) {
return strcmp(output->name, name);
}
void output_get_identifier(char *identifier, size_t len,
struct sway_output *output) {
struct wlr_output *wlr_output = output->wlr_output;
snprintf(identifier, len, "%s %s %s", wlr_output->make, wlr_output->model,
wlr_output->serial);
}
struct output_config *new_output_config(const char *name) {
struct output_config *oc = calloc(1, sizeof(struct output_config));
if (oc == NULL) {
@ -76,7 +84,7 @@ static void set_mode(struct wlr_output *output, int width, int height,
float refresh_rate) {
int mhz = (int)(refresh_rate * 1000);
if (wl_list_empty(&output->modes)) {
sway_log(L_DEBUG, "Assigning custom mode to %s", output->name);
wlr_log(L_DEBUG, "Assigning custom mode to %s", output->name);
wlr_output_set_custom_mode(output, width, height, mhz);
return;
}
@ -92,9 +100,9 @@ static void set_mode(struct wlr_output *output, int width, int height,
}
}
if (!best) {
sway_log(L_ERROR, "Configured mode for %s not available", output->name);
wlr_log(L_ERROR, "Configured mode for %s not available", output->name);
} else {
sway_log(L_DEBUG, "Assigning configured mode to %s", output->name);
wlr_log(L_DEBUG, "Assigning configured mode to %s", output->name);
wlr_output_set_mode(output, best);
}
}
@ -111,22 +119,22 @@ void apply_output_config(struct output_config *oc, swayc_t *output) {
}
if (oc && oc->width > 0 && oc->height > 0) {
sway_log(L_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width,
wlr_log(L_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width,
oc->height, oc->refresh_rate);
set_mode(wlr_output, oc->width, oc->height, oc->refresh_rate);
}
if (oc && oc->scale > 0) {
sway_log(L_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
wlr_log(L_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
wlr_output_set_scale(wlr_output, oc->scale);
}
if (oc && oc->transform >= 0) {
sway_log(L_DEBUG, "Set %s transform to %d", oc->name, oc->transform);
wlr_log(L_DEBUG, "Set %s transform to %d", oc->name, oc->transform);
wlr_output_set_transform(wlr_output, oc->transform);
}
// Find position for it
if (oc && (oc->x != -1 || oc->y != -1)) {
sway_log(L_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y);
wlr_log(L_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y);
wlr_output_layout_add(root_container.sway_root->output_layout,
wlr_output, oc->x, oc->y);
} else {
@ -157,7 +165,7 @@ void apply_output_config(struct output_config *oc, swayc_t *output) {
terminate_swaybg(output->bg_pid);
}
sway_log(L_DEBUG, "Setting background for output %d to %s", output_i, oc->background);
wlr_log(L_DEBUG, "Setting background for output %d to %s", output_i, oc->background);
size_t bufsize = 12;
char output_id[bufsize];

View file

@ -7,11 +7,11 @@
struct seat_config *new_seat_config(const char* name) {
struct seat_config *seat = calloc(1, sizeof(struct seat_config));
if (!seat) {
sway_log(L_DEBUG, "Unable to allocate seat config");
wlr_log(L_DEBUG, "Unable to allocate seat config");
return NULL;
}
sway_log(L_DEBUG, "new_seat_config(%s)", name);
wlr_log(L_DEBUG, "new_seat_config(%s)", name);
seat->name = strdup(name);
if (!sway_assert(seat->name, "could not allocate name for seat")) {
free(seat);
@ -34,7 +34,7 @@ struct seat_attachment_config *seat_attachment_config_new() {
struct seat_attachment_config *attachment =
calloc(1, sizeof(struct seat_attachment_config));
if (!attachment) {
sway_log(L_DEBUG, "cannot allocate attachment config");
wlr_log(L_DEBUG, "cannot allocate attachment config");
return NULL;
}
return attachment;
@ -99,6 +99,17 @@ void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
}
}
struct seat_config *copy_seat_config(struct seat_config *seat) {
struct seat_config *copy = new_seat_config(seat->name);
if (copy == NULL) {
return NULL;
}
merge_seat_config(copy, seat);
return copy;
}
void free_seat_config(struct seat_config *seat) {
if (!seat) {
return;

View file

@ -6,11 +6,13 @@
#include "sway/criteria.h"
#include "sway/container.h"
#include "sway/config.h"
#include "sway/view.h"
#include "stringop.h"
#include "list.h"
#include "log.h"
enum criteria_type { // *must* keep in sync with criteria_strings[]
CRIT_APP_ID,
CRIT_CLASS,
CRIT_CON_ID,
CRIT_CON_MARK,
@ -27,6 +29,7 @@ enum criteria_type { // *must* keep in sync with criteria_strings[]
};
static const char * const criteria_strings[CRIT_LAST] = {
[CRIT_APP_ID] = "app_id",
[CRIT_CLASS] = "class",
[CRIT_CON_ID] = "con_id",
[CRIT_CON_MARK] = "con_mark",
@ -100,8 +103,9 @@ static int countchr(char *str, char c) {
// of buf.
//
// Returns error string or NULL if successful.
static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str) {
sway_log(L_DEBUG, "Parsing criteria: '%s'", criteria_str);
static char *crit_tokens(int *argc, char ***buf,
const char * const criteria_str) {
wlr_log(L_DEBUG, "Parsing criteria: '%s'", criteria_str);
char *base = criteria_from(criteria_str);
char *head = base;
char *namep = head; // start of criteria name
@ -247,13 +251,13 @@ char *extract_crit_tokens(list_t *tokens, const char * const criteria) {
free_crit_token(token);
goto ect_cleanup;
} else if (token->type == CRIT_URGENT || crit_is_focused(value)) {
sway_log(L_DEBUG, "%s -> \"%s\"", name, value);
wlr_log(L_DEBUG, "%s -> \"%s\"", name, value);
list_add(tokens, token);
} else if((error = generate_regex(&token->regex, value))) {
free_crit_token(token);
goto ect_cleanup;
} else {
sway_log(L_DEBUG, "%s -> /%s/", name, value);
wlr_log(L_DEBUG, "%s -> /%s/", name, value);
list_add(tokens, token);
}
}
@ -277,94 +281,85 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
struct crit_token *crit = tokens->items[i];
switch (crit->type) {
case CRIT_CLASS:
if (!cont->class) {
// ignore
} else if (crit_is_focused(crit->raw)) {
swayc_t *focused = get_focused_view(&root_container);
if (focused->class && strcmp(cont->class, focused->class) == 0) {
{
const char *class = view_get_class(cont->sway_view);
if (!class) {
break;
}
if (crit->regex && regex_cmp(class, crit->regex) == 0) {
matches++;
}
} else if (crit->regex && regex_cmp(cont->class, crit->regex) == 0) {
matches++;
break;
}
break;
case CRIT_CON_ID: {
char *endptr;
size_t crit_id = strtoul(crit->raw, &endptr, 10);
case CRIT_CON_ID:
{
char *endptr;
size_t crit_id = strtoul(crit->raw, &endptr, 10);
if (*endptr == 0 && cont->id == crit_id) {
++matches;
}
break;
}
case CRIT_CON_MARK:
if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) {
// Make sure it isn't matching the NUL string
if ((strcmp(crit->raw, "") == 0) == (list_seq_find(cont->marks, (int (*)(const void *, const void *))strcmp, "") != -1)) {
if (*endptr == 0 && cont->id == crit_id) {
++matches;
}
break;
}
case CRIT_CON_MARK:
// TODO
break;
case CRIT_FLOATING:
if (cont->is_floating) {
matches++;
}
// TODO
break;
case CRIT_ID:
if (!cont->app_id) {
// ignore
} else if (crit->regex && regex_cmp(cont->app_id, crit->regex) == 0) {
matches++;
}
// TODO
break;
case CRIT_INSTANCE:
if (!cont->instance) {
// ignore
} else if (crit_is_focused(crit->raw)) {
swayc_t *focused = get_focused_view(&root_container);
if (focused->instance && strcmp(cont->instance, focused->instance) == 0) {
case CRIT_APP_ID:
{
const char *app_id = view_get_app_id(cont->sway_view);
if (!app_id) {
break;
}
if (crit->regex && regex_cmp(app_id, crit->regex) == 0) {
matches++;
}
} else if (crit->regex && regex_cmp(cont->instance, crit->regex) == 0) {
matches++;
break;
}
case CRIT_INSTANCE:
{
const char *instance = view_get_instance(cont->sway_view);
if (!instance) {
break;
}
if (crit->regex && regex_cmp(instance, crit->regex) == 0) {
matches++;
}
break;
}
break;
case CRIT_TILING:
if (!cont->is_floating) {
matches++;
}
// TODO
break;
case CRIT_TITLE:
if (!cont->name) {
// ignore
} else if (crit_is_focused(crit->raw)) {
swayc_t *focused = get_focused_view(&root_container);
if (focused->name && strcmp(cont->name, focused->name) == 0) {
{
const char *title = view_get_title(cont->sway_view);
if (!title) {
break;
}
if (crit->regex && regex_cmp(title, crit->regex) == 0) {
matches++;
}
} else if (crit->regex && regex_cmp(cont->name, crit->regex) == 0) {
matches++;
break;
}
break;
case CRIT_URGENT: // "latest" or "oldest"
case CRIT_URGENT:
// TODO "latest" or "oldest"
break;
case CRIT_WINDOW_ROLE:
// TODO
break;
case CRIT_WINDOW_TYPE:
// TODO wlc indeed exposes this information
// TODO
break;
case CRIT_WORKSPACE: ;
swayc_t *cont_ws = swayc_parent_by_type(cont, C_WORKSPACE);
if (!cont_ws || !cont_ws->name) {
// ignore
} else if (crit_is_focused(crit->raw)) {
swayc_t *focused_ws = swayc_active_workspace();
if (focused_ws->name && strcmp(cont_ws->name, focused_ws->name) == 0) {
matches++;
}
} else if (crit->regex && regex_cmp(cont_ws->name, crit->regex) == 0) {
matches++;
}
case CRIT_WORKSPACE:
// TODO
break;
default:
sway_abort("Invalid criteria type (%i)", crit->type);
@ -429,23 +424,22 @@ struct list_tokens {
list_t *tokens;
};
static void container_match_add(swayc_t *container, struct list_tokens *list_tokens) {
static void container_match_add(swayc_t *container,
struct list_tokens *list_tokens) {
if (criteria_test(container, list_tokens->tokens)) {
list_add(list_tokens->list, container);
}
}
list_t *container_for(list_t *tokens) {
struct list_tokens list_tokens = (struct list_tokens){create_list(), tokens};
list_t *container_for_crit_tokens(list_t *tokens) {
struct list_tokens list_tokens =
(struct list_tokens){create_list(), tokens};
container_map(&root_container, (void (*)(swayc_t *, void *))container_match_add, &list_tokens);
container_map(&root_container,
(void (*)(swayc_t *, void *))container_match_add,
&list_tokens);
// TODO look in the scratchpad
for (int i = 0; i < scratchpad->length; ++i) {
swayc_t *c = scratchpad->items[i];
if (criteria_test(c, tokens)) {
list_add(list_tokens.list, c);
}
}
return list_tokens.list;
}

View file

@ -1,9 +1,11 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdlib.h>
#include <time.h>
#include <wayland-server.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_wl_shell.h>
#include <wlr/render.h>
#include <wlr/render/matrix.h>
#include "log.h"
@ -15,102 +17,219 @@
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
/**
* Rotate a child's position relative to a parent. The parent size is (pw, ph),
* the child position is (*sx, *sy) and its size is (sw, sh).
*/
static void rotate_child_position(double *sx, double *sy, double sw, double sh,
double pw, double ph, float rotation) {
if (rotation != 0.0) {
// Coordinates relative to the center of the subsurface
double ox = *sx - pw/2 + sw/2,
oy = *sy - ph/2 + sh/2;
// Rotated coordinates
double rx = cos(-rotation)*ox - sin(-rotation)*oy,
ry = cos(-rotation)*oy + sin(-rotation)*ox;
*sx = rx + pw/2 - sw/2;
*sy = ry + ph/2 - sh/2;
}
}
static void render_surface(struct wlr_surface *surface,
struct wlr_output *wlr_output, struct timespec *when,
double lx, double ly, float rotation) {
if (!wlr_surface_has_buffer(surface)) {
return;
}
struct wlr_output_layout *layout = root_container.sway_root->output_layout;
int width = surface->current->width;
int height = surface->current->height;
int render_width = width * wlr_output->scale;
int render_height = height * wlr_output->scale;
int owidth, oheight;
wlr_output_effective_resolution(wlr_output, &owidth, &oheight);
// FIXME: view coords are inconsistently assumed to be in output or layout coords
struct wlr_box layout_box = {
.x = lx + wlr_output->lx, .y = ly + wlr_output->ly,
.width = render_width, .height = render_height,
};
if (wlr_output_layout_intersects(layout, wlr_output, &layout_box)) {
struct wlr_box render_box = {
.x = lx, .y = ly,
.width = render_width, .height = render_height
};
float matrix[16];
wlr_matrix_project_box(&matrix, &render_box,
surface->current->transform, 0, &wlr_output->transform_matrix);
wlr_render_with_matrix(server.renderer, surface->texture,
&matrix);
wlr_surface_send_frame_done(surface, when);
}
struct wlr_subsurface *subsurface;
wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
struct wlr_surface_state *state = subsurface->surface->current;
double sx = state->subsurface_position.x;
double sy = state->subsurface_position.y;
double sw = state->buffer_width / state->scale;
double sh = state->buffer_height / state->scale;
rotate_child_position(&sx, &sy, sw, sh, width, height, rotation);
render_surface(subsurface->surface, wlr_output, when,
lx + sx,
ly + sy,
rotation);
}
}
static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface,
struct wlr_output *wlr_output, struct timespec *when, double base_x,
double base_y, float rotation) {
double width = surface->surface->current->width;
double height = surface->surface->current->height;
struct wlr_xdg_popup_v6 *popup_state;
wl_list_for_each(popup_state, &surface->popups, link) {
struct wlr_xdg_surface_v6 *popup = popup_state->base;
if (!popup->configured) {
continue;
}
double popup_width = popup->surface->current->width;
double popup_height = popup->surface->current->height;
double popup_sx, popup_sy;
wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy);
rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height,
width, height, rotation);
render_surface(popup->surface, wlr_output, when,
base_x + popup_sx, base_y + popup_sy, rotation);
render_xdg_v6_popups(popup, wlr_output, when,
base_x + popup_sx, base_y + popup_sy, rotation);
}
}
static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface,
struct wlr_output *wlr_output, struct timespec *when,
double lx, double ly, float rotation,
bool is_child) {
if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) {
render_surface(surface->surface, wlr_output, when,
lx, ly, rotation);
double width = surface->surface->current->width;
double height = surface->surface->current->height;
struct wlr_wl_shell_surface *popup;
wl_list_for_each(popup, &surface->popups, popup_link) {
double popup_width = popup->surface->current->width;
double popup_height = popup->surface->current->height;
double popup_x = popup->transient_state->x;
double popup_y = popup->transient_state->y;
rotate_child_position(&popup_x, &popup_y, popup_width, popup_height,
width, height, rotation);
render_wl_shell_surface(popup, wlr_output, when,
lx + popup_x, ly + popup_y, rotation, true);
}
}
}
static void output_frame_view(swayc_t *view, void *data) {
struct sway_output *output = data;
struct wlr_output *wlr_output = output->wlr_output;
struct sway_view *sway_view = view->sway_view;
struct wlr_surface *surface = sway_view->surface;
if (!wlr_surface_has_buffer(surface)) {
if (!surface) {
return;
}
// TODO
// - Deal with wlr_output_layout
int width = sway_view->surface->current->width;
int height = sway_view->surface->current->height;
int render_width = width * wlr_output->scale;
int render_height = height * wlr_output->scale;
double ox = view->x, oy = view->y;
// TODO
//wlr_output_layout_output_coords(desktop->layout, wlr_output, &ox, &oy);
ox *= wlr_output->scale;
oy *= wlr_output->scale;
// TODO
//if (wlr_output_layout_intersects(desktop->layout, wlr_output,
// lx, ly, lx + render_width, ly + render_height)) {
// return;
//}
// if the shell specifies window geometry, make the top left corner of the
// window in the top left corner of the container to avoid arbitrarily
// sized gaps based on the attached buffer size
int window_offset_x = 0;
int window_offset_y = 0;
if (view->sway_view->type == SWAY_XDG_SHELL_V6_VIEW) {
window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry->x;
window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry->y;
switch (sway_view->type) {
case SWAY_XDG_SHELL_V6_VIEW: {
int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry->x;
int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry->y;
render_surface(surface, wlr_output, &output->last_frame,
view->x - window_offset_x,
view->y - window_offset_y,
0);
render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output,
&output->last_frame,
view->x - window_offset_x, view->y - window_offset_y,
0);
break;
}
case SWAY_WL_SHELL_VIEW:
render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output,
&output->last_frame, view->x, view->y, 0, false);
break;
case SWAY_XWAYLAND_VIEW:
render_surface(surface, wlr_output, &output->last_frame, view->x,
view->y, 0);
break;
default:
break;
}
// TODO
double rotation = 0;
float matrix[16];
float translate_origin[16];
wlr_matrix_translate(&translate_origin,
(int)ox + render_width / 2 - window_offset_x,
(int)oy + render_height / 2 - window_offset_y,
0);
float rotate[16];
wlr_matrix_rotate(&rotate, rotation);
float translate_center[16];
wlr_matrix_translate(&translate_center,
-render_width / 2,
-render_height / 2, 0);
float scale[16];
wlr_matrix_scale(&scale, render_width, render_height, 1);
float transform[16];
wlr_matrix_mul(&translate_origin, &rotate, &transform);
wlr_matrix_mul(&transform, &translate_center, &transform);
wlr_matrix_mul(&transform, &scale, &transform);
wlr_matrix_mul(&wlr_output->transform_matrix, &transform, &matrix);
wlr_render_with_matrix(output->server->renderer, surface->texture, &matrix);
// TODO: move into wlroots
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_surface_send_frame_done(surface, &now);
}
static void output_frame_notify(struct wl_listener *listener, void *data) {
struct sway_output *soutput = wl_container_of(listener, soutput, frame);
struct wlr_output *wlr_output = data;
struct sway_server *server = soutput->server;
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
wlr_renderer_clear(renderer, &clear_color);
int buffer_age = -1;
wlr_output_make_current(wlr_output, &buffer_age);
wlr_renderer_begin(server->renderer, wlr_output);
struct sway_seat *seat = input_manager_current_seat(input_manager);
swayc_t *focus = sway_seat_get_focus_inactive(seat, soutput->swayc);
swayc_t *workspace = (focus->type == C_WORKSPACE ?
focus :
swayc_parent_by_type(focus, C_WORKSPACE));
swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput);
// render unmanaged views on top
struct sway_view *view;
wl_list_for_each(view, &root_container.sway_root->unmanaged_views,
unmanaged_view_link) {
if (view->type == SWAY_XWAYLAND_VIEW) {
// the only kind of unamanged view right now is xwayland override redirect
int view_x = view->wlr_xwayland_surface->x;
int view_y = view->wlr_xwayland_surface->y;
render_surface(view->surface, wlr_output, &soutput->last_frame,
view_x, view_y, 0);
}
}
wlr_renderer_end(server->renderer);
wlr_output_swap_buffers(wlr_output, &soutput->last_frame, NULL);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_output_make_current(wlr_output);
wlr_renderer_begin(server->renderer, wlr_output);
swayc_descendants_of_type(
&root_container, C_VIEW, output_frame_view, soutput);
wlr_renderer_end(server->renderer);
wlr_output_swap_buffers(wlr_output);
soutput->last_frame = now;
}
void output_add_notify(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, output_add);
static void handle_output_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, output_destroy);
struct wlr_output *wlr_output = data;
sway_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name);
destroy_output(output->swayc);
}
void handle_new_output(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data;
wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
struct sway_output *output = calloc(1, sizeof(struct sway_output));
if (!output) {
@ -133,27 +252,11 @@ void output_add_notify(struct wl_listener *listener, void *data) {
sway_input_manager_configure_xcursor(input_manager);
output->frame.notify = output_frame_notify;
wl_signal_add(&wlr_output->events.frame, &output->frame);
}
void output_remove_notify(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, output_remove);
struct wlr_output *wlr_output = data;
sway_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name);
swayc_t *output_container = NULL;
for (int i = 0 ; i < root_container.children->length; ++i) {
swayc_t *child = root_container.children->items[i];
if (child->type == C_OUTPUT &&
child->sway_output->wlr_output == wlr_output) {
output_container = child;
break;
}
}
if (!output_container) {
return;
}
destroy_output(output_container);
output->frame.notify = output_frame_notify;
wl_signal_add(&wlr_output->events.destroy, &output->output_destroy);
output->output_destroy.notify = handle_output_destroy;
arrange_windows(&root_container, -1, -1);
}

View file

@ -51,6 +51,14 @@ static void set_activated(struct sway_view *view, bool activated) {
// no way to activate wl_shell
}
static void close(struct sway_view *view) {
if (!assert_wl_shell(view)) {
return;
}
wl_client_destroy(view->wlr_wl_shell_surface->client);
}
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_wl_shell_surface *sway_surface =
wl_container_of(listener, sway_surface, commit);
@ -77,12 +85,14 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
listener, server, wl_shell_surface);
struct wlr_wl_shell_surface *shell_surface = data;
if (shell_surface->state != WLR_WL_SHELL_SURFACE_STATE_TOPLEVEL) {
// TODO: transient and popups should be floating
if (shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP) {
// popups don't get views
return;
}
sway_log(L_DEBUG, "New wl_shell toplevel title='%s' app_id='%s'",
// TODO make transient windows floating
wlr_log(L_DEBUG, "New wl_shell toplevel title='%s' app_id='%s'",
shell_surface->title, shell_surface->class);
wlr_wl_shell_surface_ping(shell_surface);
@ -101,6 +111,7 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
sway_view->iface.set_size = set_size;
sway_view->iface.set_position = set_position;
sway_view->iface.set_activated = set_activated;
sway_view->iface.close = close;
sway_view->wlr_wl_shell_surface = shell_surface;
sway_view->sway_wl_shell_surface = sway_surface;
sway_view->surface = shell_surface->surface;

View file

@ -57,6 +57,16 @@ static void set_activated(struct sway_view *view, bool activated) {
}
}
static void close(struct sway_view *view) {
if (!assert_xdg(view)) {
return;
}
struct wlr_xdg_surface_v6 *surface = view->wlr_xdg_surface_v6;
if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) {
wlr_xdg_toplevel_v6_send_close(surface);
}
}
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xdg_surface_v6 *sway_surface =
wl_container_of(listener, sway_surface, commit);
@ -88,7 +98,7 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
return;
}
sway_log(L_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'",
wlr_log(L_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'",
xdg_surface->title, xdg_surface->app_id);
wlr_xdg_surface_v6_ping(xdg_surface);
@ -107,14 +117,13 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
sway_view->iface.set_size = set_size;
sway_view->iface.set_position = set_position;
sway_view->iface.set_activated = set_activated;
sway_view->iface.close = close;
sway_view->wlr_xdg_surface_v6 = xdg_surface;
sway_view->sway_xdg_surface_v6 = sway_surface;
sway_view->surface = xdg_surface->surface;
sway_surface->view = sway_view;
// TODO:
// - Wire up listeners
// - Handle popups
// - Look up pid and open on appropriate workspace
// - Set new view to maximized so it behaves nicely
// - Criteria
@ -125,11 +134,9 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
sway_surface->destroy.notify = handle_destroy;
wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy);
// TODO: actual focus semantics
swayc_t *parent = root_container.children->items[0];
parent = parent->children->items[0]; // workspace
swayc_t *cont = new_view(parent, sway_view);
struct sway_seat *seat = input_manager_current_seat(input_manager);
swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container);
swayc_t *cont = new_view(focus, sway_view);
sway_view->swayc = cont;
arrange_windows(cont->parent, -1, -1);

View file

@ -80,6 +80,13 @@ static void set_activated(struct sway_view *view, bool activated) {
wlr_xwayland_surface_activate(surface, activated);
}
static void close(struct sway_view *view) {
if (!assert_xwayland(view)) {
return;
}
wlr_xwayland_surface_close(view->wlr_xwayland_surface);
}
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, commit);
@ -93,13 +100,68 @@ static void handle_commit(struct wl_listener *listener, void *data) {
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, destroy);
struct wlr_xwayland_surface *xsurface = data;
wl_list_remove(&sway_surface->commit.link);
wl_list_remove(&sway_surface->destroy.link);
wl_list_remove(&sway_surface->request_configure.link);
if (xsurface->override_redirect) {
if (xsurface->mapped) {
wl_list_remove(&sway_surface->view->unmanaged_view_link);
}
}
swayc_t *parent = destroy_view(sway_surface->view->swayc);
if (parent) {
arrange_windows(parent, -1, -1);
}
free(sway_surface->view);
free(sway_surface);
arrange_windows(parent, -1, -1);
}
static void handle_unmap_notify(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, unmap_notify);
struct wlr_xwayland_surface *xsurface = data;
if (xsurface->override_redirect) {
wl_list_remove(&sway_surface->view->unmanaged_view_link);
}
// take it out of the tree
swayc_t *parent = destroy_view(sway_surface->view->swayc);
if (parent) {
arrange_windows(parent, -1, -1);
}
sway_surface->view->swayc = NULL;
sway_surface->view->surface = NULL;
}
static void handle_map_notify(struct wl_listener *listener, void *data) {
// TODO put the view back into the tree
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, map_notify);
struct wlr_xwayland_surface *xsurface = data;
sway_surface->view->surface = xsurface->surface;
// put it back into the tree
if (xsurface->override_redirect) {
wl_list_insert(&root_container.sway_root->unmanaged_views,
&sway_surface->view->unmanaged_view_link);
} else {
struct sway_view *view = sway_surface->view;
destroy_view(view->swayc);
swayc_t *parent = root_container.children->items[0];
parent = parent->children->items[0]; // workspace
swayc_t *cont = new_view(parent, view);
view->swayc = cont;
arrange_windows(cont->parent, -1, -1);
sway_input_manager_set_focus(input_manager, cont);
}
}
static void handle_configure_request(struct wl_listener *listener, void *data) {
@ -119,12 +181,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
listener, server, xwayland_surface);
struct wlr_xwayland_surface *xsurface = data;
if (xsurface->override_redirect) {
// TODO: floating popups
return;
}
sway_log(L_DEBUG, "New xwayland surface title='%s' class='%s'",
wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'",
xsurface->title, xsurface->class);
struct sway_xwayland_surface *sway_surface =
@ -142,28 +199,40 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
sway_view->iface.set_size = set_size;
sway_view->iface.set_position = set_position;
sway_view->iface.set_activated = set_activated;
sway_view->iface.close = close;
sway_view->wlr_xwayland_surface = xsurface;
sway_view->sway_xwayland_surface = sway_surface;
// TODO remove from the tree when the surface goes away (unmapped)
sway_view->surface = xsurface->surface;
sway_surface->view = sway_view;
// TODO:
// - Wire up listeners
// - Handle popups
// - Look up pid and open on appropriate workspace
// - Set new view to maximized so it behaves nicely
// - Criteria
sway_surface->commit.notify = handle_commit;
wl_signal_add(&xsurface->surface->events.commit, &sway_surface->commit);
sway_surface->destroy.notify = handle_destroy;
sway_surface->commit.notify = handle_commit;
wl_signal_add(&xsurface->events.destroy, &sway_surface->destroy);
sway_surface->request_configure.notify = handle_configure_request;
sway_surface->destroy.notify = handle_destroy;
wl_signal_add(&xsurface->events.request_configure,
&sway_surface->request_configure);
sway_surface->request_configure.notify = handle_configure_request;
wl_signal_add(&xsurface->events.unmap_notify, &sway_surface->unmap_notify);
sway_surface->unmap_notify.notify = handle_unmap_notify;
wl_signal_add(&xsurface->events.map_notify, &sway_surface->map_notify);
sway_surface->map_notify.notify = handle_map_notify;
if (xsurface->override_redirect) {
// these don't get a container in the tree
wl_list_insert(&root_container.sway_root->unmanaged_views,
&sway_view->unmanaged_view_link);
return;
}
// TODO: actual focus semantics
swayc_t *parent = root_container.children->items[0];
parent = parent->children->items[0]; // workspace

View file

@ -24,6 +24,31 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,
struct wlr_seat *seat = cursor->seat->wlr_seat;
struct wlr_surface *surface = NULL;
double sx, sy;
// check for unmanaged views first
struct sway_view *view;
wl_list_for_each_reverse(view, &root_container.sway_root->unmanaged_views,
unmanaged_view_link) {
if (view->type == SWAY_XWAYLAND_VIEW) {
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
struct wlr_box box = {
.x = xsurface->x,
.y = xsurface->y,
.width = xsurface->width,
.height = xsurface->height,
};
if (wlr_box_contains_point(&box, cursor->x, cursor->y)) {
surface = xsurface->surface;
sx = cursor->x - box.x;
sy = cursor->y - box.y;
wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
wlr_seat_pointer_notify_motion(seat, time, sx, sy);
return;
}
}
}
swayc_t *swayc =
swayc_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy);
if (swayc) {
@ -85,35 +110,35 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, touch_down);
struct wlr_event_touch_down *event = data;
sway_log(L_DEBUG, "TODO: handle touch down event: %p", event);
wlr_log(L_DEBUG, "TODO: handle touch down event: %p", event);
}
static void handle_touch_up(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, touch_up);
struct wlr_event_touch_up *event = data;
sway_log(L_DEBUG, "TODO: handle touch up event: %p", event);
wlr_log(L_DEBUG, "TODO: handle touch up event: %p", event);
}
static void handle_touch_motion(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, touch_motion);
struct wlr_event_touch_motion *event = data;
sway_log(L_DEBUG, "TODO: handle touch motion event: %p", event);
wlr_log(L_DEBUG, "TODO: handle touch motion event: %p", event);
}
static void handle_tool_axis(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, tool_axis);
struct wlr_event_tablet_tool_axis *event = data;
sway_log(L_DEBUG, "TODO: handle tool axis event: %p", event);
wlr_log(L_DEBUG, "TODO: handle tool axis event: %p", event);
}
static void handle_tool_tip(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, tool_tip);
struct wlr_event_tablet_tool_tip *event = data;
sway_log(L_DEBUG, "TODO: handle tool tip event: %p", event);
wlr_log(L_DEBUG, "TODO: handle tool tip event: %p", event);
}
static void handle_request_set_cursor(struct wl_listener *listener,
@ -121,7 +146,17 @@ static void handle_request_set_cursor(struct wl_listener *listener,
struct sway_cursor *cursor =
wl_container_of(listener, cursor, request_set_cursor);
struct wlr_seat_pointer_request_set_cursor_event *event = data;
sway_log(L_DEBUG, "TODO: handle request set cursor event: %p", event);
wlr_log(L_DEBUG, "TODO: handle request set cursor event: %p", event);
}
void sway_cursor_destroy(struct sway_cursor *cursor) {
if (!cursor) {
return;
}
wlr_xcursor_manager_destroy(cursor->xcursor_manager);
wlr_cursor_destroy(cursor->cursor);
free(cursor);
}
struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {

View file

@ -23,7 +23,15 @@ struct sway_input_manager *input_manager;
struct input_config *current_input_config = NULL;
struct seat_config *current_seat_config = NULL;
static struct sway_seat *input_manager_get_seat(
struct sway_seat *input_manager_current_seat(struct sway_input_manager *input) {
struct sway_seat *seat = config->handler_context.seat;
if (!seat) {
seat = sway_input_manager_get_default_seat(input_manager);
}
return seat;
}
struct sway_seat *input_manager_get_seat(
struct sway_input_manager *input, const char *seat_name) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
@ -52,7 +60,7 @@ static char *get_device_identifier(struct wlr_input_device *device) {
int len = snprintf(NULL, 0, fmt, vendor, product, name) + 1;
char *identifier = malloc(len);
if (!identifier) {
sway_log(L_ERROR, "Unable to allocate unique input device name");
wlr_log(L_ERROR, "Unable to allocate unique input device name");
return NULL;
}
@ -93,68 +101,93 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device
}
libinput_device = wlr_libinput_get_device_handle(wlr_device);
sway_log(L_DEBUG, "sway_input_manager_libinput_config_pointer(%s)", ic->identifier);
wlr_log(L_DEBUG, "sway_input_manager_libinput_config_pointer(%s)", ic->identifier);
if (ic->accel_profile != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)",
ic->identifier, ic->accel_profile);
libinput_device_config_accel_set_profile(libinput_device, ic->accel_profile);
}
if (ic->click_method != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)",
ic->identifier, ic->click_method);
libinput_device_config_click_set_method(libinput_device, ic->click_method);
}
if (ic->drag_lock != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
ic->identifier, ic->click_method);
libinput_device_config_tap_set_drag_lock_enabled(libinput_device, ic->drag_lock);
}
if (ic->dwt != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)",
ic->identifier, ic->dwt);
libinput_device_config_dwt_set_enabled(libinput_device, ic->dwt);
}
if (ic->left_handed != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) left_handed_set_enabled(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) left_handed_set_enabled(%d)",
ic->identifier, ic->left_handed);
libinput_device_config_left_handed_set(libinput_device, ic->left_handed);
}
if (ic->middle_emulation != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) middle_emulation_set_enabled(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) middle_emulation_set_enabled(%d)",
ic->identifier, ic->middle_emulation);
libinput_device_config_middle_emulation_set_enabled(libinput_device, ic->middle_emulation);
}
if (ic->natural_scroll != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) natural_scroll_set_enabled(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) natural_scroll_set_enabled(%d)",
ic->identifier, ic->natural_scroll);
libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, ic->natural_scroll);
}
if (ic->pointer_accel != FLT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)",
ic->identifier, ic->pointer_accel);
libinput_device_config_accel_set_speed(libinput_device, ic->pointer_accel);
}
if (ic->scroll_method != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)",
ic->identifier, ic->scroll_method);
libinput_device_config_scroll_set_method(libinput_device, ic->scroll_method);
}
if (ic->send_events != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)",
ic->identifier, ic->send_events);
libinput_device_config_send_events_set_mode(libinput_device, ic->send_events);
}
if (ic->tap != INT_MIN) {
sway_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)",
wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)",
ic->identifier, ic->tap);
libinput_device_config_tap_set_enabled(libinput_device, ic->tap);
}
}
static void input_add_notify(struct wl_listener *listener, void *data) {
static void handle_device_destroy(struct wl_listener *listener, void *data) {
struct wlr_input_device *device = data;
struct sway_input_device *input_device =
input_sway_device_from_wlr(input_manager, device);
if (!sway_assert(input_device, "could not find sway device")) {
return;
}
wlr_log(L_DEBUG, "removing device: '%s'",
input_device->identifier);
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input_manager->seats, link) {
sway_seat_remove_device(seat, input_device);
}
wl_list_remove(&input_device->link);
wl_list_remove(&input_device->device_destroy.link);
free_input_config(input_device->config);
free(input_device->identifier);
free(input_device);
}
static void handle_new_input(struct wl_listener *listener, void *data) {
struct sway_input_manager *input =
wl_container_of(listener, input, input_add);
wl_container_of(listener, input, new_input);
struct wlr_input_device *device = data;
struct sway_input_device *input_device =
@ -167,14 +200,15 @@ static void input_add_notify(struct wl_listener *listener, void *data) {
input_device->identifier = get_device_identifier(device);
wl_list_insert(&input->devices, &input_device->link);
sway_log(L_DEBUG, "adding device: '%s'",
wlr_log(L_DEBUG, "adding device: '%s'",
input_device->identifier);
// find config
for (int i = 0; i < config->input_configs->length; ++i) {
struct input_config *input_config = config->input_configs->items[i];
if (strcmp(input_config->identifier, input_device->identifier) == 0) {
input_device->config = input_config;
free_input_config(input_device->config);
input_device->config = copy_input_config(input_config);
break;
}
}
@ -185,7 +219,7 @@ static void input_add_notify(struct wl_listener *listener, void *data) {
struct sway_seat *seat = NULL;
if (!input_has_seat_configuration(input)) {
sway_log(L_DEBUG, "no seat configuration, using default seat");
wlr_log(L_DEBUG, "no seat configuration, using default seat");
seat = input_manager_get_seat(input, default_seat);
sway_seat_add_device(seat, input_device);
return;
@ -213,35 +247,13 @@ static void input_add_notify(struct wl_listener *listener, void *data) {
}
if (!added) {
sway_log(L_DEBUG,
wlr_log(L_DEBUG,
"device '%s' is not configured on any seats",
input_device->identifier);
}
}
static void input_remove_notify(struct wl_listener *listener, void *data) {
struct sway_input_manager *input =
wl_container_of(listener, input, input_remove);
struct wlr_input_device *device = data;
struct sway_input_device *input_device =
input_sway_device_from_wlr(input, device);
if (!sway_assert(input_device, "could not find sway device")) {
return;
}
sway_log(L_DEBUG, "removing device: '%s'",
input_device->identifier);
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
sway_seat_remove_device(seat, input_device);
}
wl_list_remove(&input_device->link);
free(input_device->identifier);
free(input_device);
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
input_device->device_destroy.notify = handle_device_destroy;
}
struct sway_input_manager *sway_input_manager_create(
@ -259,11 +271,8 @@ struct sway_input_manager *sway_input_manager_create(
// create the default seat
input_manager_get_seat(input, default_seat);
input->input_add.notify = input_add_notify;
wl_signal_add(&server->backend->events.input_add, &input->input_add);
input->input_remove.notify = input_remove_notify;
wl_signal_add(&server->backend->events.input_remove, &input->input_remove);
input->new_input.notify = handle_new_input;
wl_signal_add(&server->backend->events.new_input, &input->new_input);
return input;
}
@ -272,7 +281,7 @@ bool sway_input_manager_has_focus(struct sway_input_manager *input,
swayc_t *container) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
if (seat->focus == container) {
if (sway_seat_get_focus(seat) == container) {
return true;
}
}
@ -293,7 +302,8 @@ void sway_input_manager_apply_input_config(struct sway_input_manager *input,
struct sway_input_device *input_device = NULL;
wl_list_for_each(input_device, &input->devices, link) {
if (strcmp(input_device->identifier, input_config->identifier) == 0) {
input_device->config = input_config;
free_input_config(input_device->config);
input_device->config = copy_input_config(input_config);
if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
sway_input_manager_libinput_config_pointer(input_device);
@ -309,7 +319,7 @@ void sway_input_manager_apply_input_config(struct sway_input_manager *input,
void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
struct seat_config *seat_config) {
sway_log(L_DEBUG, "applying new seat config for seat %s",
wlr_log(L_DEBUG, "applying new seat config for seat %s",
seat_config->name);
struct sway_seat *seat = input_manager_get_seat(input, seat_config->name);
if (!seat) {
@ -369,3 +379,14 @@ void sway_input_manager_configure_xcursor(struct sway_input_manager *input) {
sway_seat_configure_xcursor(seat);
}
}
struct sway_seat *sway_input_manager_get_default_seat(
struct sway_input_manager *input) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
if (strcmp(seat->wlr_seat->name, "seat0") == 0) {
return seat;
}
}
return seat;
}

View file

@ -1,8 +1,328 @@
#include <assert.h>
#include <wlr/backend/multi.h>
#include <wlr/backend/session.h>
#include "sway/input/seat.h"
#include "sway/input/keyboard.h"
#include "sway/input/input-manager.h"
#include "sway/commands.h"
#include "log.h"
static bool keysym_is_modifier(xkb_keysym_t keysym) {
switch (keysym) {
case XKB_KEY_Shift_L: case XKB_KEY_Shift_R:
case XKB_KEY_Control_L: case XKB_KEY_Control_R:
case XKB_KEY_Caps_Lock:
case XKB_KEY_Shift_Lock:
case XKB_KEY_Meta_L: case XKB_KEY_Meta_R:
case XKB_KEY_Alt_L: case XKB_KEY_Alt_R:
case XKB_KEY_Super_L: case XKB_KEY_Super_R:
case XKB_KEY_Hyper_L: case XKB_KEY_Hyper_R:
return true;
default:
return false;
}
}
static size_t pressed_keysyms_length(xkb_keysym_t *pressed_keysyms) {
size_t n = 0;
for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) {
if (pressed_keysyms[i] != XKB_KEY_NoSymbol) {
++n;
}
}
return n;
}
static ssize_t pressed_keysyms_index(xkb_keysym_t *pressed_keysyms,
xkb_keysym_t keysym) {
for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) {
if (pressed_keysyms[i] == keysym) {
return i;
}
}
return -1;
}
static void pressed_keysyms_add(xkb_keysym_t *pressed_keysyms,
xkb_keysym_t keysym) {
ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym);
if (i < 0) {
i = pressed_keysyms_index(pressed_keysyms, XKB_KEY_NoSymbol);
if (i >= 0) {
pressed_keysyms[i] = keysym;
}
}
}
static void pressed_keysyms_remove(xkb_keysym_t *pressed_keysyms,
xkb_keysym_t keysym) {
ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym);
if (i >= 0) {
pressed_keysyms[i] = XKB_KEY_NoSymbol;
}
}
static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms,
const xkb_keysym_t *keysyms, size_t keysyms_len,
enum wlr_key_state state) {
for (size_t i = 0; i < keysyms_len; ++i) {
if (keysym_is_modifier(keysyms[i])) {
continue;
}
if (state == WLR_KEY_PRESSED) {
pressed_keysyms_add(pressed_keysyms, keysyms[i]);
} else { // WLR_KEY_RELEASED
pressed_keysyms_remove(pressed_keysyms, keysyms[i]);
}
}
}
static bool binding_matches_key_state(struct sway_binding *binding,
enum wlr_key_state key_state) {
if (key_state == WLR_KEY_PRESSED && !binding->release) {
return true;
}
if (key_state == WLR_KEY_RELEASED && binding->release) {
return true;
}
return false;
}
static void keyboard_execute_command(struct sway_keyboard *keyboard,
struct sway_binding *binding) {
wlr_log(L_DEBUG, "running command for binding: %s",
binding->command);
config_clear_handler_context(config);
config->handler_context.seat = keyboard->seat_device->sway_seat;
struct cmd_results *results = execute_command(binding->command, NULL);
if (results->status != CMD_SUCCESS) {
wlr_log(L_DEBUG, "could not run command for binding: %s",
binding->command);
}
free_cmd_results(results);
}
/**
* Execute a built-in, hardcoded compositor binding. These are triggered from a
* single keysym.
*
* Returns true if the keysym was handled by a binding and false if the event
* should be propagated to clients.
*/
static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) {
for (size_t i = 0; i < keysyms_len; ++i) {
xkb_keysym_t keysym = pressed_keysyms[i];
if (keysym >= XKB_KEY_XF86Switch_VT_1 &&
keysym <= XKB_KEY_XF86Switch_VT_12) {
if (wlr_backend_is_multi(server.backend)) {
struct wlr_session *session =
wlr_multi_get_session(server.backend);
if (session) {
unsigned vt = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
wlr_session_change_vt(session, vt);
}
}
return true;
}
}
return false;
}
/**
* Execute keyboard bindings bound with `bindysm` for the given keyboard state.
*
* Returns true if the keysym was handled by a binding and false if the event
* should be propagated to clients.
*/
static bool keyboard_execute_bindsym(struct sway_keyboard *keyboard,
xkb_keysym_t *pressed_keysyms, uint32_t modifiers,
enum wlr_key_state key_state) {
// configured bindings
int n = pressed_keysyms_length(pressed_keysyms);
list_t *keysym_bindings = config->current_mode->keysym_bindings;
for (int i = 0; i < keysym_bindings->length; ++i) {
struct sway_binding *binding = keysym_bindings->items[i];
if (!binding_matches_key_state(binding, key_state) ||
modifiers ^ binding->modifiers ||
n != binding->keys->length) {
continue;
}
bool match = true;
for (int j = 0; j < binding->keys->length; ++j) {
match =
pressed_keysyms_index(pressed_keysyms,
*(int*)binding->keys->items[j]) >= 0;
if (!match) {
break;
}
}
if (match) {
keyboard_execute_command(keyboard, binding);
return true;
}
}
return false;
}
static bool binding_matches_keycodes(struct wlr_keyboard *keyboard,
struct sway_binding *binding, struct wlr_event_keyboard_key *event) {
assert(binding->bindcode);
uint32_t keycode = event->keycode + 8;
if (!binding_matches_key_state(binding, event->state)) {
return false;
}
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard);
if (modifiers ^ binding->modifiers) {
return false;
}
// on release, the released key must be in the binding
if (event->state == WLR_KEY_RELEASED) {
bool found = false;
for (int i = 0; i < binding->keys->length; ++i) {
uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8;
if (binding_keycode == keycode) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
// every keycode in the binding must be present in the pressed keys on the
// keyboard
for (int i = 0; i < binding->keys->length; ++i) {
uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8;
if (event->state == WLR_KEY_RELEASED && keycode == binding_keycode) {
continue;
}
bool found = false;
for (size_t j = 0; j < keyboard->num_keycodes; ++j) {
xkb_keycode_t keycode = keyboard->keycodes[j] + 8;
if (keycode == binding_keycode) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
// every keycode pressed on the keyboard must be present within the binding
// keys (unless it is a modifier)
for (size_t i = 0; i < keyboard->num_keycodes; ++i) {
xkb_keycode_t keycode = keyboard->keycodes[i] + 8;
bool found = false;
for (int j = 0; j < binding->keys->length; ++j) {
uint32_t binding_keycode = *(uint32_t*)binding->keys->items[j] + 8;
if (binding_keycode == keycode) {
found = true;
break;
}
}
if (!found) {
if (!binding->modifiers) {
return false;
}
// check if it is a modifier, which we know matched from the check
// above
const xkb_keysym_t *keysyms;
int num_keysyms =
xkb_state_key_get_syms(keyboard->xkb_state,
keycode, &keysyms);
if (num_keysyms != 1 || !keysym_is_modifier(keysyms[0])) {
return false;
}
}
}
return true;
}
/**
* Execute keyboard bindings bound with `bindcode` for the given keyboard state.
*
* Returns true if the keysym was handled by a binding and false if the event
* should be propagated to clients.
*/
static bool keyboard_execute_bindcode(struct sway_keyboard *keyboard,
struct wlr_event_keyboard_key *event) {
struct wlr_keyboard *wlr_keyboard =
keyboard->seat_device->input_device->wlr_device->keyboard;
list_t *keycode_bindings = config->current_mode->keycode_bindings;
for (int i = 0; i < keycode_bindings->length; ++i) {
struct sway_binding *binding = keycode_bindings->items[i];
if (binding_matches_keycodes(wlr_keyboard, binding, event)) {
keyboard_execute_command(keyboard, binding);
return true;
}
}
return false;
}
/**
* Get keysyms and modifiers from the keyboard as xkb sees them.
*
* This uses the xkb keysyms translation based on pressed modifiers and clears
* the consumed modifiers from the list of modifiers passed to keybind
* detection.
*
* On US layout, pressing Alt+Shift+2 will trigger Alt+@.
*/
static size_t keyboard_keysyms_translated(struct sway_keyboard *keyboard,
xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
uint32_t *modifiers) {
struct wlr_input_device *device =
keyboard->seat_device->input_device->wlr_device;
*modifiers = wlr_keyboard_get_modifiers(device->keyboard);
xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2(
device->keyboard->xkb_state, keycode, XKB_CONSUMED_MODE_XKB);
*modifiers = *modifiers & ~consumed;
return xkb_state_key_get_syms(device->keyboard->xkb_state,
keycode, keysyms);
}
/**
* Get keysyms and modifiers from the keyboard as if modifiers didn't change
* keysyms.
*
* This avoids the xkb keysym translation based on modifiers considered pressed
* in the state.
*
* This will trigger keybinds such as Alt+Shift+2.
*/
static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard,
xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
uint32_t *modifiers) {
struct wlr_input_device *device =
keyboard->seat_device->input_device->wlr_device;
*modifiers = wlr_keyboard_get_modifiers(device->keyboard);
xkb_layout_index_t layout_index = xkb_state_key_get_layout(
device->keyboard->xkb_state, keycode);
return xkb_keymap_key_get_syms_by_level(device->keyboard->keymap,
keycode, layout_index, 0, keysyms);
}
static void handle_keyboard_key(struct wl_listener *listener, void *data) {
struct sway_keyboard *keyboard =
wl_container_of(listener, keyboard, keyboard_key);
@ -10,9 +330,70 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
struct wlr_input_device *wlr_device =
keyboard->seat_device->input_device->wlr_device;
struct wlr_event_keyboard_key *event = data;
wlr_seat_set_keyboard(wlr_seat, wlr_device);
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
event->keycode, event->state);
xkb_keycode_t keycode = event->keycode + 8;
bool handled = false;
// handle keycodes
handled = keyboard_execute_bindcode(keyboard, event);
// handle translated keysyms
if (!handled && event->state == WLR_KEY_RELEASED) {
handled = keyboard_execute_bindsym(keyboard,
keyboard->pressed_keysyms_translated,
keyboard->modifiers_translated,
event->state);
}
const xkb_keysym_t *translated_keysyms;
size_t translated_keysyms_len =
keyboard_keysyms_translated(keyboard, keycode, &translated_keysyms,
&keyboard->modifiers_translated);
pressed_keysyms_update(keyboard->pressed_keysyms_translated,
translated_keysyms, translated_keysyms_len, event->state);
if (!handled && event->state == WLR_KEY_PRESSED) {
handled = keyboard_execute_bindsym(keyboard,
keyboard->pressed_keysyms_translated,
keyboard->modifiers_translated,
event->state);
}
// Handle raw keysyms
if (!handled && event->state == WLR_KEY_RELEASED) {
handled = keyboard_execute_bindsym(keyboard,
keyboard->pressed_keysyms_raw, keyboard->modifiers_raw,
event->state);
}
const xkb_keysym_t *raw_keysyms;
size_t raw_keysyms_len =
keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &keyboard->modifiers_raw);
pressed_keysyms_update(keyboard->pressed_keysyms_raw, raw_keysyms,
raw_keysyms_len, event->state);
if (!handled && event->state == WLR_KEY_PRESSED) {
handled = keyboard_execute_bindsym(keyboard,
keyboard->pressed_keysyms_raw, keyboard->modifiers_raw,
event->state);
}
// Compositor bindings
if (!handled && event->state == WLR_KEY_PRESSED) {
handled =
keyboard_execute_compositor_binding(keyboard,
keyboard->pressed_keysyms_translated,
keyboard->modifiers_translated,
translated_keysyms_len);
}
if (!handled && event->state == WLR_KEY_PRESSED) {
handled =
keyboard_execute_compositor_binding(keyboard,
keyboard->pressed_keysyms_raw, keyboard->modifiers_raw,
raw_keysyms_len);
}
if (!handled || event->state == WLR_KEY_RELEASED) {
wlr_seat_set_keyboard(wlr_seat, wlr_device);
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
event->keycode, event->state);
}
}
static void handle_keyboard_modifiers(struct wl_listener *listener,
@ -23,7 +404,7 @@ static void handle_keyboard_modifiers(struct wl_listener *listener,
struct wlr_input_device *wlr_device =
keyboard->seat_device->input_device->wlr_device;
wlr_seat_set_keyboard(wlr_seat, wlr_device);
wlr_seat_keyboard_notify_modifiers(wlr_seat);
wlr_seat_keyboard_notify_modifiers(wlr_seat, &wlr_device->keyboard->modifiers);
}
struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
@ -89,7 +470,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!keymap) {
sway_log(L_DEBUG, "cannot configure keyboard: keymap does not exist");
wlr_log(L_DEBUG, "cannot configure keyboard: keymap does not exist");
xkb_context_unref(context);
return;
}

View file

@ -1,6 +1,7 @@
#define _XOPEN_SOURCE 700
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include "sway/container.h"
#include "sway/input/seat.h"
#include "sway/input/cursor.h"
#include "sway/input/input-manager.h"
@ -21,6 +22,91 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
free(seat_device);
}
void sway_seat_destroy(struct sway_seat *seat) {
struct sway_seat_device *seat_device, *next;
wl_list_for_each_safe(seat_device, next, &seat->devices, link) {
seat_device_destroy(seat_device);
}
sway_cursor_destroy(seat->cursor);
wl_list_remove(&seat->link);
wlr_seat_destroy(seat->wlr_seat);
}
static void handle_seat_container_destroy(struct wl_listener *listener,
void *data) {
struct sway_seat_container *seat_con =
wl_container_of(listener, seat_con, destroy);
struct sway_seat *seat = seat_con->seat;
swayc_t *con = seat_con->container;
bool is_focus = (sway_seat_get_focus(seat) == con);
wl_list_remove(&seat_con->link);
if (is_focus) {
// pick next focus
sway_seat_set_focus(seat, NULL);
swayc_t *next = sway_seat_get_focus_inactive(seat, con->parent);
if (next == NULL) {
next = con->parent;
}
sway_seat_set_focus(seat, next);
}
wl_list_remove(&seat_con->destroy.link);
free(seat_con);
}
static struct sway_seat_container *seat_container_from_container(
struct sway_seat *seat, swayc_t *con) {
if (con->type < C_WORKSPACE) {
// these don't get seat containers ever
return NULL;
}
struct sway_seat_container *seat_con = NULL;
wl_list_for_each(seat_con, &seat->focus_stack, link) {
if (seat_con->container == con) {
return seat_con;
}
}
seat_con = calloc(1, sizeof(struct sway_seat_container));
if (seat_con == NULL) {
wlr_log(L_ERROR, "could not allocate seat container");
return NULL;
}
seat_con->container = con;
seat_con->seat = seat;
wl_list_insert(seat->focus_stack.prev, &seat_con->link);
wl_signal_add(&con->events.destroy, &seat_con->destroy);
seat_con->destroy.notify = handle_seat_container_destroy;
return seat_con;
}
static void handle_new_container(struct wl_listener *listener, void *data) {
struct sway_seat *seat = wl_container_of(listener, seat, new_container);
swayc_t *con = data;
seat_container_from_container(seat, con);
}
static void collect_focus_iter(swayc_t *con, void *data) {
struct sway_seat *seat = data;
if (con->type > C_WORKSPACE) {
return;
}
struct sway_seat_container *seat_con =
seat_container_from_container(seat, con);
if (!seat_con) {
return;
}
wl_list_remove(&seat_con->link);
wl_list_insert(&seat->focus_stack, &seat_con->link);
}
struct sway_seat *sway_seat_create(struct sway_input_manager *input,
const char *seat_name) {
struct sway_seat *seat = calloc(1, sizeof(struct sway_seat));
@ -41,6 +127,15 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input,
return NULL;
}
// init the focus stack
wl_list_init(&seat->focus_stack);
container_for_each_bfs(&root_container, collect_focus_iter, seat);
wl_signal_add(&root_container.sway_root->events.new_container,
&seat->new_container);
seat->new_container.notify = handle_new_container;
seat->input = input;
wl_list_init(&seat->devices);
@ -67,13 +162,17 @@ static void seat_configure_keyboard(struct sway_seat *seat,
if (!seat_device->keyboard) {
sway_keyboard_create(seat, seat_device);
}
struct wlr_keyboard *wlr_keyboard = seat_device->input_device->wlr_device->keyboard;
sway_keyboard_configure(seat_device->keyboard);
wlr_seat_set_keyboard(seat->wlr_seat,
seat_device->input_device->wlr_device);
if (seat->focus) {
seat_device->input_device->wlr_device);
swayc_t *focus = sway_seat_get_focus(seat);
if (focus && focus->type == C_VIEW) {
// force notify reenter to pick up the new configuration
wlr_seat_keyboard_clear_focus(seat->wlr_seat);
wlr_seat_keyboard_notify_enter(seat->wlr_seat, seat->focus->sway_view->surface);
wlr_seat_keyboard_notify_enter(seat->wlr_seat,
focus->sway_view->surface, wlr_keyboard->keycodes,
wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers);
}
}
@ -112,7 +211,7 @@ void sway_seat_configure_device(struct sway_seat *seat,
case WLR_INPUT_DEVICE_TOUCH:
case WLR_INPUT_DEVICE_TABLET_PAD:
case WLR_INPUT_DEVICE_TABLET_TOOL:
sway_log(L_DEBUG, "TODO: configure other devices");
wlr_log(L_DEBUG, "TODO: configure other devices");
break;
}
}
@ -127,11 +226,11 @@ void sway_seat_add_device(struct sway_seat *seat,
struct sway_seat_device *seat_device =
calloc(1, sizeof(struct sway_seat_device));
if (!seat_device) {
sway_log(L_DEBUG, "could not allocate seat device");
wlr_log(L_DEBUG, "could not allocate seat device");
return;
}
sway_log(L_DEBUG, "adding device %s to seat %s",
wlr_log(L_DEBUG, "adding device %s to seat %s",
input_device->identifier, seat->wlr_seat->name);
seat_device->sway_seat = seat;
@ -150,7 +249,7 @@ void sway_seat_remove_device(struct sway_seat *seat,
return;
}
sway_log(L_DEBUG, "removing device %s from seat %s",
wlr_log(L_DEBUG, "removing device %s from seat %s",
input_device->identifier, seat->wlr_seat->name);
seat_device_destroy(seat_device);
@ -190,46 +289,89 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) {
seat->cursor->cursor->y);
}
static void handle_focus_destroy(struct wl_listener *listener, void *data) {
struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy);
//swayc_t *container = data;
// TODO set new focus based on the state of the tree
sway_seat_set_focus(seat, NULL);
}
void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) {
swayc_t *last_focus = seat->focus;
swayc_t *last_focus = sway_seat_get_focus(seat);
if (last_focus == container) {
if (container && last_focus == container) {
return;
}
if (last_focus) {
wl_list_remove(&seat->focus_destroy.link);
}
if (container) {
struct sway_view *view = container->sway_view;
view->iface.set_activated(view, true);
wl_signal_add(&container->events.destroy, &seat->focus_destroy);
seat->focus_destroy.notify = handle_focus_destroy;
wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface);
struct sway_seat_container *seat_con =
seat_container_from_container(seat, container);
if (!seat_con) {
return;
}
wl_list_remove(&seat_con->link);
wl_list_insert(&seat->focus_stack, &seat_con->link);
if (container->type == C_VIEW) {
struct sway_view *view = container->sway_view;
view_set_activated(view, true);
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
if (keyboard) {
wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface,
keyboard->keycodes, keyboard->num_keycodes,
&keyboard->modifiers);
} else {
wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface,
NULL, 0, NULL);
}
}
}
seat->focus = container;
if (last_focus &&
if (last_focus && last_focus->type == C_VIEW &&
!sway_input_manager_has_focus(seat->input, last_focus)) {
struct sway_view *view = last_focus->sway_view;
view->iface.set_activated(view, false);
view_set_activated(view, false);
}
seat->has_focus = (container != NULL);
}
swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container) {
struct sway_seat_container *current = NULL;
swayc_t *parent = NULL;
wl_list_for_each(current, &seat->focus_stack, link) {
parent = current->container->parent;
if (current->container == container) {
return current->container;
}
while (parent) {
if (parent == container) {
return current->container;
}
parent = parent->parent;
}
}
return NULL;
}
swayc_t *sway_seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) {
return NULL;
}
return sway_seat_get_focus_inactive(seat, &root_container);
}
swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat,
enum swayc_types type) {
swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container);
if (focus->type == type) {
return focus;
}
return swayc_parent_by_type(focus, type);
}
void sway_seat_set_config(struct sway_seat *seat,
struct seat_config *seat_config) {
// clear configs
free_seat_config(seat->config);
seat->config = NULL;
struct sway_seat_device *seat_device = NULL;
@ -242,11 +384,9 @@ void sway_seat_set_config(struct sway_seat *seat,
}
// add configs
seat->config = seat_config;
seat->config = copy_seat_config(seat_config);
wl_list_for_each(seat_device, &seat->devices, link) {
seat_device->attachment_config =
seat_config_get_attachment(seat_config,
seat_device->input_device->identifier);
sway_seat_configure_device(seat, seat_device->input_device);
}
}

View file

@ -74,8 +74,8 @@ static void ipc_json_describe_output(swayc_t *container, json_object *object) {
json_object_object_add(object, "refresh", json_object_new_int(wlr_output->refresh));
json_object_object_add(object, "transform",
json_object_new_string(ipc_json_get_output_transform(wlr_output->transform)));
json_object_object_add(object, "current_workspace",
(container->focused) ? json_object_new_string(container->focused->name) : NULL);
// TODO WLR need to set "current_workspace" to the currently focused
// workspace in a way that makes sense with multiseat
}
static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) {

View file

@ -125,32 +125,32 @@ struct sockaddr_un *ipc_user_sockaddr(void) {
int ipc_handle_connection(int fd, uint32_t mask, void *data) {
(void) fd;
struct sway_server *server = data;
sway_log(L_DEBUG, "Event on IPC listening socket");
wlr_log(L_DEBUG, "Event on IPC listening socket");
assert(mask == WL_EVENT_READABLE);
int client_fd = accept(ipc_socket, NULL, NULL);
if (client_fd == -1) {
sway_log_errno(L_ERROR, "Unable to accept IPC client connection");
wlr_log_errno(L_ERROR, "Unable to accept IPC client connection");
return 0;
}
int flags;
if ((flags = fcntl(client_fd, F_GETFD)) == -1
|| fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
sway_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket");
wlr_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket");
close(client_fd);
return 0;
}
if ((flags = fcntl(client_fd, F_GETFL)) == -1
|| fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) {
sway_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket");
wlr_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket");
close(client_fd);
return 0;
}
struct ipc_client *client = malloc(sizeof(struct ipc_client));
if (!client) {
sway_log(L_ERROR, "Unable to allocate ipc client");
wlr_log(L_ERROR, "Unable to allocate ipc client");
close(client_fd);
return 0;
}
@ -166,12 +166,12 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
client->write_buffer_len = 0;
client->write_buffer = malloc(client->write_buffer_size);
if (!client->write_buffer) {
sway_log(L_ERROR, "Unable to allocate ipc client write buffer");
wlr_log(L_ERROR, "Unable to allocate ipc client write buffer");
close(client_fd);
return 0;
}
sway_log(L_DEBUG, "New client: fd %d", client_fd);
wlr_log(L_DEBUG, "New client: fd %d", client_fd);
list_add(ipc_client_list, client);
return 0;
}
@ -182,22 +182,22 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
struct ipc_client *client = data;
if (mask & WL_EVENT_ERROR) {
sway_log(L_ERROR, "IPC Client socket error, removing client");
wlr_log(L_ERROR, "IPC Client socket error, removing client");
ipc_client_disconnect(client);
return 0;
}
if (mask & WL_EVENT_HANGUP) {
sway_log(L_DEBUG, "Client %d hung up", client->fd);
wlr_log(L_DEBUG, "Client %d hung up", client->fd);
ipc_client_disconnect(client);
return 0;
}
sway_log(L_DEBUG, "Client %d readable", client->fd);
wlr_log(L_DEBUG, "Client %d readable", client->fd);
int read_available;
if (ioctl(client_fd, FIONREAD, &read_available) == -1) {
sway_log_errno(L_INFO, "Unable to read IPC socket buffer size");
wlr_log_errno(L_INFO, "Unable to read IPC socket buffer size");
ipc_client_disconnect(client);
return 0;
}
@ -219,13 +219,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
// Should be fully available, because read_available >= ipc_header_size
ssize_t received = recv(client_fd, buf, ipc_header_size, 0);
if (received == -1) {
sway_log_errno(L_INFO, "Unable to receive header from IPC client");
wlr_log_errno(L_INFO, "Unable to receive header from IPC client");
ipc_client_disconnect(client);
return 0;
}
if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) {
sway_log(L_DEBUG, "IPC header check failed");
wlr_log(L_DEBUG, "IPC header check failed");
ipc_client_disconnect(client);
return 0;
}
@ -244,13 +244,13 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
struct ipc_client *client = data;
if (mask & WL_EVENT_ERROR) {
sway_log(L_ERROR, "IPC Client socket error, removing client");
wlr_log(L_ERROR, "IPC Client socket error, removing client");
ipc_client_disconnect(client);
return 0;
}
if (mask & WL_EVENT_HANGUP) {
sway_log(L_DEBUG, "Client %d hung up", client->fd);
wlr_log(L_DEBUG, "Client %d hung up", client->fd);
ipc_client_disconnect(client);
return 0;
}
@ -259,14 +259,14 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
return 0;
}
sway_log(L_DEBUG, "Client %d writable", client->fd);
wlr_log(L_DEBUG, "Client %d writable", client->fd);
ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len);
if (written == -1 && errno == EAGAIN) {
return 0;
} else if (written == -1) {
sway_log_errno(L_INFO, "Unable to send data from queue to IPC client");
wlr_log_errno(L_INFO, "Unable to send data from queue to IPC client");
ipc_client_disconnect(client);
return 0;
}
@ -291,7 +291,7 @@ void ipc_client_disconnect(struct ipc_client *client) {
shutdown(client->fd, SHUT_RDWR);
}
sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
wlr_log(L_INFO, "IPC Client %d disconnected", client->fd);
wl_event_source_remove(client->event_source);
if (client->writable_event_source) {
wl_event_source_remove(client->writable_event_source);
@ -313,7 +313,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
char *buf = malloc(client->payload_length + 1);
if (!buf) {
sway_log_errno(L_INFO, "Unable to allocate IPC payload");
wlr_log_errno(L_INFO, "Unable to allocate IPC payload");
ipc_client_disconnect(client);
return;
}
@ -322,7 +322,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
ssize_t received = recv(client->fd, buf, client->payload_length, 0);
if (received == -1)
{
sway_log_errno(L_INFO, "Unable to receive payload from IPC client");
wlr_log_errno(L_INFO, "Unable to receive payload from IPC client");
ipc_client_disconnect(client);
free(buf);
return;
@ -335,7 +335,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
switch (client->current_command) {
case IPC_COMMAND:
{
struct cmd_results *results = handle_command(buf);
config_clear_handler_context(config);
struct cmd_results *results = execute_command(buf, NULL);
const char *json = cmd_results_to_json(results);
char reply[256];
int length = snprintf(reply, sizeof(reply), "%s", json);
@ -393,12 +394,12 @@ void ipc_client_handle_command(struct ipc_client *client) {
}
default:
sway_log(L_INFO, "Unknown IPC command type %i", client->current_command);
wlr_log(L_INFO, "Unknown IPC command type %i", client->current_command);
goto exit_cleanup;
}
ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied));
sway_log(L_DEBUG, "Denied IPC client access to %i", client->current_command);
wlr_log(L_DEBUG, "Denied IPC client access to %i", client->current_command);
exit_cleanup:
client->payload_length = 0;
@ -422,14 +423,14 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
}
if (client->write_buffer_size > 4e6) { // 4 MB
sway_log(L_ERROR, "Client write buffer too big, disconnecting client");
wlr_log(L_ERROR, "Client write buffer too big, disconnecting client");
ipc_client_disconnect(client);
return false;
}
char *new_buffer = realloc(client->write_buffer, client->write_buffer_size);
if (!new_buffer) {
sway_log(L_ERROR, "Unable to reallocate ipc client write buffer");
wlr_log(L_ERROR, "Unable to reallocate ipc client write buffer");
ipc_client_disconnect(client);
return false;
}
@ -446,6 +447,6 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
ipc_client_handle_writable, client);
}
sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
wlr_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
return true;
}

View file

@ -15,12 +15,12 @@
#include <sys/capability.h>
#include <sys/prctl.h>
#endif
#include <wlr/util/log.h>
#include "sway/config.h"
#include "sway/server.h"
#include "sway/layout.h"
#include "sway/ipc-server.h"
#include "ipc-client.h"
#include "log.h"
#include "readline.h"
#include "stringop.h"
#include "util.h"
@ -126,7 +126,7 @@ static void log_env() {
"SWAYSOCK"
};
for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) {
sway_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
wlr_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
}
}
@ -141,14 +141,14 @@ static void log_distro() {
for (size_t i = 0; i < sizeof(paths) / sizeof(char *); ++i) {
FILE *f = fopen(paths[i], "r");
if (f) {
sway_log(L_INFO, "Contents of %s:", paths[i]);
wlr_log(L_INFO, "Contents of %s:", paths[i]);
while (!feof(f)) {
char *line;
if (!(line = read_line(f))) {
break;
}
if (*line) {
sway_log(L_INFO, "%s", line);
wlr_log(L_INFO, "%s", line);
}
free(line);
}
@ -161,7 +161,7 @@ static void log_kernel() {
return;
FILE *f = popen("uname -a", "r");
if (!f) {
sway_log(L_INFO, "Unable to determine kernel version");
wlr_log(L_INFO, "Unable to determine kernel version");
return;
}
while (!feof(f)) {
@ -170,7 +170,7 @@ static void log_kernel() {
break;
}
if (*line) {
sway_log(L_INFO, "%s", line);
wlr_log(L_INFO, "%s", line);
}
free(line);
}
@ -181,14 +181,14 @@ static void security_sanity_check() {
// TODO: Notify users visually if this has issues
struct stat s;
if (stat("/proc", &s)) {
sway_log(L_ERROR,
wlr_log(L_ERROR,
"!! DANGER !! /proc is not available - sway CANNOT enforce security rules!");
}
#ifdef __linux__
cap_flag_value_t v;
cap_t cap = cap_get_proc();
if (!cap || cap_get_flag(cap, CAP_SYS_PTRACE, CAP_PERMITTED, &v) != 0 || v != CAP_SET) {
sway_log(L_ERROR,
wlr_log(L_ERROR,
"!! DANGER !! Sway does not have CAP_SYS_PTRACE and cannot enforce security rules for processes running as other users.");
}
if (cap) {
@ -204,13 +204,13 @@ static void executable_sanity_check() {
stat(exe, &sb);
// We assume that cap_get_file returning NULL implies ENODATA
if (sb.st_mode & (S_ISUID|S_ISGID) && cap_get_file(exe)) {
sway_log(L_ERROR,
wlr_log(L_ERROR,
"sway executable has both the s(g)uid bit AND file caps set.");
sway_log(L_ERROR,
wlr_log(L_ERROR,
"This is strongly discouraged (and completely broken).");
sway_log(L_ERROR,
wlr_log(L_ERROR,
"Please clear one of them (either the suid bit, or the file caps).");
sway_log(L_ERROR,
wlr_log(L_ERROR,
"If unsure, strip the file caps.");
exit(EXIT_FAILURE);
}
@ -221,16 +221,16 @@ static void executable_sanity_check() {
static void drop_permissions(bool keep_caps) {
if (getuid() != geteuid() || getgid() != getegid()) {
if (setgid(getgid()) != 0) {
sway_log(L_ERROR, "Unable to drop root");
wlr_log(L_ERROR, "Unable to drop root");
exit(EXIT_FAILURE);
}
if (setuid(getuid()) != 0) {
sway_log(L_ERROR, "Unable to drop root");
wlr_log(L_ERROR, "Unable to drop root");
exit(EXIT_FAILURE);
}
}
if (setuid(0) != -1) {
sway_log(L_ERROR, "Root privileges can be restored.");
wlr_log(L_ERROR, "Root privileges can be restored.");
exit(EXIT_FAILURE);
}
#ifdef __linux__
@ -238,11 +238,11 @@ static void drop_permissions(bool keep_caps) {
// Drop every cap except CAP_SYS_PTRACE
cap_t caps = cap_init();
cap_value_t keep = CAP_SYS_PTRACE;
sway_log(L_INFO, "Dropping extra capabilities");
wlr_log(L_INFO, "Dropping extra capabilities");
if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) ||
cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) ||
cap_set_proc(caps)) {
sway_log(L_ERROR, "Failed to drop extra capabilities");
wlr_log(L_ERROR, "Failed to drop extra capabilities");
exit(EXIT_FAILURE);
}
}
@ -330,22 +330,22 @@ int main(int argc, char **argv) {
// TODO: switch logging over to wlroots?
if (debug) {
init_log(L_DEBUG);
wlr_log_init(L_DEBUG, NULL);
} else if (verbose || validate) {
init_log(L_INFO);
wlr_log_init(L_INFO, NULL);
} else {
init_log(L_ERROR);
wlr_log_init(L_ERROR, NULL);
}
if (optind < argc) { // Behave as IPC client
if(optind != 1) {
sway_log(L_ERROR, "Don't use options with the IPC client");
wlr_log(L_ERROR, "Don't use options with the IPC client");
exit(EXIT_FAILURE);
}
drop_permissions(false);
char *socket_path = getenv("SWAYSOCK");
if (!socket_path) {
sway_log(L_ERROR, "Unable to retrieve socket path");
wlr_log(L_ERROR, "Unable to retrieve socket path");
exit(EXIT_FAILURE);
}
char *command = join_args(argv + optind, argc - optind);
@ -359,7 +359,7 @@ int main(int argc, char **argv) {
if (getuid() != geteuid() || getgid() != getegid()) {
// Retain capabilities after setuid()
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
sway_log(L_ERROR, "Cannot keep caps after setuid()");
wlr_log(L_ERROR, "Cannot keep caps after setuid()");
exit(EXIT_FAILURE);
}
suid = true;
@ -380,7 +380,7 @@ int main(int argc, char **argv) {
// prevent ipc from crashing sway
signal(SIGPIPE, SIG_IGN);
sway_log(L_INFO, "Starting sway version " SWAY_VERSION "\n");
wlr_log(L_INFO, "Starting sway version " SWAY_VERSION);
init_layout();
@ -414,6 +414,8 @@ int main(int argc, char **argv) {
server_run(&server);
}
wlr_log(L_INFO, "Shutting down sway");
server_fini(&server);
ipc_terminate();

View file

@ -7,14 +7,19 @@ sway_sources = files(
'input/cursor.c',
'input/keyboard.c',
'commands/backend.c',
'commands/bind.c',
'commands/exit.c',
'commands/exec.c',
'commands/exec_always.c',
'commands/focus.c',
'commands/kill.c',
'commands/include.c',
'commands/input.c',
'commands/layout.c',
'commands/seat.c',
'commands/seat/attach.c',
'commands/seat/fallback.c',
'commands/set.c',
'commands/input/accel_profile.c',
'commands/input/click_method.c',
'commands/input/drag_lock.c',
@ -32,10 +37,13 @@ sway_sources = files(
'commands/input/xkb_rules.c',
'commands/input/xkb_variant.c',
'commands/output.c',
'commands/reload.c',
'commands/workspace.c',
'config.c',
'config/output.c',
'config/seat.c',
'config/input.c',
'criteria.c',
'ipc-json.c',
'ipc-server.c',
'desktop/output.c',
@ -45,10 +53,12 @@ sway_sources = files(
'security.c',
'tree/container.c',
'tree/layout.c',
'tree/view.c',
'tree/workspace.c',
)
sway_deps = [
pcre,
pixman,
wayland_server,
jsonc,

View file

@ -1,510 +0,0 @@
#define _XOPEN_SOURCE 700
#include <wlc/wlc-render.h>
#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <arpa/inet.h>
#include "sway/border.h"
#include "sway/container.h"
#include "sway/config.h"
#include "client/pango.h"
void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
color = htonl(color);
cairo_set_source_rgba(cairo,
(color >> (2*8) & 0xFF) / 255.0,
(color >> (1*8) & 0xFF) / 255.0,
(color >> (0*8) & 0xFF) / 255.0,
(color >> (3*8) & 0xFF) / 255.0);
}
void border_clear(struct border *border) {
if (border && border->buffer) {
free(border->buffer);
border->buffer = NULL;
}
}
static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry g, cairo_surface_t **surface) {
if (view->border == NULL) {
view->border = malloc(sizeof(struct border));
if (!view->border) {
sway_log(L_ERROR, "Unable to allocate window border information");
return NULL;
}
}
cairo_t *cr;
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, g.size.w);
view->border->buffer = calloc(stride * g.size.h, sizeof(unsigned char));
view->border->geometry = g;
if (!view->border->buffer) {
sway_log(L_ERROR, "Unable to allocate window border buffer");
return NULL;
}
*surface = cairo_image_surface_create_for_data(view->border->buffer,
CAIRO_FORMAT_ARGB32, g.size.w, g.size.h, stride);
if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) {
border_clear(view->border);
sway_log(L_ERROR, "Unable to allocate window border surface");
return NULL;
}
cr = cairo_create(*surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy(*surface);
border_clear(view->border);
sway_log(L_ERROR, "Unable to create cairo context");
return NULL;
}
return cr;
}
// TODO: move to client/cairo.h when local set_source_u32 is fixed.
/**
* Renders a sharp line of any width and height.
*
* The line is drawn from (x,y) to (x+width,y+height) where width/height is 0
* if the line has a width/height of one pixel, respectively.
*/
static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) {
cairo_set_source_u32(cairo, color);
if (width > 1 && height > 1) {
cairo_rectangle(cairo, x, y, width, height);
cairo_fill(cairo);
} else {
if (width == 1) {
x += 0.5;
height += y;
width = x;
}
if (height == 1) {
y += 0.5;
width += x;
height = y;
}
cairo_move_to(cairo, x, y);
cairo_set_line_width(cairo, 1.0);
cairo_line_to(cairo, width, height);
cairo_stroke(cairo);
}
}
int get_font_text_height(const char *font) {
cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 200, 200);
cairo_t *cr = cairo_create(surface);
int width, height;
get_text_size(cr, font, &width, &height, 1, false, "Gg");
cairo_surface_destroy(surface);
cairo_destroy(cr);
return height;
}
static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors, bool top) {
struct wlc_geometry *g = &view->border->geometry;
struct wlc_geometry *b = &view->border_geometry;
struct wlc_geometry *v = &view->actual_geometry;
enum swayc_layouts layout = view->parent->layout;
uint32_t color;
int x = b->origin.x - g->origin.x;
int y = b->origin.y - g->origin.y;
// draw vertical/horizontal indicator if container is the only child of its parent container
bool is_only_child = view->parent && view->parent->children && view->parent->children->length == 1;
// left border
int left_border = v->origin.x - b->origin.x;
if (left_border > 0) {
render_sharp_line(cr,
colors->child_border,
x, y,
left_border,
b->size.h);
}
// right border
int right_border = b->size.w - v->size.w - left_border;
if (right_border > 0) {
if (is_only_child && layout == L_HORIZ && !view->is_floating) {
color = colors->indicator;
} else {
color = colors->child_border;
}
render_sharp_line(cr,
color,
x + b->size.w - right_border,
y,
right_border,
b->size.h);
}
// top border
int top_border = v->origin.y - b->origin.y;
if (top && top_border > 0) {
render_sharp_line(cr,
colors->child_border,
x, y,
b->size.w,
top_border);
}
// bottom border
int bottom_border = b->size.h - (top_border + v->size.h);
if (bottom_border > 0) {
if (is_only_child && layout == L_VERT && !view->is_floating) {
color = colors->indicator;
} else {
color = colors->child_border;
}
render_sharp_line(cr,
color,
x,
y + b->size.h - bottom_border,
b->size.w,
bottom_border);
}
}
static void render_title_bar(swayc_t *view, cairo_t *cr, struct wlc_geometry *b, struct border_colors *colors) {
struct wlc_geometry *tb = &view->title_bar_geometry;
int x = MIN(tb->origin.x, tb->origin.x - b->origin.x);
int y = MIN(tb->origin.y, tb->origin.y - b->origin.y);
// title bar background
cairo_set_source_u32(cr, colors->background);
cairo_rectangle(cr, x, y, tb->size.w, tb->size.h);
cairo_fill(cr);
// header top line
render_sharp_line(cr, colors->border, x, y, tb->size.w, 1);
// text
if (view->name) {
int width, height;
get_text_size(cr, config->font, &width, &height, 1, false, "%s", view->name);
cairo_move_to(cr, x + 2, y + 2);
cairo_set_source_u32(cr, colors->text);
pango_printf(cr, config->font, 1, false, "%s", view->name);
}
// Marks
if (config->show_marks && view->marks) {
int total_len = 0;
for(int i = view->marks->length - 1; i >= 0; --i) {
char *mark = (char *)view->marks->items[i];
if (*mark != '_') {
int width, height;
get_text_size(cr, config->font, &width, &height, 1, false, "[%s]", mark);
total_len += width;
if ((int)tb->size.w + x - (total_len + 2) < x + 2) {
break;
} else {
cairo_move_to(cr, (int)tb->size.w + x - (total_len + 2), y + 2);
cairo_set_source_u32(cr, colors->text);
pango_printf(cr, config->font, 1, false, "[%s]", mark);
}
}
}
}
// titlebars has a border all around for tabbed layouts
if (view->parent->layout == L_TABBED) {
// header bottom line
render_sharp_line(cr, colors->border, x, y + tb->size.h - 1,
tb->size.w, 1);
// left border
render_sharp_line(cr, colors->border, x, y, 1, tb->size.h);
// right border
render_sharp_line(cr, colors->border, x + tb->size.w - 1, y,
1, tb->size.h);
return;
}
if ((uint32_t)(view->actual_geometry.origin.y - tb->origin.y) == tb->size.h) {
// header bottom line
render_sharp_line(cr, colors->border,
x + view->actual_geometry.origin.x - tb->origin.x,
y + tb->size.h - 1,
view->actual_geometry.size.w, 1);
} else {
// header bottom line
render_sharp_line(cr, colors->border, x,
y + tb->size.h - 1,
tb->size.w, 1);
}
}
/**
* Generate nested container title for tabbed/stacked layouts
*/
static char *generate_container_title(swayc_t *container) {
char layout = 'H';
char *name, *prev_name = NULL;
switch (container->layout) {
case L_TABBED:
layout = 'T';
break;
case L_STACKED:
layout = 'S';
break;
case L_VERT:
layout = 'V';
break;
default:
layout = 'H';
}
int len = 9;
name = malloc(len * sizeof(char));
if (!name) {
sway_log(L_ERROR, "Unable to allocate container title");
return NULL;
}
snprintf(name, len, "sway: %c[", layout);
int i;
for (i = 0; i < container->children->length; ++i) {
prev_name = name;
swayc_t* child = container->children->items[i];
const char *title = NULL;
if (child->type == C_VIEW) {
title = child->app_id ? child->app_id :
(child->instance ? child->instance :
(child->class ? child->class :"(null)"));
} else { //child->type == C_CONTAINER
title = generate_container_title(child);
}
len = strlen(name) + strlen(title) + 1;
if (i < container->children->length-1) {
len++;
}
name = malloc(len * sizeof(char));
if (!name) {
free(prev_name);
sway_log(L_ERROR, "Unable to allocate container title");
return NULL;
}
if (i < container->children->length-1) {
snprintf(name, len, "%s%s ", prev_name, title);
} else {
snprintf(name, len, "%s%s", prev_name, title);
}
free(prev_name);
}
prev_name = name;
len = strlen(name) + 2;
name = malloc(len * sizeof(char));
if (!name) {
free(prev_name);
sway_log(L_ERROR, "Unable to allocate container title");
return NULL;
}
snprintf(name, len, "%s]", prev_name);
free(prev_name);
free(container->name);
container->name = name;
return container->name + 6; // don't include "sway: "
}
void update_tabbed_stacked_titlebars(swayc_t *c, cairo_t *cr, struct wlc_geometry *g, swayc_t *focused, swayc_t *focused_inactive) {
if (c->type == C_CONTAINER) {
if (c->parent->focused == c) {
render_title_bar(c, cr, g, &config->border_colors.focused_inactive);
} else {
render_title_bar(c, cr, g, &config->border_colors.unfocused);
}
if (!c->visible) {
return;
}
int i;
for (i = 0; i < c->children->length; ++i) {
swayc_t *child = c->children->items[i];
update_tabbed_stacked_titlebars(child, cr, g, focused, focused_inactive);
}
} else {
bool is_child_of_focused = swayc_is_child_of(c, get_focused_container(&root_container));
if (focused == c || is_child_of_focused) {
render_title_bar(c, cr, g, &config->border_colors.focused);
} else if (focused_inactive == c) {
render_title_bar(c, cr, g, &config->border_colors.focused_inactive);
} else {
render_title_bar(c, cr, g, &config->border_colors.unfocused);
}
}
}
static void update_view_border(swayc_t *view) {
if (!view->visible) {
return;
}
cairo_t *cr = NULL;
cairo_surface_t *surface = NULL;
// clear previous border buffer.
border_clear(view->border);
// get focused and focused_inactive views
swayc_t *focused = get_focused_view(&root_container);
swayc_t *container = swayc_parent_by_type(view, C_CONTAINER);
swayc_t *focused_inactive = NULL;
bool is_child_of_focused = swayc_is_parent_of(get_focused_container(&root_container), view);
if (container) {
focused_inactive = swayc_focus_by_type(container, C_VIEW);
} else {
container = swayc_parent_by_type(view, C_WORKSPACE);
if (container) {
focused_inactive = swayc_focus_by_type(container, C_VIEW);
}
}
// for tabbed/stacked layouts the focused view has to draw all the
// titlebars of the hidden views.
swayc_t *p = NULL;
if (view->parent->focused == view && (p = swayc_tabbed_stacked_ancestor(view))) {
struct wlc_geometry g = {
.origin = {
.x = p->x,
.y = p->y
},
.size = {
.w = p->width,
.h = p->height
}
};
cr = create_border_buffer(view, g, &surface);
if (!cr) {
goto cleanup;
}
bool render_top = !should_hide_top_border(view, view->y);
if (view == focused || is_child_of_focused) {
render_borders(view, cr, &config->border_colors.focused, render_top);
} else {
render_borders(view, cr, &config->border_colors.focused_inactive, render_top);
}
// generate container titles
int i;
for (i = 0; i < p->children->length; ++i) {
swayc_t *child = p->children->items[i];
if (child->type == C_CONTAINER) {
generate_container_title(child);
}
}
update_tabbed_stacked_titlebars(p, cr, &g, focused, focused_inactive);
} else {
switch (view->border_type) {
case B_NONE:
break;
case B_PIXEL:
cr = create_border_buffer(view, view->border_geometry, &surface);
if (!cr) {
break;
}
if (focused == view || is_child_of_focused) {
render_borders(view, cr, &config->border_colors.focused, true);
} else if (focused_inactive == view) {
render_borders(view, cr, &config->border_colors.focused_inactive, true);
} else {
render_borders(view, cr, &config->border_colors.unfocused, true);
}
break;
case B_NORMAL:
cr = create_border_buffer(view, view->border_geometry, &surface);
if (!cr) {
break;
}
if (focused == view || is_child_of_focused) {
render_borders(view, cr, &config->border_colors.focused, false);
render_title_bar(view, cr, &view->border_geometry,
&config->border_colors.focused);
} else if (focused_inactive == view) {
render_borders(view, cr, &config->border_colors.focused_inactive, false);
render_title_bar(view, cr, &view->border_geometry,
&config->border_colors.focused_inactive);
} else {
render_borders(view, cr, &config->border_colors.unfocused, false);
render_title_bar(view, cr, &view->border_geometry,
&config->border_colors.unfocused);
}
break;
}
}
cleanup:
if (surface) {
cairo_surface_flush(surface);
cairo_surface_destroy(surface);
}
if (cr) {
cairo_destroy(cr);
}
}
void update_container_border(swayc_t *container) {
if (container->type == C_VIEW) {
update_view_border(container);
return;
} else {
for (int i = 0; i < container->children->length; ++i) {
update_container_border(container->children->items[i]);
}
}
}
void render_view_borders(wlc_handle view) {
swayc_t *c = swayc_by_handle(view);
// emulate i3 behavior for drawing borders for tabbed and stacked layouts:
// if we are not the only child in the container, always draw borders,
// regardless of the border setting on the individual view
if (!c || (c->border_type == B_NONE
&& !((c->parent->layout == L_TABBED || c->parent->layout == L_STACKED)
&& c->parent->children->length > 1))) {
return;
}
if (c->border && c->border->buffer) {
wlc_pixels_write(WLC_RGBA8888, &c->border->geometry, c->border->buffer);
}
}
bool should_hide_top_border(swayc_t *con, double y) {
// returns true if container is child of tabbed/stacked layout and is
// sharing top border with tabbed titlebar
swayc_t *par = con->parent;
while (par->type != C_WORKSPACE) {
if (par->layout == L_TABBED || par->layout == L_STACKED) {
return con->y == y;
}
con = par;
par = par->parent;
}
return false;
}

View file

@ -1,686 +0,0 @@
#define _XOPEN_SOURCE 700
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-names.h>
#include <wlc/wlc.h>
#include <wlc/wlc-render.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <ctype.h>
#include <wordexp.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <limits.h>
#include <float.h>
#include <libinput.h>
#include "sway/layout.h"
#include "sway/focus.h"
#include "sway/workspace.h"
#include "sway/commands.h"
#include "sway/container.h"
#include "sway/output.h"
#include "sway/handlers.h"
#include "sway/input_state.h"
#include "sway/criteria.h"
#include "sway/ipc-server.h"
#include "sway/security.h"
#include "sway/input.h"
#include "sway/border.h"
#include "stringop.h"
#include "sway.h"
#include "util.h"
#include "list.h"
#include "log.h"
struct cmd_handler {
char *command;
sway_cmd *handle;
};
int sp_index = 0;
swayc_t *current_container = NULL;
// Returns error object, or NULL if check succeeds.
struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) {
struct cmd_results *error = NULL;
switch (type) {
case EXPECTED_MORE_THAN:
if (argc > val) {
return NULL;
}
error = cmd_results_new(CMD_INVALID, name, "Invalid %s command "
"(expected more than %d argument%s, got %d)",
name, val, (char*[2]){"s", ""}[argc==1], argc);
break;
case EXPECTED_AT_LEAST:
if (argc >= val) {
return NULL;
}
error = cmd_results_new(CMD_INVALID, name, "Invalid %s command "
"(expected at least %d argument%s, got %d)",
name, val, (char*[2]){"s", ""}[argc==1], argc);
break;
case EXPECTED_LESS_THAN:
if (argc < val) {
return NULL;
};
error = cmd_results_new(CMD_INVALID, name, "Invalid %s command "
"(expected less than %d argument%s, got %d)",
name, val, (char*[2]){"s", ""}[argc==1], argc);
break;
case EXPECTED_EQUAL_TO:
if (argc == val) {
return NULL;
};
error = cmd_results_new(CMD_INVALID, name, "Invalid %s command "
"(expected %d arguments, got %d)", name, val, argc);
break;
}
return error;
}
void hide_view_in_scratchpad(swayc_t *sp_view) {
if (sp_view == NULL) {
return;
}
wlc_view_set_mask(sp_view->handle, 0);
sp_view->visible = false;
swayc_t *ws = sp_view->parent;
remove_child(sp_view);
if (swayc_active_workspace() != ws && ws->floating->length == 0 && ws->children->length == 0) {
destroy_workspace(ws);
} else {
arrange_windows(ws, -1, -1);
}
set_focused_container(container_under_pointer());
}
void input_cmd_apply(struct input_config *input) {
int i;
i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier);
if (i >= 0) {
// merge existing config
struct input_config *ic = config->input_configs->items[i];
merge_input_config(ic, input);
free_input_config(input);
input = ic;
} else {
list_add(config->input_configs, input);
}
current_input_config = input;
if (input->identifier) {
// Try to find the input device and apply configuration now. If
// this is during startup then there will be no container and config
// will be applied during normal "new input" event from wlc.
/* TODO WLR
struct libinput_device *device = NULL;
for (int i = 0; i < input_devices->length; ++i) {
device = input_devices->items[i];
char* dev_identifier = libinput_dev_unique_id(device);
if (!dev_identifier) {
break;
}
int match = dev_identifier && strcmp(dev_identifier, input->identifier) == 0;
free(dev_identifier);
if (match) {
apply_input_config(input, device);
break;
}
}
*/
}
}
void remove_view_from_scratchpad(swayc_t *view) {
int i;
for (i = 0; i < scratchpad->length; i++) {
if (scratchpad->items[i] == view) {
if (sp_index == 0) {
sp_index = scratchpad->length - 1;
} else {
sp_index--;
}
list_del(scratchpad, sp_index);
sp_view = NULL;
}
}
}
/* Keep alphabetized */
static struct cmd_handler handlers[] = {
{ "assign", cmd_assign },
{ "bar", cmd_bar },
{ "bindcode", cmd_bindcode },
{ "bindsym", cmd_bindsym },
{ "border", cmd_border },
{ "client.background", cmd_client_background },
{ "client.focused", cmd_client_focused },
{ "client.focused_inactive", cmd_client_focused_inactive },
{ "client.placeholder", cmd_client_placeholder },
{ "client.unfocused", cmd_client_unfocused },
{ "client.urgent", cmd_client_urgent },
{ "clipboard", cmd_clipboard },
{ "commands", cmd_commands },
{ "debuglog", cmd_debuglog },
{ "default_border", cmd_default_border },
{ "default_floating_border", cmd_default_floating_border },
{ "default_orientation", cmd_orientation },
{ "exec", cmd_exec },
{ "exec_always", cmd_exec_always },
{ "exit", cmd_exit },
{ "floating", cmd_floating },
{ "floating_maximum_size", cmd_floating_maximum_size },
{ "floating_minimum_size", cmd_floating_minimum_size },
{ "floating_modifier", cmd_floating_mod },
{ "floating_scroll", cmd_floating_scroll },
{ "focus", cmd_focus },
{ "focus_follows_mouse", cmd_focus_follows_mouse },
{ "font", cmd_font },
{ "for_window", cmd_for_window },
{ "force_focus_wrapping", cmd_force_focus_wrapping },
{ "fullscreen", cmd_fullscreen },
{ "gaps", cmd_gaps },
{ "hide_edge_borders", cmd_hide_edge_borders },
{ "include", cmd_include },
{ "input", cmd_input },
{ "ipc", cmd_ipc },
{ "kill", cmd_kill },
{ "layout", cmd_layout },
{ "log_colors", cmd_log_colors },
{ "mark", cmd_mark },
{ "mode", cmd_mode },
{ "mouse_warping", cmd_mouse_warping },
{ "move", cmd_move },
{ "new_float", cmd_new_float },
{ "new_window", cmd_new_window },
{ "no_focus", cmd_no_focus },
{ "output", cmd_output },
{ "permit", cmd_permit },
{ "reject", cmd_reject },
{ "reload", cmd_reload },
{ "resize", cmd_resize },
{ "scratchpad", cmd_scratchpad },
{ "seamless_mouse", cmd_seamless_mouse },
{ "set", cmd_set },
{ "show_marks", cmd_show_marks },
{ "smart_gaps", cmd_smart_gaps },
{ "split", cmd_split },
{ "splith", cmd_splith },
{ "splitt", cmd_splitt },
{ "splitv", cmd_splitv },
{ "sticky", cmd_sticky },
{ "unmark", cmd_unmark },
{ "workspace", cmd_workspace },
{ "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth },
{ "workspace_layout", cmd_workspace_layout },
};
static struct cmd_handler bar_handlers[] = {
{ "activate_button", bar_cmd_activate_button },
{ "binding_mode_indicator", bar_cmd_binding_mode_indicator },
{ "bindsym", bar_cmd_bindsym },
{ "colors", bar_cmd_colors },
{ "context_button", bar_cmd_context_button },
{ "font", bar_cmd_font },
{ "height", bar_cmd_height },
{ "hidden_state", bar_cmd_hidden_state },
{ "icon_theme", bar_cmd_icon_theme },
{ "id", bar_cmd_id },
{ "mode", bar_cmd_mode },
{ "modifier", bar_cmd_modifier },
{ "output", bar_cmd_output },
{ "pango_markup", bar_cmd_pango_markup },
{ "position", bar_cmd_position },
{ "secondary_button", bar_cmd_secondary_button },
{ "separator_symbol", bar_cmd_separator_symbol },
{ "status_command", bar_cmd_status_command },
{ "strip_workspace_numbers", bar_cmd_strip_workspace_numbers },
{ "swaybar_command", bar_cmd_swaybar_command },
{ "tray_output", bar_cmd_tray_output },
{ "tray_padding", bar_cmd_tray_padding },
{ "workspace_buttons", bar_cmd_workspace_buttons },
{ "wrap_scroll", bar_cmd_wrap_scroll },
};
/**
* Check and add color to buffer.
*
* return error object, or NULL if color is valid.
*/
struct cmd_results *add_color(const char *name, char *buffer, const char *color) {
int len = strlen(color);
if (len != 7 && len != 9) {
return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color);
}
if (color[0] != '#') {
return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color);
}
int i;
for (i = 1; i < len; ++i) {
if (!isxdigit(color[i])) {
return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color);
}
}
// copy color to buffer
strncpy(buffer, color, len);
// add default alpha channel if color was defined without it
if (len == 7) {
buffer[7] = 'f';
buffer[8] = 'f';
}
buffer[9] = '\0';
return NULL;
}
static struct cmd_handler input_handlers[] = {
{ "accel_profile", input_cmd_accel_profile },
{ "click_method", input_cmd_click_method },
{ "drag_lock", input_cmd_drag_lock },
{ "dwt", input_cmd_dwt },
{ "events", input_cmd_events },
{ "left_handed", input_cmd_left_handed },
{ "middle_emulation", input_cmd_middle_emulation },
{ "natural_scroll", input_cmd_natural_scroll },
{ "pointer_accel", input_cmd_pointer_accel },
{ "scroll_method", input_cmd_scroll_method },
{ "tap", input_cmd_tap },
};
static struct cmd_handler bar_colors_handlers[] = {
{ "active_workspace", bar_colors_cmd_active_workspace },
{ "background", bar_colors_cmd_background },
{ "binding_mode", bar_colors_cmd_binding_mode },
{ "focused_background", bar_colors_cmd_focused_background },
{ "focused_separator", bar_colors_cmd_focused_separator },
{ "focused_statusline", bar_colors_cmd_focused_statusline },
{ "focused_workspace", bar_colors_cmd_focused_workspace },
{ "inactive_workspace", bar_colors_cmd_inactive_workspace },
{ "separator", bar_colors_cmd_separator },
{ "statusline", bar_colors_cmd_statusline },
{ "urgent_workspace", bar_colors_cmd_urgent_workspace },
};
static struct cmd_handler ipc_handlers[] = {
{ "*", cmd_ipc_cmd },
{ "bar-config", cmd_ipc_cmd },
{ "command", cmd_ipc_cmd },
{ "events", cmd_ipc_events },
{ "inputs", cmd_ipc_cmd },
{ "marks", cmd_ipc_cmd },
{ "outputs", cmd_ipc_cmd },
{ "tree", cmd_ipc_cmd },
{ "workspaces", cmd_ipc_cmd },
};
static struct cmd_handler ipc_event_handlers[] = {
{ "*", cmd_ipc_event_cmd },
{ "binding", cmd_ipc_event_cmd },
{ "input", cmd_ipc_event_cmd },
{ "mode", cmd_ipc_event_cmd },
{ "output", cmd_ipc_event_cmd },
{ "window", cmd_ipc_event_cmd },
{ "workspace", cmd_ipc_event_cmd },
};
static int handler_compare(const void *_a, const void *_b) {
const struct cmd_handler *a = _a;
const struct cmd_handler *b = _b;
return strcasecmp(a->command, b->command);
}
static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
struct cmd_handler d = { .command=line };
struct cmd_handler *res = NULL;
sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT);
if (block == CMD_BLOCK_BAR) {
res = bsearch(&d, bar_handlers,
sizeof(bar_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
} else if (block == CMD_BLOCK_BAR_COLORS){
res = bsearch(&d, bar_colors_handlers,
sizeof(bar_colors_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
} else if (block == CMD_BLOCK_INPUT) {
res = bsearch(&d, input_handlers,
sizeof(input_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
} else if (block == CMD_BLOCK_IPC) {
res = bsearch(&d, ipc_handlers,
sizeof(ipc_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
} else if (block == CMD_BLOCK_IPC_EVENTS) {
res = bsearch(&d, ipc_event_handlers,
sizeof(ipc_event_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
} else {
res = bsearch(&d, handlers,
sizeof(handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
}
return res;
}
struct cmd_results *handle_command(char *_exec, enum command_context context) {
// Even though this function will process multiple commands we will only
// return the last error, if any (for now). (Since we have access to an
// error string we could e.g. concatonate all errors there.)
struct cmd_results *results = NULL;
char *exec = strdup(_exec);
char *head = exec;
char *cmdlist;
char *cmd;
list_t *containers = NULL;
head = exec;
do {
// Extract criteria (valid for this command list only).
if (*head == '[') {
++head;
char *criteria_string = argsep(&head, "]");
if (head) {
++head;
list_t *tokens = create_list();
char *error;
if ((error = extract_crit_tokens(tokens, criteria_string))) {
results = cmd_results_new(CMD_INVALID, criteria_string,
"Can't parse criteria string: %s", error);
free(error);
free(tokens);
goto cleanup;
}
containers = container_for(tokens);
free(tokens);
} else {
if (!results) {
results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched [");
}
goto cleanup;
}
// Skip leading whitespace
head += strspn(head, whitespace);
}
// Split command list
cmdlist = argsep(&head, ";");
cmdlist += strspn(cmdlist, whitespace);
do {
// Split commands
cmd = argsep(&cmdlist, ",");
cmd += strspn(cmd, whitespace);
if (strcmp(cmd, "") == 0) {
sway_log(L_INFO, "Ignoring empty command.");
continue;
}
sway_log(L_INFO, "Handling command '%s'", cmd);
//TODO better handling of argv
int argc;
char **argv = split_args(cmd, &argc);
if (strcmp(argv[0], "exec") != 0) {
int i;
for (i = 1; i < argc; ++i) {
if (*argv[i] == '\"' || *argv[i] == '\'') {
strip_quotes(argv[i]);
}
}
}
struct cmd_handler *handler = find_handler(argv[0], CMD_BLOCK_END);
if (!handler) {
if (results) {
free_cmd_results(results);
}
results = cmd_results_new(CMD_INVALID, cmd, "Unknown/invalid command");
free_argv(argc, argv);
goto cleanup;
}
if (!(get_command_policy_mask(argv[0]) & context)) {
if (results) {
free_cmd_results(results);
}
results = cmd_results_new(CMD_INVALID, cmd,
"Permission denied for %s via %s", cmd,
command_policy_str(context));
free_argv(argc, argv);
goto cleanup;
}
int i = 0;
do {
if (!containers) {
current_container = get_focused_container(&root_container);
} else if (containers->length == 0) {
if (results) {
free_cmd_results(results);
}
results = cmd_results_new(CMD_FAILURE, argv[0], "No matching container");
goto cleanup;
} else {
current_container = (swayc_t *)containers->items[i];
}
sway_log(L_INFO, "Running on container '%s'", current_container->name);
struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status != CMD_SUCCESS) {
free_argv(argc, argv);
if (results) {
free_cmd_results(results);
}
results = res;
goto cleanup;
}
free_cmd_results(res);
++i;
} while(containers && i < containers->length);
free_argv(argc, argv);
} while(cmdlist);
if (containers) {
list_free(containers);
containers = NULL;
}
} while(head);
cleanup:
free(exec);
if (containers) {
free(containers);
}
if (!results) {
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
return results;
}
// this is like handle_command above, except:
// 1) it ignores empty commands (empty lines)
// 2) it does variable substitution
// 3) it doesn't split commands (because the multiple commands are supposed to
// be chained together)
// 4) handle_command handles all state internally while config_command has some
// state handled outside (notably the block mode, in read_config)
struct cmd_results *config_command(char *exec, enum cmd_status block) {
struct cmd_results *results = NULL;
int argc;
char **argv = split_args(exec, &argc);
if (!argc) {
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
goto cleanup;
}
sway_log(L_INFO, "handling config command '%s'", exec);
// Endblock
if (**argv == '}') {
results = cmd_results_new(CMD_BLOCK_END, NULL, NULL);
goto cleanup;
}
struct cmd_handler *handler = find_handler(argv[0], block);
if (!handler) {
char *input = argv[0] ? argv[0] : "(empty)";
results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
goto cleanup;
}
int i;
// Var replacement, for all but first argument of set
for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
argv[i] = do_var_replacement(argv[i]);
unescape_string(argv[i]);
}
/* Strip quotes for first argument.
* TODO This part needs to be handled much better */
if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
strip_quotes(argv[1]);
}
if (handler->handle) {
results = handler->handle(argc-1, argv+1);
} else {
results = cmd_results_new(CMD_INVALID, argv[0], "This command is shimmed, but unimplemented");
}
cleanup:
free_argv(argc, argv);
return results;
}
struct cmd_results *config_commands_command(char *exec) {
struct cmd_results *results = NULL;
int argc;
char **argv = split_args(exec, &argc);
if (!argc) {
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
goto cleanup;
}
// Find handler for the command this is setting a policy for
char *cmd = argv[0];
if (strcmp(cmd, "}") == 0) {
results = cmd_results_new(CMD_BLOCK_END, NULL, NULL);
goto cleanup;
}
struct cmd_handler *handler = find_handler(cmd, CMD_BLOCK_END);
if (!handler && strcmp(cmd, "*") != 0) {
char *input = cmd ? cmd : "(empty)";
results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
goto cleanup;
}
enum command_context context = 0;
struct {
char *name;
enum command_context context;
} context_names[] = {
{ "config", CONTEXT_CONFIG },
{ "binding", CONTEXT_BINDING },
{ "ipc", CONTEXT_IPC },
{ "criteria", CONTEXT_CRITERIA },
{ "all", CONTEXT_ALL },
};
for (int i = 1; i < argc; ++i) {
size_t j;
for (j = 0; j < sizeof(context_names) / sizeof(context_names[0]); ++j) {
if (strcmp(context_names[j].name, argv[i]) == 0) {
break;
}
}
if (j == sizeof(context_names) / sizeof(context_names[0])) {
results = cmd_results_new(CMD_INVALID, cmd,
"Invalid command context %s", argv[i]);
goto cleanup;
}
context |= context_names[j].context;
}
struct command_policy *policy = NULL;
for (int i = 0; i < config->command_policies->length; ++i) {
struct command_policy *p = config->command_policies->items[i];
if (strcmp(p->command, cmd) == 0) {
policy = p;
break;
}
}
if (!policy) {
policy = alloc_command_policy(cmd);
sway_assert(policy, "Unable to allocate security policy");
if (policy) {
list_add(config->command_policies, policy);
}
}
policy->context = context;
sway_log(L_INFO, "Set command policy for %s to %d",
policy->command, policy->context);
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
cleanup:
free_argv(argc, argv);
return results;
}
struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, const char *format, ...) {
struct cmd_results *results = malloc(sizeof(struct cmd_results));
if (!results) {
sway_log(L_ERROR, "Unable to allocate command results");
return NULL;
}
results->status = status;
if (input) {
results->input = strdup(input); // input is the command name
} else {
results->input = NULL;
}
if (format) {
char *error = malloc(256);
va_list args;
va_start(args, format);
if (error) {
vsnprintf(error, 256, format, args);
}
va_end(args);
results->error = error;
} else {
results->error = NULL;
}
return results;
}
void free_cmd_results(struct cmd_results *results) {
if (results->input) {
free(results->input);
}
if (results->error) {
free(results->error);
}
free(results);
}
const char *cmd_results_to_json(struct cmd_results *results) {
json_object *result_array = json_object_new_array();
json_object *root = json_object_new_object();
json_object_object_add(root, "success", json_object_new_boolean(results->status == CMD_SUCCESS));
if (results->input) {
json_object_object_add(root, "input", json_object_new_string(results->input));
}
if (results->error) {
json_object_object_add(root, "error", json_object_new_string(results->error));
}
json_object_array_add(result_array, root);
const char *json = json_object_to_json_string(result_array);
free(result_array);
free(root);
return json;
}

View file

@ -1,57 +0,0 @@
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <string.h>
#include "sway/commands.h"
#include "sway/criteria.h"
#include "list.h"
#include "log.h"
struct cmd_results *cmd_assign(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "assign", EXPECTED_AT_LEAST, 2))) {
return error;
}
char *criteria = *argv++;
if (strncmp(*argv, "", strlen("")) == 0) {
if (argc < 3) {
return cmd_results_new(CMD_INVALID, "assign", "Missing workspace");
}
argv++;
}
char *movecmd = "move container to workspace ";
int arglen = strlen(movecmd) + strlen(*argv) + 1;
char *cmdlist = calloc(1, arglen);
if (!cmdlist) {
return cmd_results_new(CMD_FAILURE, "assign", "Unable to allocate command list");
}
snprintf(cmdlist, arglen, "%s%s", movecmd, *argv);
struct criteria *crit = malloc(sizeof(struct criteria));
if (!crit) {
free(cmdlist);
return cmd_results_new(CMD_FAILURE, "assign", "Unable to allocate criteria");
}
crit->crit_raw = strdup(criteria);
crit->cmdlist = cmdlist;
crit->tokens = create_list();
char *err_str = extract_crit_tokens(crit->tokens, crit->crit_raw);
if (err_str) {
error = cmd_results_new(CMD_INVALID, "assign", err_str);
free(err_str);
free_criteria(crit);
} else if (crit->tokens->length == 0) {
error = cmd_results_new(CMD_INVALID, "assign", "Found no name/value pairs in criteria");
free_criteria(crit);
} else if (list_seq_find(config->criteria, criteria_cmp, crit) != -1) {
sway_log(L_DEBUG, "assign: Duplicate, skipping.");
free_criteria(crit);
} else {
sway_log(L_DEBUG, "assign: '%s' -> '%s' added", crit->crit_raw, crit->cmdlist);
list_add(config->criteria, crit);
}
return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,59 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "log.h"
#include "util.h"
struct cmd_results *cmd_bar(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) {
return error;
}
if (config->reading && strcmp("{", argv[0]) != 0) {
return cmd_results_new(CMD_INVALID, "bar",
"Expected '{' at start of bar config definition.");
}
if (!config->reading) {
if (argc > 1) {
if (strcasecmp("mode", argv[0]) == 0) {
return bar_cmd_mode(argc-1, argv + 1);
}
if (strcasecmp("hidden_state", argv[0]) == 0) {
return bar_cmd_hidden_state(argc-1, argv + 1);
}
}
return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file.");
}
// Create new bar with default values
struct bar_config *bar = default_bar_config();
if (!bar) {
return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar state");
}
// set bar id
int i;
for (i = 0; i < config->bars->length; ++i) {
if (bar == config->bars->items[i]) {
const int len = 5 + numlen(i); // "bar-" + i + \0
bar->id = malloc(len * sizeof(char));
if (bar->id) {
snprintf(bar->id, len, "bar-%d", i);
} else {
return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar ID");
}
break;
}
}
// Set current bar
config->current_bar = bar;
sway_log(L_DEBUG, "Configuring bar %s", bar->id);
return cmd_results_new(CMD_BLOCK_BAR, NULL, NULL);
}

View file

@ -1,26 +0,0 @@
#include <stdlib.h>
#include "sway/commands.h"
#include "log.h"
struct cmd_results *bar_cmd_activate_button(int argc, char **argv) {
const char *cmd_name = "activate_button";
#ifndef ENABLE_TRAY
return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command "
"%s called, but sway was compiled without tray support",
cmd_name, cmd_name);
#else
struct cmd_results *error = NULL;
if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined.");
}
// User should be able to prefix with 0x or whatever they want
config->current_bar->secondary_button = strtoul(argv[0], NULL, 0);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
#endif
}

View file

@ -1,27 +0,0 @@
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "log.h"
struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "binding_mode_indicator", EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, "binding_mode_indicator", "No bar defined.");
}
if (strcasecmp("yes", argv[0]) == 0) {
config->current_bar->binding_mode_indicator = true;
sway_log(L_DEBUG, "Enabling binding mode indicator on bar: %s", config->current_bar->id);
} else if (strcasecmp("no", argv[0]) == 0) {
config->current_bar->binding_mode_indicator = false;
sway_log(L_DEBUG, "Disabling binding mode indicator on bar: %s", config->current_bar->id);
} else {
error = cmd_results_new(CMD_INVALID, "binding_mode_indicator", "Invalid value %s", argv[0]);
return error;
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,48 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "list.h"
#include "log.h"
#include "stringop.h"
struct cmd_results *bar_cmd_bindsym(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) {
return error;
} else if (!config->reading) {
return cmd_results_new(CMD_FAILURE, "bindsym", "Can only be used in config file.");
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, "bindsym", "No bar defined.");
}
if (strlen(argv[1]) != 7) {
return cmd_results_new(CMD_INVALID, "bindsym", "Invalid mouse binding %s", argv[1]);
}
uint32_t numbutton = (uint32_t)atoi(argv[1] + 6);
if (numbutton < 1 || numbutton > 5 || strncmp(argv[1], "button", 6) != 0) {
return cmd_results_new(CMD_INVALID, "bindsym", "Invalid mouse binding %s", argv[1]);
}
struct sway_mouse_binding *binding = malloc(sizeof(struct sway_mouse_binding));
if (!binding) {
return cmd_results_new(CMD_FAILURE, "bindsym", "Unable to allocate binding");
}
binding->button = numbutton;
binding->command = join_args(argv + 1, argc - 1);
struct bar_config *bar = config->current_bar;
int i = list_seq_find(bar->bindings, sway_mouse_binding_cmp_buttons, binding);
if (i > -1) {
sway_log(L_DEBUG, "bindsym - '%s' for swaybar already exists, overwriting", argv[0]);
struct sway_mouse_binding *dup = bar->bindings->items[i];
free_sway_mouse_binding(dup);
list_del(bar->bindings, i);
}
list_add(bar->bindings, binding);
list_qsort(bar->bindings, sway_mouse_binding_cmp_qsort);
sway_log(L_DEBUG, "bindsym - Bound %s to command %s when clicking swaybar", argv[0], binding->command);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,129 +0,0 @@
#include <string.h>
#include "sway/commands.h"
static struct cmd_results *parse_single_color(char **color, const char *cmd_name, int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!*color) {
*color = malloc(10);
if (!*color) {
return cmd_results_new(CMD_FAILURE, cmd_name, "Unable to allocate color");
}
}
error = add_color(cmd_name, *color, argv[0]);
if (error) {
return error;
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
static struct cmd_results *parse_three_colors(char ***colors, const char *cmd_name, int argc, char **argv) {
struct cmd_results *error = NULL;
if (argc != 3) {
return cmd_results_new(CMD_INVALID, cmd_name, "Requires exactly three color values");
}
int i;
for (i = 0; i < 3; i++) {
if (!*colors[i]) {
*(colors[i]) = malloc(10);
if (!*(colors[i])) {
return cmd_results_new(CMD_FAILURE, cmd_name, "Unable to allocate color");
}
}
error = add_color(cmd_name, *(colors[i]), argv[i]);
if (error) {
return error;
}
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
struct cmd_results *bar_cmd_colors(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "colors", EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (strcmp("{", argv[0]) != 0) {
return cmd_results_new(CMD_INVALID, "colors",
"Expected '{' at the start of colors config definition.");
}
return cmd_results_new(CMD_BLOCK_BAR_COLORS, NULL, NULL);
}
struct cmd_results *bar_colors_cmd_active_workspace(int argc, char **argv) {
char **colors[3] = {
&(config->current_bar->colors.active_workspace_border),
&(config->current_bar->colors.active_workspace_bg),
&(config->current_bar->colors.active_workspace_text)
};
return parse_three_colors(colors, "active_workspace", argc, argv);
}
struct cmd_results *bar_colors_cmd_background(int argc, char **argv) {
return parse_single_color(&(config->current_bar->colors.background), "background", argc, argv);
}
struct cmd_results *bar_colors_cmd_focused_background(int argc, char **argv) {
return parse_single_color(&(config->current_bar->colors.focused_background), "focused_background", argc, argv);
}
struct cmd_results *bar_colors_cmd_binding_mode(int argc, char **argv) {
char **colors[3] = {
&(config->current_bar->colors.binding_mode_border),
&(config->current_bar->colors.binding_mode_bg),
&(config->current_bar->colors.binding_mode_text)
};
return parse_three_colors(colors, "binding_mode", argc, argv);
}
struct cmd_results *bar_colors_cmd_focused_workspace(int argc, char **argv) {
char **colors[3] = {
&(config->current_bar->colors.focused_workspace_border),
&(config->current_bar->colors.focused_workspace_bg),
&(config->current_bar->colors.focused_workspace_text)
};
return parse_three_colors(colors, "focused_workspace", argc, argv);
}
struct cmd_results *bar_colors_cmd_inactive_workspace(int argc, char **argv) {
char **colors[3] = {
&(config->current_bar->colors.inactive_workspace_border),
&(config->current_bar->colors.inactive_workspace_bg),
&(config->current_bar->colors.inactive_workspace_text)
};
return parse_three_colors(colors, "inactive_workspace", argc, argv);
}
struct cmd_results *bar_colors_cmd_separator(int argc, char **argv) {
return parse_single_color(&(config->current_bar->colors.separator), "separator", argc, argv);
}
struct cmd_results *bar_colors_cmd_focused_separator(int argc, char **argv) {
return parse_single_color(&(config->current_bar->colors.focused_separator), "focused_separator", argc, argv);
}
struct cmd_results *bar_colors_cmd_statusline(int argc, char **argv) {
return parse_single_color(&(config->current_bar->colors.statusline), "statusline", argc, argv);
}
struct cmd_results *bar_colors_cmd_focused_statusline(int argc, char **argv) {
return parse_single_color(&(config->current_bar->colors.focused_separator), "focused_separator", argc, argv);
}
struct cmd_results *bar_colors_cmd_urgent_workspace(int argc, char **argv) {
char **colors[3] = {
&(config->current_bar->colors.urgent_workspace_border),
&(config->current_bar->colors.urgent_workspace_bg),
&(config->current_bar->colors.urgent_workspace_text)
};
return parse_three_colors(colors, "urgent_workspace", argc, argv);
}

View file

@ -1,26 +0,0 @@
#include <stdlib.h>
#include "sway/commands.h"
#include "log.h"
struct cmd_results *bar_cmd_context_button(int argc, char **argv) {
const char *cmd_name = "context_button";
#ifndef ENABLE_TRAY
return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command "
"%s called, but sway was compiled without tray support",
cmd_name, cmd_name);
#else
struct cmd_results *error = NULL;
if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined.");
}
// User should be able to prefix with 0x or whatever they want
config->current_bar->context_button = strtoul(argv[0], NULL, 0);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
#endif
}

View file

@ -1,26 +0,0 @@
#include <string.h>
#include "sway/commands.h"
#include "log.h"
#include "stringop.h"
struct cmd_results *bar_cmd_font(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "font", EXPECTED_AT_LEAST, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, "font", "No bar defined.");
}
char *font = join_args(argv, argc);
free(config->current_bar->font);
if (strlen(font) > 6 && strncmp("pango:", font, 6) == 0) {
config->current_bar->font = font;
} else {
config->current_bar->font = font;
}
sway_log(L_DEBUG, "Settings font '%s' for bar: %s", config->current_bar->font, config->current_bar->id);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,21 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "sway/commands.h"
#include "log.h"
struct cmd_results *bar_cmd_height(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "height", EXPECTED_EQUAL_TO, 1))) {
return error;
}
int height = atoi(argv[0]);
if (height < 0) {
return cmd_results_new(CMD_INVALID, "height",
"Invalid height value: %s", argv[0]);
}
config->current_bar->height = height;
sway_log(L_DEBUG, "Setting bar height to %d on bar: %s", height, config->current_bar->id);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,79 +0,0 @@
#define _XOPEN_SOURCE 500
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/ipc-server.h"
#include "log.h"
static struct cmd_results *bar_set_hidden_state(struct bar_config *bar, const char *hidden_state) {
char *old_state = bar->hidden_state;
if (strcasecmp("toggle", hidden_state) == 0 && !config->reading) {
if (strcasecmp("hide", bar->hidden_state) == 0) {
bar->hidden_state = strdup("show");
} else if (strcasecmp("show", bar->hidden_state) == 0) {
bar->hidden_state = strdup("hide");
}
} else if (strcasecmp("hide", hidden_state) == 0) {
bar->hidden_state = strdup("hide");
} else if (strcasecmp("show", hidden_state) == 0) {
bar->hidden_state = strdup("show");
} else {
return cmd_results_new(CMD_INVALID, "hidden_state", "Invalid value %s", hidden_state);
}
if (strcmp(old_state, bar->hidden_state) != 0) {
if (!config->reading) {
ipc_event_barconfig_update(bar);
}
sway_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s", bar->hidden_state, bar->id);
}
// free old mode
free(old_state);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "hidden_state", EXPECTED_AT_LEAST, 1))) {
return error;
}
if ((error = checkarg(argc, "hidden_state", EXPECTED_LESS_THAN, 3))) {
return error;
}
if (config->reading && argc > 1) {
return cmd_results_new(CMD_INVALID, "hidden_state", "Unexpected value %s in config mode", argv[1]);
}
const char *state = argv[0];
if (config->reading) {
return bar_set_hidden_state(config->current_bar, state);
}
const char *id = NULL;
if (argc == 2) {
id = argv[1];
}
int i;
struct bar_config *bar;
for (i = 0; i < config->bars->length; ++i) {
bar = config->bars->items[i];
if (id && strcmp(id, bar->id) == 0) {
return bar_set_hidden_state(bar, state);
}
error = bar_set_hidden_state(bar, state);
if (error) {
return error;
}
}
// active bar modifiers might have changed.
update_active_bar_modifiers();
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,25 +0,0 @@
#define _XOPEN_SOURCE 500
#include <string.h>
#include "sway/commands.h"
struct cmd_results *bar_cmd_icon_theme(int argc, char **argv) {
const char *cmd_name = "tray_output";
#ifndef ENABLE_TRAY
return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command "
"%s called, but sway was compiled without tray support",
cmd_name, cmd_name);
#else
struct cmd_results *error = NULL;
if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined.");
}
config->current_bar->icon_theme = strdup(argv[0]);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
#endif
}

View file

@ -1,33 +0,0 @@
#define _XOPEN_SOURCE 500
#include <string.h>
#include "sway/commands.h"
#include "log.h"
struct cmd_results *bar_cmd_id(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "id", EXPECTED_EQUAL_TO, 1))) {
return error;
}
const char *name = argv[0];
const char *oldname = config->current_bar->id;
// check if id is used by a previously defined bar
int i;
for (i = 0; i < config->bars->length; ++i) {
struct bar_config *find = config->bars->items[i];
if (strcmp(name, find->id) == 0 && config->current_bar != find) {
return cmd_results_new(CMD_FAILURE, "id",
"Id '%s' already defined for another bar. Id unchanged (%s).",
name, oldname);
}
}
sway_log(L_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name);
// free old bar id
free(config->current_bar->id);
config->current_bar->id = strdup(name);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,81 +0,0 @@
#define _XOPEN_SOURCE 500
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/ipc-server.h"
#include "log.h"
static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode) {
char *old_mode = bar->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) {
bar->mode = strdup("dock");
}
} else if (strcasecmp("dock", mode) == 0) {
bar->mode = strdup("dock");
} else if (strcasecmp("hide", mode) == 0) {
bar->mode = strdup("hide");
} else if (strcasecmp("invisible", mode) == 0) {
bar->mode = strdup("invisible");
} else {
return cmd_results_new(CMD_INVALID, "mode", "Invalid value %s", mode);
}
if (strcmp(old_mode, bar->mode) != 0) {
if (!config->reading) {
ipc_event_barconfig_update(bar);
// active bar modifiers might have changed.
update_active_bar_modifiers();
}
sway_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id);
}
// free old mode
free(old_mode);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
struct cmd_results *bar_cmd_mode(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) {
return error;
}
if ((error = checkarg(argc, "mode", EXPECTED_LESS_THAN, 3))) {
return error;
}
if (config->reading && argc > 1) {
return cmd_results_new(CMD_INVALID, "mode", "Unexpected value %s in config mode", argv[1]);
}
const char *mode = argv[0];
if (config->reading) {
return bar_set_mode(config->current_bar, mode);
}
const char *id = NULL;
if (argc == 2) {
id = argv[1];
}
int i;
struct bar_config *bar;
for (i = 0; i < config->bars->length; ++i) {
bar = config->bars->items[i];
if (id && strcmp(id, bar->id) == 0) {
return bar_set_mode(bar, mode);
}
error = bar_set_mode(bar, mode);
if (error) {
return error;
}
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,35 +0,0 @@
#include <string.h>
#include "sway/commands.h"
#include "log.h"
#include "stringop.h"
#include "util.h"
struct cmd_results *bar_cmd_modifier(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "modifier", EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, "modifier", "No bar defined.");
}
uint32_t mod = 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;
continue;
} else {
free_flat_list(split);
return cmd_results_new(CMD_INVALID, "modifier", "Unknown modifier '%s'", split->items[i]);
}
}
free_flat_list(split);
config->current_bar->modifier = mod;
sway_log(L_DEBUG, "Show/Hide the bar when pressing '%s' in hide mode.", argv[0]);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,50 +0,0 @@
#define _XOPEN_SOURCE 500
#include <string.h>
#include "sway/commands.h"
#include "list.h"
#include "log.h"
struct cmd_results *bar_cmd_output(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "output", EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, "output", "No bar defined.");
}
const char *output = argv[0];
list_t *outputs = config->current_bar->outputs;
if (!outputs) {
outputs = create_list();
config->current_bar->outputs = outputs;
}
int i;
int add_output = 1;
if (strcmp("*", output) == 0) {
// remove all previous defined outputs and replace with '*'
for (i = 0; i < outputs->length; ++i) {
free(outputs->items[i]);
list_del(outputs, i);
}
} else {
// only add output if not already defined with either the same
// name or as '*'
for (i = 0; i < outputs->length; ++i) {
const char *find = outputs->items[i];
if (strcmp("*", find) == 0 || strcmp(output, find) == 0) {
add_output = 0;
break;
}
}
}
if (add_output) {
list_add(outputs, strdup(output));
sway_log(L_DEBUG, "Adding bar: '%s' to output '%s'", config->current_bar->id, output);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,27 +0,0 @@
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "log.h"
struct cmd_results *bar_cmd_pango_markup(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "pango_markup", EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, "pango_markup", "No bar defined.");
}
if (strcasecmp("enabled", argv[0]) == 0) {
config->current_bar->pango_markup = true;
sway_log(L_DEBUG, "Enabling pango markup for bar: %s", config->current_bar->id);
} else if (strcasecmp("disabled", argv[0]) == 0) {
config->current_bar->pango_markup = false;
sway_log(L_DEBUG, "Disabling pango markup for bar: %s", config->current_bar->id);
} else {
error = cmd_results_new(CMD_INVALID, "pango_markup", "Invalid value %s", argv[0]);
return error;
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,33 +0,0 @@
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "log.h"
struct cmd_results *bar_cmd_position(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "position", EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, "position", "No bar defined.");
}
if (strcasecmp("top", argv[0]) == 0) {
config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_TOP;
} else if (strcasecmp("bottom", argv[0]) == 0) {
config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_BOTTOM;
} else if (strcasecmp("left", argv[0]) == 0) {
sway_log(L_INFO, "Warning: swaybar currently only supports top and bottom positioning. YMMV");
config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_LEFT;
} else if (strcasecmp("right", argv[0]) == 0) {
sway_log(L_INFO, "Warning: swaybar currently only supports top and bottom positioning. YMMV");
config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_RIGHT;
} else {
error = cmd_results_new(CMD_INVALID, "position", "Invalid value %s", argv[0]);
return error;
}
sway_log(L_DEBUG, "Setting bar position '%s' for bar: %s", argv[0], config->current_bar->id);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -1,26 +0,0 @@
#include <stdlib.h>
#include "sway/commands.h"
#include "log.h"
struct cmd_results *bar_cmd_secondary_button(int argc, char **argv) {
const char *cmd_name = "secondary_button";
#ifndef ENABLE_TRAY
return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command "
"%s called, but sway was compiled without tray support",
cmd_name, cmd_name);
#else
struct cmd_results *error = NULL;
if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (!config->current_bar) {
return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined.");
}
// User should be able to prefix with 0x or whatever they want
config->current_bar->secondary_button = strtoul(argv[0], NULL, 0);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
#endif
}

Some files were not shown because too many files have changed in this diff Show more