mirror of
https://github.com/swaywm/sway.git
synced 2026-07-12 11:03:58 -04:00
Merge branch 'wlroots' into multibackend
This commit is contained in:
commit
9a50972577
186 changed files with 2893 additions and 16072 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
149
common/log.c
149
common/log.c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -14,6 +14,7 @@ struct sway_output {
|
|||
struct timespec last_frame;
|
||||
|
||||
struct wl_listener frame;
|
||||
struct wl_listener output_destroy;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
176
sway/commands.c
176
sway/commands.c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
59
sway/commands/focus.c
Normal 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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
24
sway/commands/kill.c
Normal 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
56
sway/commands/layout.c
Normal 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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
189
sway/config.c
189
sway/config.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
50
sway/main.c
50
sway/main.c
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue