Merge pull request #179 from taiyu-len/master

new_workspace null behavior + testmap functions + regex
This commit is contained in:
Drew DeVault 2015-09-12 10:29:11 -04:00
commit 9c8f1fb964
12 changed files with 581 additions and 370 deletions

View file

@ -3,19 +3,21 @@
#include <stdbool.h> #include <stdbool.h>
#include "config.h" #include "config.h"
struct cmd_handler { typedef enum cmd_status {
char *command;
enum cmd_status {
CMD_SUCCESS, CMD_SUCCESS,
CMD_FAILURE, CMD_FAILURE,
CMD_DEFER, CMD_DEFER,
} (*handle)(int argc, char **argv); } sway_cmd(char *criteria, int argc, char **argv);
struct cmd_handler {
const char*command;
sway_cmd *handle;
}; };
enum cmd_status handle_command(char *command); enum cmd_status handle_command(char *command);
// Handles commands during config // Handles commands during config
enum cmd_status config_command(char *command); enum cmd_status config_command(char *command);
void remove_view_from_scratchpad(); void remove_view_from_scratchpad(swayc_t *view);
#endif #endif

View file

@ -63,6 +63,10 @@ bool load_config(const char *file);
bool read_config(FILE *file, bool is_active); bool read_config(FILE *file, bool is_active);
char *do_var_replacement(char *str); char *do_var_replacement(char *str);
// Find workspace_output from config by workspace or output name
struct workspace_output *wsop_find_workspace(const char *);
struct workspace_output *wsop_find_output(const char *);
extern struct sway_config *config; extern struct sway_config *config;
#endif #endif

View file

@ -2,29 +2,25 @@
#define _SWAY_CONTAINER_H #define _SWAY_CONTAINER_H
#include <wlc/wlc.h> #include <wlc/wlc.h>
typedef struct sway_container swayc_t; typedef struct sway_container swayc_t;
#include "layout.h" #include "layout.h"
enum swayc_types{ enum swayc_types {
C_ROOT, C_ROOT = 1 << 0,
C_OUTPUT, C_OUTPUT = 1 << 1,
C_WORKSPACE, C_WORKSPACE = 1 << 2,
C_CONTAINER, C_CONTAINER = 1 << 3,
C_VIEW, C_VIEW = 1 << 4,
// Keep last C_TYPES = 5,
C_TYPES,
}; };
enum swayc_layouts {
enum swayc_layouts{ L_NONE = 1 << 0,
L_NONE, L_HORIZ = 1 << 1,
L_HORIZ, L_VERT = 1 << 2,
L_VERT, L_STACKED = 1 << 3,
L_STACKED, L_TABBED = 1 << 4,
L_TABBED, L_FLOATING = 1 << 5,
L_FLOATING, L_LAYOUTS = 6,
// Keep last
L_LAYOUTS,
}; };
struct sway_container { struct sway_container {
@ -35,13 +31,16 @@ struct sway_container {
// Not including borders or margins // Not including borders or margins
double width, height; double width, height;
double x, y;
// Used for setting floating geometry // Used for setting floating geometry
int desired_width, desired_height; int desired_width, desired_height;
double x, y; enum visibility_mask {
INVISIBLE = false,
VISIBLE = true,
} visible;
bool visible;
bool is_floating; bool is_floating;
bool is_focused; bool is_focused;
@ -56,70 +55,120 @@ struct sway_container {
struct sway_container *focused; struct sway_container *focused;
}; };
enum visibility_mask { // swayc Creation
VISIBLE = 1
};
// Container Creation
/* Creates and returns new, or an already created output.
* If it creates a new output, it also creates a workspace using
* `new_workspace(outputname, NULL);` */
swayc_t *new_output(wlc_handle handle); swayc_t *new_output(wlc_handle handle);
/* Creates workspace with given name, under given output.
* If workspace with that name already exists, returns that workspace
* If name is NULL, it will choose a name automatically.
* If output is NULL, it will choose an output automatically. */
swayc_t *new_workspace(swayc_t *output, const char *name); swayc_t *new_workspace(swayc_t *output, const char *name);
// Creates container Around child (parent child) -> (parent (container child)) // Creates container Around child (parent child) -> (parent (container child))
swayc_t *new_container(swayc_t *child, enum swayc_layouts layout); swayc_t *new_container(swayc_t *child, enum swayc_layouts layout);
// Creates view as a sibling of current focused container, or as child of a workspace // Creates view as a sibling of current focused container, or as child of a workspace
swayc_t *new_view(swayc_t *sibling, wlc_handle handle); swayc_t *new_view(swayc_t *sibling, wlc_handle handle);
// Creates view as a new floating view which is in the active workspace // Creates view as a new floating view which is in the active workspace
swayc_t *new_floating_view(wlc_handle handle); swayc_t *new_floating_view(wlc_handle handle);
// Container Destroying // Container Destroying
// Destroys output and moves workspaces to another output
swayc_t *destroy_output(swayc_t *output); swayc_t *destroy_output(swayc_t *output);
// Destroys workspace if empty and returns parent pointer, else returns NULL // Destroys workspace if empty and returns parent pointer, else returns NULL
swayc_t *destroy_workspace(swayc_t *workspace); swayc_t *destroy_workspace(swayc_t *workspace);
// Destroyes container and all parent container if they are empty, returns // Destroyes container and all parent container if they are empty, returns
// topmost non-empty parent. returns NULL otherwise // topmost non-empty parent. returns NULL otherwise
swayc_t *destroy_container(swayc_t *container); swayc_t *destroy_container(swayc_t *container);
// Destroys view and all empty parent containers. return topmost non-empty // Destroys view and all empty parent containers. return topmost non-empty
// parent // parent
swayc_t *destroy_view(swayc_t *view); swayc_t *destroy_view(swayc_t *view);
// Container Lookup // Container Mapping and testing functions
typedef bool swayc_test_func(swayc_t *view, void *data);
typedef void swayc_map_func(swayc_t *view, void *data);
// Returns the first swayc that matches test()
swayc_t *swayc_by_test_r(swayc_t *root, swayc_test_func test, void *data);
swayc_t *swayc_by_test(swayc_test_func test, void *data);
// Calls func for all children.
void swayc_map_r(swayc_t *root, swayc_map_func func, void *data);
void swayc_map(swayc_map_func func, void *data);
// Call func on container if test passes
void swayc_map_by_test_r(swayc_t *root,
swayc_map_func func, swayc_test_func test,
void *funcdata, void *testdata);
void swayc_map_by_test(
swayc_map_func func, swayc_test_func test,
void *funcdata, void *testdata);
// Map functions
swayc_map_func set_gaps;
swayc_map_func add_gaps;
// Test functions
// generic swayc tests
swayc_test_func test_name;
swayc_test_func test_name_regex;
swayc_test_func test_layout;
swayc_test_func test_type;
swayc_test_func test_visibility;
swayc_test_func test_handle;
// C_VIEW tests
// See wlc_view_*_bit enums
swayc_test_func test_view_state;
swayc_test_func test_view_type;
swayc_test_func test_view_title;
swayc_test_func test_view_class;
swayc_test_func test_view_appid;
swayc_test_func test_view_title_regex;
swayc_test_func test_view_class_regex;
swayc_test_func test_view_appid_regex;
// functions for test_*_regex
void *compile_regex(const char *regex);
void free_regex(void *);
// these take a NULL terminated array of test_list struct.
struct test_list { swayc_test_func *test; void *data ; };
swayc_test_func test_and;
swayc_test_func test_or;
swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data);
swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types); swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types);
swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts); swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts);
// Follow focused until type/layout // Follow focused until type/layout
swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types); swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types);
swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts); swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts);
swayc_t *swayc_by_handle(wlc_handle handle);
swayc_t *swayc_by_name(const char *name);
swayc_t *swayc_active_output(void); swayc_t *swayc_active_output(void);
swayc_t *swayc_active_workspace(void); swayc_t *swayc_active_workspace(void);
swayc_t *swayc_active_workspace_for(swayc_t *view); swayc_t *swayc_active_workspace_for(swayc_t *view);
// Container information // Container information
// if `parent` is the parent of `child`
bool swayc_is_fullscreen(swayc_t *view);
bool swayc_is_active(swayc_t *view);
// Is `parent` the parent of `child`
bool swayc_is_parent_of(swayc_t *parent, swayc_t *child); bool swayc_is_parent_of(swayc_t *parent, swayc_t *child);
// Is `child` a child of `parent` // If `child` is a child of `parent`
bool swayc_is_child_of(swayc_t *child, swayc_t *parent); bool swayc_is_child_of(swayc_t *child, swayc_t *parent);
// Return gap of specified container // Return gap of specified container
int swayc_gap(swayc_t *container); int swayc_gap(swayc_t *container);
// Mapping functions bool swayc_is_fullscreen(swayc_t *view);
bool swayc_is_active(swayc_t *view);
void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
// Mappings
void set_view_visibility(swayc_t *view, void *data);
// Set or add to gaps
void set_gaps(swayc_t *view, void *amount);
void add_gaps(swayc_t *view, void *amount);
// Specialized mapping functions
void update_visibility(swayc_t *container); void update_visibility(swayc_t *container);
#endif #endif

View file

@ -19,7 +19,7 @@ void free_argv(int argc, char **argv);
char *code_strchr(const char *string, char delimiter); char *code_strchr(const char *string, char delimiter);
char *code_strstr(const char *haystack, const char *needle); char *code_strstr(const char *haystack, const char *needle);
int unescape_string(char *string); int unescape_string(char *string);
char *join_args(char **argv, int argc); char *join_args(int argc, char **argv);
char *join_list(list_t *list, char *separator); char *join_list(list_t *list, char *separator);
char *strdup(const char *); char *strdup(const char *);

View file

@ -7,13 +7,17 @@
extern char *prev_workspace_name; extern char *prev_workspace_name;
char *workspace_next_name(void); // Search for available workspace name on output from config
swayc_t *workspace_create(const char*); const char *workspace_output_open_name(swayc_t *output);
// Search for any available workspace name
const char *workspace_next_name(void);
swayc_t *workspace_by_name(const char*); swayc_t *workspace_by_name(const char*);
void workspace_switch(swayc_t*); void workspace_switch(swayc_t*);
swayc_t *workspace_output_next(); swayc_t *workspace_output_next(void);
swayc_t *workspace_next(); swayc_t *workspace_next(void);
swayc_t *workspace_output_prev(); swayc_t *workspace_output_prev(void);
swayc_t *workspace_prev(); swayc_t *workspace_prev(void);
#endif #endif

View file

@ -21,6 +21,35 @@
swayc_t *sp_view; swayc_t *sp_view;
int sp_index = 0; int sp_index = 0;
// Commands
static sway_cmd cmd_bindsym;
static sway_cmd cmd_orientation;
static sway_cmd cmd_exec;
static sway_cmd cmd_exec_always;
static sway_cmd cmd_exit;
static sway_cmd cmd_floating;
static sway_cmd cmd_floating_mod;
static sway_cmd cmd_focus;
static sway_cmd cmd_focus_follows_mouse;
static sway_cmd cmd_for_window;
static sway_cmd cmd_fullscreen;
static sway_cmd cmd_gaps;
static sway_cmd cmd_kill;
static sway_cmd cmd_layout;
static sway_cmd cmd_log_colors;
static sway_cmd cmd_mode;
static sway_cmd cmd_move;
static sway_cmd cmd_output;
static sway_cmd cmd_reload;
static sway_cmd cmd_resize;
static sway_cmd cmd_scratchpad;
static sway_cmd cmd_set;
static sway_cmd cmd_split;
static sway_cmd cmd_splith;
static sway_cmd cmd_splitv;
static sway_cmd cmd_workspace;
static sway_cmd cmd_ws_auto_back_and_forth;
static struct modifier_key { static struct modifier_key {
char *name; char *name;
uint32_t mod; uint32_t mod;
@ -94,7 +123,7 @@ static int bindsym_sort(const void *_lbind, const void *_rbind) {
return (rbind->keys->length + rmod) - (lbind->keys->length + lmod); return (rbind->keys->length + rmod) - (lbind->keys->length + lmod);
} }
static enum cmd_status cmd_bindsym(int argc, char **argv) { enum cmd_status cmd_bindsym(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1) if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)
|| !config->reading) { || !config->reading) {
return CMD_FAILURE; return CMD_FAILURE;
@ -103,7 +132,7 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) {
struct sway_binding *binding = malloc(sizeof(struct sway_binding)); struct sway_binding *binding = malloc(sizeof(struct sway_binding));
binding->keys = create_list(); binding->keys = create_list();
binding->modifiers = 0; binding->modifiers = 0;
binding->command = join_args(argv + 1, argc - 1); binding->command = join_args(argc - 1, argv + 1);
list_t *split = split_string(argv[0], "+"); list_t *split = split_string(argv[0], "+");
int i; int i;
@ -144,7 +173,7 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_exec_always(int argc, char **argv) { enum cmd_status cmd_exec_always(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) { if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) {
return CMD_FAILURE; return CMD_FAILURE;
} }
@ -160,7 +189,7 @@ static enum cmd_status cmd_exec_always(int argc, char **argv) {
} }
/* Child process */ /* Child process */
if (pid == 0) { if (pid == 0) {
char *args = join_args(argv, argc); char *args = join_args(argc, argv);
sway_log(L_DEBUG, "Executing %s", args); sway_log(L_DEBUG, "Executing %s", args);
execl("/bin/sh", "sh", "-c", args, (char *)NULL); execl("/bin/sh", "sh", "-c", args, (char *)NULL);
/* Execl doesnt return unless failure */ /* Execl doesnt return unless failure */
@ -172,17 +201,17 @@ static enum cmd_status cmd_exec_always(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_exec(int argc, char **argv) { enum cmd_status cmd_exec(char *criteria, int argc, char **argv) {
if (!config->active) { if (!config->active) {
return CMD_DEFER; return CMD_DEFER;
} }
if (config->reloading) { if (config->reloading) {
char *args = join_args(argv, argc); char *args = join_args(argc, argv);
sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
free(args); free(args);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
return cmd_exec_always(argc, argv); return cmd_exec_always(criteria, argc, argv);
} }
static void kill_views(swayc_t *container, void *data) { static void kill_views(swayc_t *container, void *data) {
@ -191,18 +220,19 @@ static void kill_views(swayc_t *container, void *data) {
} }
} }
static enum cmd_status cmd_exit(int argc, char **argv) { enum cmd_status cmd_exit(char *criteria, int argc, char **argv) {
(void) argv;
if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0) if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)
|| config->reading || !config->active) { || config->reading || !config->active) {
return CMD_FAILURE; return CMD_FAILURE;
} }
// Close all views // Close all views
container_map(&root_container, kill_views, NULL); swayc_map(kill_views, NULL);
sway_terminate(); sway_terminate();
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_floating(int argc, char **argv) { enum cmd_status cmd_floating(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1) if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)
|| config->reading || !config->active) { || config->reading || !config->active) {
return CMD_FAILURE; return CMD_FAILURE;
@ -264,7 +294,7 @@ static enum cmd_status cmd_floating(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_floating_mod(int argc, char **argv) { enum cmd_status cmd_floating_mod(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1) if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)
|| !config->reading) { || !config->reading) {
return CMD_FAILURE; return CMD_FAILURE;
@ -289,7 +319,7 @@ static enum cmd_status cmd_floating_mod(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_focus(int argc, char **argv) { enum cmd_status cmd_focus(char *criteria, int argc, char **argv) {
static int floating_toggled_index = 0; static int floating_toggled_index = 0;
static int tiled_toggled_index = 0; static int tiled_toggled_index = 0;
if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1) if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)
@ -347,7 +377,7 @@ static enum cmd_status cmd_focus(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) { enum cmd_status cmd_focus_follows_mouse(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) { if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) {
return CMD_FAILURE; return CMD_FAILURE;
} }
@ -356,6 +386,21 @@ static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static void debug_for_window(swayc_t *view, void *data) {
layout_log(view, 0);
}
enum cmd_status cmd_for_window(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "for_window", EXPECTED_AT_LEAST, 1)) {
return CMD_FAILURE;
}
//TODO
void *re = compile_regex(argv[0]);
swayc_map_by_test(debug_for_window, test_view_title_regex, NULL, re);
free_regex(re);
return CMD_FAILURE;
}
static void hide_view_in_scratchpad(swayc_t *sp_view) { static void hide_view_in_scratchpad(swayc_t *sp_view) {
if(sp_view == NULL) { if(sp_view == NULL) {
return; return;
@ -372,7 +417,7 @@ static void hide_view_in_scratchpad(swayc_t *sp_view) {
set_focused_container(container_under_pointer()); set_focused_container(container_under_pointer());
} }
static enum cmd_status cmd_mode(int argc, char **argv) { enum cmd_status cmd_mode(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) {
return CMD_FAILURE; return CMD_FAILURE;
} }
@ -381,7 +426,7 @@ static enum cmd_status cmd_mode(int argc, char **argv) {
return CMD_FAILURE; return CMD_FAILURE;
} }
char *mode_name = join_args(argv, argc - mode_make); char *mode_name = join_args(argc - mode_make, argv);
struct sway_mode *mode = NULL; struct sway_mode *mode = NULL;
// Find mode // Find mode
int i, len = config->modes->length; int i, len = config->modes->length;
@ -411,7 +456,7 @@ static enum cmd_status cmd_mode(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_move(int argc, char **argv) { enum cmd_status cmd_move(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1) if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)
|| config->reading || !config->active) { || config->reading || !config->active) {
return CMD_FAILURE; return CMD_FAILURE;
@ -444,11 +489,7 @@ static enum cmd_status cmd_move(int argc, char **argv) {
// move "container to workspace number x" // move "container to workspace number x"
ws_name = argv[4]; ws_name = argv[4];
} }
swayc_t *ws = new_workspace(NULL, ws_name);
swayc_t *ws = workspace_by_name(ws_name);
if (ws == NULL) {
ws = workspace_create(ws_name);
}
move_container_to(view, get_focused_container(ws)); move_container_to(view, get_focused_container(ws));
} else if (strcasecmp(argv[0], "scratchpad") == 0) { } else if (strcasecmp(argv[0], "scratchpad") == 0) {
if (view->type != C_CONTAINER && view->type != C_VIEW) { if (view->type != C_CONTAINER && view->type != C_VIEW) {
@ -482,7 +523,7 @@ static enum cmd_status cmd_move(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_orientation(int argc, char **argv) { enum cmd_status cmd_orientation(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1) if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1)
|| !config->reading) { || !config->reading) {
return CMD_FAILURE; return CMD_FAILURE;
@ -499,7 +540,7 @@ static enum cmd_status cmd_orientation(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_output(int argc, char **argv) { enum cmd_status cmd_output(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) { if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) {
return CMD_FAILURE; return CMD_FAILURE;
} }
@ -564,7 +605,7 @@ static enum cmd_status cmd_output(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_gaps(int argc, char **argv) { enum cmd_status cmd_gaps(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) { if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) {
return CMD_FAILURE; return CMD_FAILURE;
} }
@ -698,15 +739,14 @@ static enum cmd_status cmd_gaps(int argc, char **argv) {
top = &root_container; top = &root_container;
} }
int top_gap = top->gaps; int top_gap = top->gaps;
container_map(top, method == SET ? set_gaps : add_gaps, &amount); swayc_map_r(top, method == SET ? set_gaps : add_gaps, &amount);
top->gaps = top_gap; top->gaps = top_gap;
arrange_windows(top, -1, -1); arrange_windows(top, -1, -1);
} }
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_kill(int argc, char **argv) { enum cmd_status cmd_kill(char *criteria, int argc, char **argv) {
if (config->reading || !config->active) { if (config->reading || !config->active) {
return CMD_FAILURE; return CMD_FAILURE;
} }
@ -715,7 +755,7 @@ static enum cmd_status cmd_kill(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_layout(int argc, char **argv) { enum cmd_status cmd_layout(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "layout", EXPECTED_MORE_THAN, 0) if (!checkarg(argc, "layout", EXPECTED_MORE_THAN, 0)
|| config->reading || !config->active) { || config->reading || !config->active) {
return CMD_FAILURE; return CMD_FAILURE;
@ -741,7 +781,7 @@ static enum cmd_status cmd_layout(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_reload(int argc, char **argv) { enum cmd_status cmd_reload(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0) if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)
|| config->reading || config->reading
|| !load_config(NULL)) { || !load_config(NULL)) {
@ -751,7 +791,7 @@ static enum cmd_status cmd_reload(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_resize(int argc, char **argv) { enum cmd_status cmd_resize(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "resize", EXPECTED_AT_LEAST, 3) if (!checkarg(argc, "resize", EXPECTED_AT_LEAST, 3)
|| config->reading || !config->active) { || config->reading || !config->active) {
return CMD_FAILURE; return CMD_FAILURE;
@ -781,7 +821,7 @@ static enum cmd_status cmd_resize(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static swayc_t *fetch_view_from_scratchpad() { static swayc_t *fetch_view_from_scratchpad(void) {
if (sp_index >= scratchpad->length) { if (sp_index >= scratchpad->length) {
sp_index = 0; sp_index = 0;
} }
@ -826,7 +866,7 @@ void remove_view_from_scratchpad(swayc_t *view) {
} }
} }
static enum cmd_status cmd_scratchpad(int argc, char **argv) { enum cmd_status cmd_scratchpad(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1) if (!checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1)
|| config->reading || !config->active) { || config->reading || !config->active) {
return CMD_FAILURE; return CMD_FAILURE;
@ -860,7 +900,7 @@ static int compare_set(const void *_l, const void *_r) {
return strlen((*r)->name) - strlen((*l)->name); return strlen((*r)->name) - strlen((*l)->name);
} }
static enum cmd_status cmd_set(int argc, char **argv) { enum cmd_status cmd_set(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "set", EXPECTED_AT_LEAST, 2) if (!checkarg(argc, "set", EXPECTED_AT_LEAST, 2)
|| !config->reading) { || !config->reading) {
return CMD_FAILURE; return CMD_FAILURE;
@ -883,11 +923,11 @@ static enum cmd_status cmd_set(int argc, char **argv) {
list_add(config->symbols, var); list_add(config->symbols, var);
list_sort(config->symbols, compare_set); list_sort(config->symbols, compare_set);
} }
var->value = join_args(argv + 1, argc - 1); var->value = join_args(argc - 1, argv + 1);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status _do_split(int argc, char **argv, int layout) { static enum cmd_status _do_split(char *criteria, int argc, char **argv, int layout) {
char *name = layout == L_VERT ? "splitv" : char *name = layout == L_VERT ? "splitv" :
layout == L_HORIZ ? "splith" : "split"; layout == L_HORIZ ? "splith" : "split";
if (!checkarg(argc, name, EXPECTED_EQUAL_TO, 0) if (!checkarg(argc, name, EXPECTED_EQUAL_TO, 0)
@ -919,16 +959,16 @@ static enum cmd_status _do_split(int argc, char **argv, int layout) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_split(int argc, char **argv) { enum cmd_status cmd_split(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "split", EXPECTED_EQUAL_TO, 1) if (!checkarg(argc, "split", EXPECTED_EQUAL_TO, 1)
|| config->reading || !config->active) { || config->reading || !config->active) {
return CMD_FAILURE; return CMD_FAILURE;
} }
if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) {
_do_split(argc - 1, argv + 1, L_VERT); _do_split(criteria, argc - 1, argv + 1, L_VERT);
} else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) { } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) {
_do_split(argc - 1, argv + 1, L_HORIZ); _do_split(criteria, argc - 1, argv + 1, L_HORIZ);
} else { } else {
sway_log(L_ERROR, "Invalid split command (expected either horiziontal or vertical)."); sway_log(L_ERROR, "Invalid split command (expected either horiziontal or vertical).");
return CMD_FAILURE; return CMD_FAILURE;
@ -936,15 +976,15 @@ static enum cmd_status cmd_split(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_splitv(int argc, char **argv) { enum cmd_status cmd_splitv(char *criteria, int argc, char **argv) {
return _do_split(argc, argv, L_VERT); return _do_split(criteria, argc, argv, L_VERT);
} }
static enum cmd_status cmd_splith(int argc, char **argv) { enum cmd_status cmd_splith(char *criteria, int argc, char **argv) {
return _do_split(argc, argv, L_HORIZ); return _do_split(criteria, argc, argv, L_HORIZ);
} }
static enum cmd_status cmd_log_colors(int argc, char **argv) { enum cmd_status cmd_log_colors(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "log_colors", EXPECTED_EQUAL_TO, 1) if (!checkarg(argc, "log_colors", EXPECTED_EQUAL_TO, 1)
|| !config->reading) { || !config->reading) {
return CMD_FAILURE; return CMD_FAILURE;
@ -960,7 +1000,7 @@ static enum cmd_status cmd_log_colors(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_fullscreen(int argc, char **argv) { enum cmd_status cmd_fullscreen(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0) if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0)
|| config->reading || !config->active) { || config->reading || !config->active) {
return CMD_FAILURE; return CMD_FAILURE;
@ -980,7 +1020,7 @@ static enum cmd_status cmd_fullscreen(int argc, char **argv) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_workspace(int argc, char **argv) { enum cmd_status cmd_workspace(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1)) { if (!checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1)) {
return CMD_FAILURE; return CMD_FAILURE;
} }
@ -989,28 +1029,7 @@ static enum cmd_status cmd_workspace(int argc, char **argv) {
if (config->reading || !config->active) { if (config->reading || !config->active) {
return CMD_DEFER; return CMD_DEFER;
} }
// Handle workspace next/prev workspace_switch(new_workspace(NULL, argv[0]));
swayc_t *ws = NULL;
if (strcasecmp(argv[0], "next") == 0) {
ws = workspace_next();
} else if (strcasecmp(argv[0], "prev") == 0) {
ws = workspace_prev();
} else if (strcasecmp(argv[0], "next_on_output") == 0) {
ws = workspace_output_next();
} else if (strcasecmp(argv[0], "prev_on_output") == 0) {
ws = workspace_output_prev();
} else if (strcasecmp(argv[0], "back_and_forth") == 0) {
if (prev_workspace_name) {
if (!(ws = workspace_by_name(prev_workspace_name))) {
ws = workspace_create(prev_workspace_name);
}
}
} else {
if (!(ws= workspace_by_name(argv[0]))) {
ws = workspace_create(argv[0]);
}
}
workspace_switch(ws);
} else { } else {
if (strcasecmp(argv[1], "output") == 0) { if (strcasecmp(argv[1], "output") == 0) {
if (!checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 3)) { if (!checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 3)) {
@ -1021,15 +1040,12 @@ static enum cmd_status cmd_workspace(int argc, char **argv) {
wso->workspace = strdup(argv[0]); wso->workspace = strdup(argv[0]);
wso->output = strdup(argv[2]); wso->output = strdup(argv[2]);
list_add(config->workspace_outputs, wso); list_add(config->workspace_outputs, wso);
if (!config->reading) {
// TODO: Move workspace to output. (dont do so when reloading)
}
} }
} }
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static enum cmd_status cmd_ws_auto_back_and_forth(int argc, char **argv) { enum cmd_status cmd_ws_auto_back_and_forth(char *criteria, int argc, char **argv) {
if (!checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1)) { if (!checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1)) {
return CMD_FAILURE; return CMD_FAILURE;
} }
@ -1044,7 +1060,7 @@ static enum cmd_status cmd_ws_auto_back_and_forth(int argc, char **argv) {
} }
/* Keep alphabetized */ /* Keep alphabetized */
static struct cmd_handler handlers[] = { static const struct cmd_handler handlers[] = {
{ "bindsym", cmd_bindsym }, { "bindsym", cmd_bindsym },
{ "default_orientation", cmd_orientation }, { "default_orientation", cmd_orientation },
{ "exec", cmd_exec }, { "exec", cmd_exec },
@ -1054,6 +1070,7 @@ static struct cmd_handler handlers[] = {
{ "floating_modifier", cmd_floating_mod }, { "floating_modifier", cmd_floating_mod },
{ "focus", cmd_focus }, { "focus", cmd_focus },
{ "focus_follows_mouse", cmd_focus_follows_mouse }, { "focus_follows_mouse", cmd_focus_follows_mouse },
{ "for_window", cmd_for_window },
{ "fullscreen", cmd_fullscreen }, { "fullscreen", cmd_fullscreen },
{ "gaps", cmd_gaps }, { "gaps", cmd_gaps },
{ "kill", cmd_kill }, { "kill", cmd_kill },
@ -1090,6 +1107,7 @@ static struct cmd_handler *find_handler(char *line) {
enum cmd_status handle_command(char *exec) { enum cmd_status handle_command(char *exec) {
sway_log(L_INFO, "Handling command '%s'", exec); sway_log(L_INFO, "Handling command '%s'", exec);
int argc; int argc;
char *criteria = NULL;
char **argv = split_args(exec, &argc); char **argv = split_args(exec, &argc);
enum cmd_status status = CMD_FAILURE; enum cmd_status status = CMD_FAILURE;
struct cmd_handler *handler; struct cmd_handler *handler;
@ -1097,7 +1115,7 @@ enum cmd_status handle_command(char *exec) {
return status; return status;
} }
if ((handler = find_handler(argv[0])) == NULL if ((handler = find_handler(argv[0])) == NULL
|| (status = handler->handle(argc - 1, argv + 1)) != CMD_SUCCESS) { || (status = handler->handle(criteria, argc - 1, argv + 1)) != CMD_SUCCESS) {
sway_log(L_ERROR, "Command failed: %s", argv[0]); sway_log(L_ERROR, "Command failed: %s", argv[0]);
} }
free_argv(argc, argv); free_argv(argc, argv);
@ -1108,6 +1126,7 @@ enum cmd_status config_command(char *exec) {
sway_log(L_INFO, "handling config command '%s'", exec); sway_log(L_INFO, "handling config command '%s'", exec);
int argc; int argc;
char **argv = split_args(exec, &argc); char **argv = split_args(exec, &argc);
char *criteria = NULL;
enum cmd_status status = CMD_FAILURE; enum cmd_status status = CMD_FAILURE;
struct cmd_handler *handler; struct cmd_handler *handler;
if (!argc) { if (!argc) {
@ -1127,7 +1146,7 @@ enum cmd_status config_command(char *exec) {
for (; i < e; ++i) { for (; i < e; ++i) {
argv[i] = do_var_replacement(argv[i]); argv[i] = do_var_replacement(argv[i]);
} }
status = handler->handle(argc - 1, argv + 1); status = handler->handle(criteria, argc - 1, argv + 1);
if (status == CMD_FAILURE) { if (status == CMD_FAILURE) {
sway_log(L_ERROR, "Config load failed for line `%s'", exec); sway_log(L_ERROR, "Config load failed for line `%s'", exec);
} else if (status == CMD_DEFER) { } else if (status == CMD_DEFER) {

View file

@ -286,3 +286,28 @@ char *do_var_replacement(char *str) {
} }
return str; return str;
} }
struct workspace_output *wsop_find_workspace(const char *name) {
int i, len = config->workspace_outputs->length;
struct workspace_output *wsop;
for (i = 0; i < len; ++i) {
wsop = config->workspace_outputs->items[i];
if (strcasecmp(wsop->workspace, name) == 0) {
return wsop;
}
}
return NULL;
}
struct workspace_output *wsop_find_output(const char *name) {
int i, len = config->workspace_outputs->length;
struct workspace_output *wsop;
for (i = 0; i < len; ++i) {
wsop = config->workspace_outputs->items[i];
if (strcasecmp(wsop->output, name) == 0) {
return wsop;
}
}
return NULL;
}

View file

@ -1,6 +1,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <strings.h> #include <strings.h>
#include <pcre.h>
#include "config.h" #include "config.h"
#include "container.h" #include "container.h"
#include "workspace.h" #include "workspace.h"
@ -53,26 +54,30 @@ static void free_swayc(swayc_t *cont) {
// New containers // New containers
swayc_t *new_output(wlc_handle handle) { swayc_t *new_output(wlc_handle handle) {
const struct wlc_size *size = wlc_output_get_resolution(handle);
const char *name = wlc_output_get_name(handle); const char *name = wlc_output_get_name(handle);
int i, len;
// Find current outputs to see if this already exists // Find current outputs to see if this already exists
{ if (name) {
int i, len = root_container.children->length; len = root_container.children->length;
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
swayc_t *op = root_container.children->items[i]; swayc_t *op = root_container.children->items[i];
const char *op_name = op->name; if (strcmp(op->name, name) == 0) {
if (op_name && name && strcmp(op_name, name) == 0) { sway_log(L_DEBUG, "restoring output %lu:%s", handle, op->name);
sway_log(L_DEBUG, "restoring output %lu:%s", handle, op_name);
return op; return op;
} }
} }
} else {
sway_log(L_ERROR, "Output has no given name");
return NULL;
} }
sway_log(L_DEBUG, "Added output %lu:%s", handle, name); sway_log(L_DEBUG, "Adding output %lu:%s", handle, name);
// Find output config
struct output_config *oc = NULL; struct output_config *oc = NULL;
int i; len = config->output_configs->length;
for (i = 0; i < config->output_configs->length; ++i) { for (i = 0; i < len; ++i) {
oc = config->output_configs->items[i]; oc = config->output_configs->items[i];
if (strcasecmp(name, oc->name) == 0) { if (strcasecmp(name, oc->name) == 0) {
sway_log(L_DEBUG, "Matched output config for %s", name); sway_log(L_DEBUG, "Matched output config for %s", name);
@ -86,77 +91,88 @@ swayc_t *new_output(wlc_handle handle) {
} }
swayc_t *output = new_swayc(C_OUTPUT); swayc_t *output = new_swayc(C_OUTPUT);
if (oc && oc->width != -1 && oc->height != -1) {
output->width = oc->width;
output->height = oc->height;
struct wlc_size new_size = { .w = oc->width, .h = oc->height };
wlc_output_set_resolution(handle, &new_size);
} else {
output->width = size->w;
output->height = size->h;
}
output->handle = handle; output->handle = handle;
output->name = name ? strdup(name) : NULL; output->name = name ? strdup(name) : NULL;
// Find position for it if (oc) {
if (oc && oc->x != -1 && oc->y != -1) { // Set output width/height
sway_log(L_DEBUG, "Set %s position to %d, %d", name, oc->x, oc->y); if (oc->width > 0 && oc->height > 0) {
output->width = oc->width;
output->height = oc->height;
struct wlc_size geo = { .w = oc->width, .h = oc->height};
wlc_output_set_resolution(handle, &geo);
} else {
struct wlc_size geo = *wlc_output_get_resolution(handle);
output->width = geo.w;
output->height = geo.h;
}
// find position in config or find where it should go
// TODO more intelligent method
if (oc->x > 0 && oc->y > 0) {
output->x = oc->x; output->x = oc->x;
output->y = oc->y; output->y = oc->y;
} else { } else {
int x = 0; unsigned int x = 0;
for (i = 0; i < root_container.children->length; ++i) { len = root_container.children->length;
for (i = 0; i < len; ++i) {
swayc_t *c = root_container.children->items[i]; swayc_t *c = root_container.children->items[i];
if (c->type == C_OUTPUT) { if (c->type == C_OUTPUT) {
if (c->width + c->x > x) { unsigned int cx = c->width + c->x;
x = c->width + c->x; if (cx > x) {
x = cx;
} }
} }
} }
output->x = x; output->x = x;
} }
}
// Add as child to root
add_child(&root_container, output); add_child(&root_container, output);
// Create workspace
char *ws_name = NULL;
if (name) {
for (i = 0; i < config->workspace_outputs->length; ++i) {
struct workspace_output *wso = config->workspace_outputs->items[i];
if (strcasecmp(wso->output, name) == 0) {
sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output);
// Check if any other workspaces are using this name
if (workspace_by_name(wso->workspace)) {
sway_log(L_DEBUG, "But it's already taken");
break;
}
sway_log(L_DEBUG, "So we're going to use it");
ws_name = strdup(wso->workspace);
break;
}
}
}
if (!ws_name) {
ws_name = workspace_next_name();
}
// create and initilize default workspace // create and initilize default workspace
swayc_t *ws = new_workspace(output, ws_name); swayc_t *ws = new_workspace(output, NULL);
ws->is_focused = true; ws->is_focused = true;
free(ws_name);
return output; return output;
} }
swayc_t *new_workspace(swayc_t *output, const char *name) { swayc_t *new_workspace(swayc_t *output, const char *name) {
if (!ASSERT_NONNULL(output)) { swayc_t *ws = NULL;
return NULL; struct workspace_output *wsop;
if (name) {
// Find existing workspace with same name.
// or workspace found by special name
if ((ws = workspace_by_name(name))) {
return ws;
}
// Find matching output from config
if (!output) {
if ((wsop = wsop_find_workspace(name))) {
int i, len = root_container.children->length;
for (i = 0; i < len; ++i) {
swayc_t *op = root_container.children->items[i];
if (strcasecmp(op->name, wsop->output) == 0) {
output = op;
goto find_wsop_end;
}
}
}
// Set output to active_output if there is no output.
output = swayc_active_output();
find_wsop_end:;
}
} else {
// No name or output, use active_output
if (!output) {
output = swayc_active_output();
}
// search for available output name
if (!(name = workspace_output_open_name(output))) {
// otherwise just use simple next name
name = workspace_next_name();
}
} }
sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle);
swayc_t *workspace = new_swayc(C_WORKSPACE); swayc_t *workspace = new_swayc(C_WORKSPACE);
// TODO: default_layout
if (config->default_layout != L_NONE) { if (config->default_layout != L_NONE) {
workspace->layout = config->default_layout; workspace->layout = config->default_layout;
} else if (config->default_orientation != L_NONE) { } else if (config->default_orientation != L_NONE) {
@ -374,7 +390,7 @@ swayc_t *destroy_view(swayc_t *view) {
// Container lookup // Container lookup
swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { swayc_t *swayc_by_test_r(swayc_t *container, swayc_test_func test, void *data) {
if (!container->children) { if (!container->children) {
return NULL; return NULL;
} }
@ -393,7 +409,7 @@ swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *dat
if (test(child, data)) { if (test(child, data)) {
return child; return child;
} else { } else {
swayc_t *res = swayc_by_test(child, test, data); swayc_t *res = swayc_by_test_r(child, test, data);
if (res) { if (res) {
return res; return res;
} }
@ -401,17 +417,192 @@ swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *dat
} }
return NULL; return NULL;
} }
swayc_t *swayc_by_test(swayc_test_func test, void *data) {
return swayc_by_test_r(&root_container, test, data);
}
static bool test_name(swayc_t *view, void *data) { void swayc_map_r(swayc_t *container, swayc_map_func f, void *data) {
if (!view && !view->name) { if (container) {
f(container, data);
int i;
if (container->children) {
for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i];
swayc_map_r(child, f, data);
}
}
if (container->floating) {
for (i = 0; i < container->floating->length; ++i) {
swayc_t *child = container->floating->items[i];
swayc_map_r(child, f, data);
}
}
}
}
void swayc_map(swayc_map_func f, void *data) {
swayc_map_r(&root_container, f, data);
}
void swayc_map_by_test_r(swayc_t *container,
swayc_map_func func, swayc_test_func test,
void *funcdata, void *testdata) {
if (container) {
if (test(container, testdata)) {
func(container, funcdata);
}
int i;
if (container->children) {
for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i];
swayc_map_by_test_r(child, func, test, funcdata, testdata);
}
}
if (container->floating) {
for (i = 0; i < container->floating->length; ++i) {
swayc_t *child = container->floating->items[i];
swayc_map_by_test_r(child, func, test, funcdata, testdata);
}
}
}
}
void swayc_map_by_test(
swayc_map_func func, swayc_test_func test,
void *funcdata, void *testdata) {
swayc_map_by_test_r(&root_container, func, test, funcdata, testdata);
}
// Map functions
void set_gaps(swayc_t *view, void *_data) {
int *data = _data;
if (view->type == C_WORKSPACE || view->type == C_VIEW) {
view->gaps = *data;
}
}
void add_gaps(swayc_t *view, void *_data) {
int *data = _data;
if (view->type == C_WORKSPACE || view->type == C_VIEW) {
if ((view->gaps += *data) < 0) {
view->gaps = 0;
}
}
}
// Test functions
bool test_name(swayc_t *view, void *data) {
return view->name && strcmp(view->name, data) == 0;
}
// test_name_regex
struct test_name_regex {
pcre *reg;
pcre_extra *regext;
};
void *compile_regex(const char *pattern) {
struct test_name_regex *regex = malloc(sizeof *regex);
const char *error;
int erroffset;
if (!(regex->reg = pcre_compile(pattern, 0, &error, &erroffset, NULL))) {
sway_log(L_ERROR, "Regex compilation failed:%s:%s", pattern, error);
free(regex);
return NULL;
}
regex->regext = pcre_study(regex->reg, 0, &error);
if (error) {
sway_log(L_DEBUG, "Regex study failed:%s:%s", pattern, error);
}
return regex;
}
void free_regex(void *_regex) {
struct test_name_regex *regex = _regex;
pcre_free(regex->reg);
pcre_free_study(regex->regext);
free(regex);
}
static bool exec_regex(const char *pattern, struct test_name_regex *regex) {
int ovector[300];
return 0 < pcre_exec(regex->reg, regex->regext, pattern,
strlen(pattern), 0, 0, ovector, 300);
}
bool test_name_regex(swayc_t *view, void *data) {
return view->name && exec_regex(view->name, data);
}
bool test_layout(swayc_t *view, void *data) {
return view->layout & *(enum swayc_layouts *)data;
}
bool test_type(swayc_t *view, void *data) {
return view->layout & *(enum swayc_types *)data;
}
bool test_visibility(swayc_t *view, void *data) {
return view->visible == *(bool *)data;
}
bool test_handle(swayc_t *view, void *data) {
return view->handle == *(wlc_handle *)data;
}
// C_VIEW tests
bool test_view_state(swayc_t *view, void *data) {
return view->type == C_VIEW
&& wlc_view_get_state(view->handle) & *(int *)data;
}
bool test_view_type(swayc_t *view, void *data) {
return view->type == C_VIEW
&& wlc_view_get_type(view->handle) & *(int *)data;
}
bool test_view_title(swayc_t *view, void *data) {
return view->type == C_VIEW
&& strcmp(view->name, data) == 0;
}
bool test_view_class(swayc_t *view, void *data) {
return view->type == C_VIEW
&& strcmp(wlc_view_get_class(view->handle), data) == 0;
}
bool test_view_appid(swayc_t *view, void *data) {
return view->type == C_VIEW
&& strcmp(wlc_view_get_app_id(view->handle), data) == 0;
}
bool test_view_title_regex(swayc_t *view, void *data) {
return view->type == C_VIEW
&& exec_regex(view->name, data);
}
bool test_view_class_regex(swayc_t *view, void *data) {
return view->type == C_VIEW
&& exec_regex(wlc_view_get_class(view->handle), data);
}
bool test_view_appid_regex(swayc_t *view, void *data) {
return view->type == C_VIEW
&& exec_regex(wlc_view_get_app_id(view->handle), data);
}
// Fancy test combiners
bool test_and(swayc_t *view, void *data) {
struct test_list *list = data;
while (list->test) {
if (!list->test(view, list->data)) {
return false; return false;
} }
return strcmp(view->name, data) == 0; ++list;
}
return true;
}
bool test_or(swayc_t *view, void *data) {
struct test_list *list = data;
while (list->test) {
if (list->test(view, list->data)) {
return true;
}
++list;
}
return false;
} }
swayc_t *swayc_by_name(const char *name) { // Focus|parent lookup
return swayc_by_test(&root_container, test_name, (void *)name);
}
swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
if (!ASSERT_NONNULL(container)) { if (!ASSERT_NONNULL(container)) {
@ -465,42 +656,6 @@ swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts layout) {
return container; return container;
} }
static swayc_t *_swayc_by_handle_helper(wlc_handle handle, swayc_t *parent) {
if (!parent || !parent->children) {
return NULL;
}
int i, len;
swayc_t **child;
if (parent->type == C_WORKSPACE) {
len = parent->floating->length;
child = (swayc_t **)parent->floating->items;
for (i = 0; i < len; ++i, ++child) {
if ((*child)->handle == handle) {
return *child;
}
}
}
len = parent->children->length;
child = (swayc_t**)parent->children->items;
for (i = 0; i < len; ++i, ++child) {
if ((*child)->handle == handle) {
return *child;
} else {
swayc_t *res;
if ((res = _swayc_by_handle_helper(handle, *child))) {
return res;
}
}
}
return NULL;
}
swayc_t *swayc_by_handle(wlc_handle handle) {
return _swayc_by_handle_helper(handle, &root_container);
}
swayc_t *swayc_active_output(void) { swayc_t *swayc_active_output(void) {
return root_container.focused; return root_container.focused;
} }
@ -533,11 +688,13 @@ swayc_t *swayc_active_workspace_for(swayc_t *cont) {
// Container information // Container information
bool swayc_is_fullscreen(swayc_t *view) { bool swayc_is_fullscreen(swayc_t *view) {
return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN); return view && view->type == C_VIEW
&& wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN;
} }
bool swayc_is_active(swayc_t *view) { bool swayc_is_active(swayc_t *view) {
return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED); return view && view->type == C_VIEW
&& wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED;
} }
bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) { bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) {
@ -566,25 +723,6 @@ int swayc_gap(swayc_t *container) {
// Mapping // Mapping
void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
if (container) {
f(container, data);
int i;
if (container->children) {
for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i];
container_map(child, f, data);
}
}
if (container->floating) {
for (i = 0; i < container->floating->length; ++i) {
swayc_t *child = container->floating->items[i];
container_map(child, f, data);
}
}
}
}
void update_visibility_output(swayc_t *container, wlc_handle output) { void update_visibility_output(swayc_t *container, wlc_handle output) {
// Inherit visibility // Inherit visibility
swayc_t *parent = container->parent; swayc_t *parent = container->parent;
@ -653,24 +791,3 @@ void update_visibility(swayc_t *container) {
} }
} }
void set_gaps(swayc_t *view, void *_data) {
int *data = _data;
if (!ASSERT_NONNULL(view)) {
return;
}
if (view->type == C_WORKSPACE || view->type == C_VIEW) {
view->gaps = *data;
}
}
void add_gaps(swayc_t *view, void *_data) {
int *data = _data;
if (!ASSERT_NONNULL(view)) {
return;
}
if (view->type == C_WORKSPACE || view->type == C_VIEW) {
if ((view->gaps += *data) < 0) {
view->gaps = 0;
}
}
}

View file

@ -126,7 +126,7 @@ static void handle_output_destroyed(wlc_handle output) {
static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) {
sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h);
swayc_t *c = swayc_by_handle(output); swayc_t *c = swayc_by_test(test_handle, &output);
if (!c) return; if (!c) return;
c->width = to->w; c->width = to->w;
c->height = to->h; c->height = to->h;
@ -134,7 +134,7 @@ static void handle_output_resolution_change(wlc_handle output, const struct wlc_
} }
static void handle_output_focused(wlc_handle output, bool focus) { static void handle_output_focused(wlc_handle output, bool focus) {
swayc_t *c = swayc_by_handle(output); swayc_t *c = swayc_by_test(test_handle, &output);
// if for some reason this output doesnt exist, create it. // if for some reason this output doesnt exist, create it.
if (!c) { if (!c) {
handle_output_created(output); handle_output_created(output);
@ -152,7 +152,7 @@ static bool handle_view_created(wlc_handle handle) {
// Get parent container, to add view in // Get parent container, to add view in
if (parent) { if (parent) {
focused = swayc_by_handle(parent); focused = swayc_by_test(test_handle, &parent);
} }
if (!focused || focused->type == C_OUTPUT) { if (!focused || focused->type == C_OUTPUT) {
focused = get_focused_container(&root_container); focused = get_focused_container(&root_container);
@ -221,7 +221,7 @@ static bool handle_view_created(wlc_handle handle) {
static void handle_view_destroyed(wlc_handle handle) { static void handle_view_destroyed(wlc_handle handle) {
sway_log(L_DEBUG, "Destroying window %lu", handle); sway_log(L_DEBUG, "Destroying window %lu", handle);
swayc_t *view = swayc_by_handle(handle); swayc_t *view = swayc_by_test(test_handle, &handle);
// destroy views by type // destroy views by type
switch (wlc_view_get_type(handle)) { switch (wlc_view_get_type(handle)) {
@ -258,7 +258,7 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo
// If the view is floating, then apply the geometry. // If the view is floating, then apply the geometry.
// Otherwise save the desired width/height for the view. // Otherwise save the desired width/height for the view.
// This will not do anything for the time being as WLC improperly sends geometry requests // This will not do anything for the time being as WLC improperly sends geometry requests
swayc_t *view = swayc_by_handle(handle); swayc_t *view = swayc_by_test(test_handle, &handle);
if (view) { if (view) {
view->desired_width = geometry->size.w; view->desired_width = geometry->size.w;
view->desired_height = geometry->size.h; view->desired_height = geometry->size.h;
@ -274,7 +274,7 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo
} }
static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) {
swayc_t *c = swayc_by_handle(view); swayc_t *c = swayc_by_test(test_handle, &view);
switch (state) { switch (state) {
case WLC_BIT_FULLSCREEN: case WLC_BIT_FULLSCREEN:
// i3 just lets it become fullscreen // i3 just lets it become fullscreen

View file

@ -207,7 +207,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_GET_WORKSPACES: case IPC_GET_WORKSPACES:
{ {
json_object *workspaces = json_object_new_array(); json_object *workspaces = json_object_new_array();
container_map(&root_container, ipc_get_workspaces_callback, workspaces); swayc_map(ipc_get_workspaces_callback, workspaces);
const char *json_string = json_object_to_json_string(workspaces); const char *json_string = json_object_to_json_string(workspaces);
ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
json_object_put(workspaces); // free json_object_put(workspaces); // free
@ -216,7 +216,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_GET_OUTPUTS: case IPC_GET_OUTPUTS:
{ {
json_object *outputs = json_object_new_array(); json_object *outputs = json_object_new_array();
container_map(&root_container, ipc_get_outputs_callback, outputs); swayc_map(ipc_get_outputs_callback, outputs);
const char *json_string = json_object_to_json_string(outputs); const char *json_string = json_object_to_json_string(outputs);
ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
json_object_put(outputs); // free json_object_put(outputs); // free

View file

@ -258,7 +258,7 @@ int unescape_string(char *string) {
return len - shift; return len - shift;
} }
char *join_args(char **argv, int argc) { char *join_args(int argc, char **argv) {
int len = 0, i; int len = 0, i;
for (i = 0; i < argc; ++i) { for (i = 0; i < argc; ++i) {
len += strlen(argv[i]) + 1; len += strlen(argv[i]) + 1;

View file

@ -15,7 +15,26 @@
char *prev_workspace_name = NULL; char *prev_workspace_name = NULL;
char *workspace_next_name(void) { static swayc_t *workspace_by_name_only(const char *name);
const char *workspace_output_open_name(swayc_t *output) {
struct workspace_output *wsop;
int i, len = config->workspace_outputs->length;
// Search config for output
for (i = 0; i < len; ++i) {
wsop = config->workspace_outputs->items[i];
// Find matching outputs
if (strcasecmp(wsop->output, output->name)) {
// Check if workspace is available and use that name
if (!workspace_by_name(wsop->workspace)) {
return wsop->workspace;
}
}
}
return NULL;
}
const char *workspace_next_name(void) {
sway_log(L_DEBUG, "Workspace: Generating new name"); sway_log(L_DEBUG, "Workspace: Generating new name");
int i; int i;
int l = 1; int l = 1;
@ -25,42 +44,29 @@ char *workspace_next_name(void) {
for (i = 0; i < mode->bindings->length; ++i) { for (i = 0; i < mode->bindings->length; ++i) {
struct sway_binding *binding = mode->bindings->items[i]; struct sway_binding *binding = mode->bindings->items[i];
const char* command = binding->command; const char *command = binding->command;
list_t *args = split_string(command, " "); const char *ws = "workspace";
const int wslen = sizeof("workspace") - 1;
if (strcmp("workspace", args->items[0]) == 0 && args->length > 1) { if (strncmp(ws, command, wslen) == 0) {
sway_log(L_DEBUG, "Got valid workspace command for target: '%s'", (char *)args->items[1]); command += wslen;
char* target = malloc(strlen(args->items[1]) + 1); // Skip whitespace
strcpy(target, args->items[1]); command += strspn(command, whitespace);
while (*target == ' ' || *target == '\t') // make sure its not a special command
target++; if (strcmp(command, "next") == 0
|| strcmp(command, "prev") == 0
// Make sure that the command references an actual workspace || strcmp(command, "next_on_output") == 0
// not a command about workspaces || strcmp(command, "prev_on_output") == 0
if (strcmp(target, "next") == 0 || || strcmp(command, "number") == 0
strcmp(target, "prev") == 0 || || strcmp(command, "back_and_forth") == 0
strcmp(target, "next_on_output") == 0 || || strcmp(command, "current") == 0
strcmp(target, "prev_on_output") == 0 || // Or if it already exists
strcmp(target, "number") == 0 || || workspace_by_name_only(command)) {
strcmp(target, "back_and_forth") == 0 ||
strcmp(target, "current") == 0)
{
free_flat_list(args);
continue; continue;
} else {
// otherwise we found it
return command;
} }
// Make sure that the workspace doesn't already exist
if (workspace_by_name(target)) {
free_flat_list(args);
continue;
} }
free_flat_list(args);
sway_log(L_DEBUG, "Workspace: Found free name %s", target);
return target;
}
free_flat_list(args);
} }
// As a fall back, get the current number of active workspaces // As a fall back, get the current number of active workspaces
// and return that + 1 for the next workspace's name // and return that + 1 for the next workspace's name
@ -75,55 +81,40 @@ char *workspace_next_name(void) {
return name; return name;
} }
swayc_t *workspace_create(const char* name) { swayc_t *workspace_by_name_only(const char *name) {
swayc_t *parent; int i, len = root_container.children->length;
// Search for workspace<->output pair for (i = 0; i < len; ++i) {
int i, e = config->workspace_outputs->length; swayc_t *op = root_container.children->items[i];
for (i = 0; i < e; ++i) { int i, len = op->children->length;
struct workspace_output *wso = config->workspace_outputs->items[i]; for (i = 0; i < len; ++i) {
if (strcasecmp(wso->workspace, name) == 0) swayc_t *ws = op->children->items[i];
{ if (strcasecmp(ws->name, name) == 0) {
// Find output to use if it exists return ws;
e = root_container.children->length;
for (i = 0; i < e; ++i) {
parent = root_container.children->items[i];
if (strcmp(parent->name, wso->output) == 0) {
return new_workspace(parent, name);
} }
} }
break;
} }
} return NULL;
// Otherwise create a new one
parent = get_focused_container(&root_container);
parent = swayc_parent_by_type(parent, C_OUTPUT);
return new_workspace(parent, name);
}
static bool _workspace_by_name(swayc_t *view, void *data) {
return (view->type == C_WORKSPACE) &&
(strcasecmp(view->name, (char *) data) == 0);
} }
swayc_t *workspace_by_name(const char* name) { swayc_t *workspace_by_name(const char* name) {
if (strcmp(name, "prev") == 0) { if (strcmp(name, "prev") == 0) {
return workspace_prev(); return workspace_prev();
} } else if (!strcmp(name, "prev_on_output")) {
else if (strcmp(name, "prev_on_output") == 0) {
return workspace_output_prev(); return workspace_output_prev();
} } else if (!strcmp(name, "next")) {
else if (strcmp(name, "next") == 0) {
return workspace_next(); return workspace_next();
} } else if (!strcmp(name, "next_on_output")) {
else if (strcmp(name, "next_on_output") == 0) {
return workspace_output_next(); return workspace_output_next();
} } else if (!strcmp(name, "current")) {
else if (strcmp(name, "current") == 0) { return swayc_active_workspace();
} else if (!strcmp(name, "back_and_forth")) {
if (prev_workspace_name) {
name = prev_workspace_name;
} else { // If there is no prev workspace name. just return current
return swayc_active_workspace(); return swayc_active_workspace();
} }
else {
return swayc_by_test(&root_container, _workspace_by_name, (void *) name);
} }
return workspace_by_name_only(name);
} }
/** /**
@ -181,19 +172,19 @@ swayc_t *workspace_prev_next_impl(swayc_t *workspace, bool next) {
return NULL; return NULL;
} }
swayc_t *workspace_output_next() { swayc_t *workspace_output_next(void) {
return workspace_output_prev_next_impl(swayc_active_output(), true); return workspace_output_prev_next_impl(swayc_active_output(), true);
} }
swayc_t *workspace_next() { swayc_t *workspace_next(void) {
return workspace_prev_next_impl(swayc_active_workspace(), true); return workspace_prev_next_impl(swayc_active_workspace(), true);
} }
swayc_t *workspace_output_prev() { swayc_t *workspace_output_prev(void) {
return workspace_output_prev_next_impl(swayc_active_output(), false); return workspace_output_prev_next_impl(swayc_active_output(), false);
} }
swayc_t *workspace_prev() { swayc_t *workspace_prev(void) {
return workspace_prev_next_impl(swayc_active_workspace(), false); return workspace_prev_next_impl(swayc_active_workspace(), false);
} }
@ -202,17 +193,17 @@ void workspace_switch(swayc_t *workspace) {
return; return;
} }
swayc_t *active_ws = swayc_active_workspace(); swayc_t *active_ws = swayc_active_workspace();
if (config->auto_back_and_forth && active_ws == workspace && prev_workspace_name) { // set workspace to prev_workspace
swayc_t *new_ws = workspace_by_name(prev_workspace_name); if (config->auto_back_and_forth && active_ws == workspace) {
workspace = new_ws ? new_ws : workspace_create(prev_workspace_name); workspace = new_workspace(NULL, "back_and_forth");
} }
// set prev workspace name
if (!prev_workspace_name if (!prev_workspace_name
|| (strcmp(prev_workspace_name, active_ws->name) || (strcmp(prev_workspace_name, active_ws->name)
&& active_ws != workspace)) { && active_ws != workspace)) {
free(prev_workspace_name); free(prev_workspace_name);
prev_workspace_name = malloc(strlen(active_ws->name)+1); prev_workspace_name = strdup(active_ws->name);
strcpy(prev_workspace_name, active_ws->name);
} }
sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);