From c98ef97eedf286ef4b6aea2728571f7480bcde45 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Thu, 16 Jul 2020 12:11:09 -0700 Subject: [PATCH] ipc: add query for mode bindings --- include/sway/ipc-json.h | 2 + sway/ipc-json.c | 191 ++++++++++++++++++++++++++++++++++++++++ sway/ipc-server.c | 115 ++++++++---------------- 3 files changed, 232 insertions(+), 76 deletions(-) diff --git a/include/sway/ipc-json.h b/include/sway/ipc-json.h index bc9f49856..96d69858c 100644 --- a/include/sway/ipc-json.h +++ b/include/sway/ipc-json.h @@ -8,6 +8,8 @@ json_object *ipc_json_get_version(void); json_object *ipc_json_get_binding_mode(void); +json_object *ipc_json_describe_binding(struct sway_binding *binding); +json_object *ipc_json_describe_binding_mode(struct sway_mode *mode); json_object *ipc_json_describe_disabled_output(struct sway_output *o); json_object *ipc_json_describe_non_desktop_output(struct sway_output_non_desktop *o); diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 763fb3fef..898d4c747 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -16,6 +16,7 @@ #include "sway/output.h" #include "sway/input/input-manager.h" #include "sway/input/cursor.h" +#include "sway/input/keyboard.h" #include "sway/input/seat.h" #include "wlr-layer-shell-unstable-v1-protocol.h" #include "sway/desktop/idle_inhibit_v1.h" @@ -1319,3 +1320,193 @@ json_object *ipc_json_get_binding_mode(void) { json_object_new_string(config->current_mode->name)); return current_mode; } + +json_object *ipc_json_describe_binding_flags(uint32_t flags) { + json_object *json_flags = json_object_new_array(); + if (flags & BINDING_RELEASE) { + json_object_array_add(json_flags, json_object_new_string("release")); + } else if (flags & BINDING_LOCKED) { + json_object_array_add(json_flags, json_object_new_string("locked")); + } else if (flags & BINDING_BORDER) { + json_object_array_add(json_flags, json_object_new_string("border")); + } else if (flags & BINDING_CONTENTS) { + json_object_array_add(json_flags, json_object_new_string("contents")); + } else if (flags & BINDING_TITLEBAR) { + json_object_array_add(json_flags, json_object_new_string("titlebar")); + } else if (flags & BINDING_CODE) { + json_object_array_add(json_flags, json_object_new_string("code")); + } else if (flags & BINDING_RELOAD) { + json_object_array_add(json_flags, json_object_new_string("reload")); + } else if (flags & BINDING_INHIBITED) { + json_object_array_add(json_flags, json_object_new_string("inhibited")); + } else if (flags & BINDING_NOREPEAT) { + json_object_array_add(json_flags, json_object_new_string("norepeat")); + } + return json_flags; +} + +json_object *ipc_json_describe_switch_binding(struct sway_switch_binding *binding) { + json_object *json_binding = json_object_new_object(); + json_object_object_add(json_binding, "command", json_object_new_string(binding->command)); + + json_object *type = NULL; + switch (binding->type) { + case WLR_SWITCH_TYPE_LID: + type = json_object_new_string("lid"); + break; + case WLR_SWITCH_TYPE_TABLET_MODE: + type = json_object_new_string("tablet_mode"); + break; + } + json_object_object_add(json_binding, "type", type); + + json_object *trigger = NULL; + switch (binding->trigger) { + case SWAY_SWITCH_TRIGGER_OFF: + trigger = json_object_new_string("off"); + break; + case SWAY_SWITCH_TRIGGER_ON: + trigger = json_object_new_string("on"); + break; + case SWAY_SWITCH_TRIGGER_TOGGLE: + trigger = json_object_new_string("on"); + break; + } + json_object_object_add(json_binding, "trigger", trigger); + + json_object *flags = ipc_json_describe_binding_flags(binding->flags); + json_object_object_add(json_binding, "flags", flags); + + return json_binding; +} + +json_object *ipc_json_describe_binding(struct sway_binding *binding) { + json_object *json_binding = json_object_new_object(); + json_object_object_add(json_binding, "command", json_object_new_string(binding->command)); + + const char *names[10]; + int len = get_modifier_names(names, binding->modifiers); + json_object *modifiers = json_object_new_array(); + for (int i = 0; i < len; ++i) { + json_object_array_add(modifiers, json_object_new_string(names[i])); + } + json_object_object_add(json_binding, "modifiers", modifiers); + + json_object *input_codes = json_object_new_array(); + int input_code = 0; + json_object *symbols = json_object_new_array(); + json_object *symbol = NULL; + + json_object *binding_flags = ipc_json_describe_binding_flags(binding->flags); + json_object_object_add(json_binding, "flags", binding_flags); + + switch (binding->type) { + case BINDING_KEYCODE: + json_object_object_add(json_binding, "type", json_object_new_string("keycode")); + // bindcode: populate input_codes + uint32_t keycode; + for (int i = 0; i < binding->keys->length; ++i) { + keycode = *(uint32_t *)binding->keys->items[i]; + json_object_array_add(input_codes, json_object_new_int(keycode)); + if (i == 0) { + input_code = keycode; + } + } + break; + + case BINDING_KEYSYM: + json_object_object_add(json_binding, "type", json_object_new_string("keysym")); + goto symbols; + case BINDING_MOUSESYM: + json_object_object_add(json_binding, "type", json_object_new_string("mousesym")); + goto symbols; + case BINDING_MOUSECODE: + json_object_object_add(json_binding, "type", json_object_new_string("mousecode")); + symbols:; // bindsym/mouse: populate symbols + uint32_t keysym; + char buffer[64]; + for (int i = 0; i < binding->keys->length; ++i) { + keysym = *(uint32_t *)binding->keys->items[i]; + if (keysym >= BTN_LEFT && keysym <= BTN_LEFT + 8) { + snprintf(buffer, 64, "button%u", keysym - BTN_LEFT + 1); + } else if (xkb_keysym_get_name(keysym, buffer, 64) < 0) { + continue; + } + + json_object *str = json_object_new_string(buffer); + if (i == 0) { + // str is owned by both symbol and symbols. Make sure + // to bump the ref count. + json_object_array_add(symbols, json_object_get(str)); + symbol = str; + } else { + json_object_array_add(symbols, str); + } + } + break; + + default: + json_object_put(input_codes); + json_object_put(symbols); + json_object_put(json_binding); + return NULL; // do not send any event + } + + json_object_object_add(json_binding, "input_codes", input_codes); + json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); + json_object_object_add(json_binding, "symbols", symbols); + json_object_object_add(json_binding, "symbol", symbol); + + bool mouse = binding->type == BINDING_MOUSECODE || + binding->type == BINDING_MOUSESYM; + json_object_object_add(json_binding, "input_type", mouse + ? json_object_new_string("mouse") + : json_object_new_string("keyboard")); + + json_object_object_add(json_binding, "input_device", + json_object_new_string(binding->input)); + + return json_binding; +} + +json_object *ipc_json_describe_binding_mode(struct sway_mode *mode) { + json_object *json_mode = json_object_new_object(); + json_object_object_add(json_mode, "name", json_object_new_string(mode->name)); + + json_object *bindings = json_object_new_array(); + for (int i = 0; i < mode->keysym_bindings->length; i++) { + struct sway_binding *binding = mode->keysym_bindings->items[i]; + json_object *json_binding = ipc_json_describe_binding(binding); + if (json_binding) { + json_object_array_add(bindings, json_binding); + } + } + + for (int i = 0; i < mode->keycode_bindings->length; i++) { + struct sway_binding *binding = mode->keycode_bindings->items[i]; + json_object *json_binding = ipc_json_describe_binding(binding); + if (json_binding) { + json_object_array_add(bindings, json_binding); + } + } + + for (int i = 0; i < mode->mouse_bindings->length; i++) { + struct sway_binding *binding = mode->mouse_bindings->items[i]; + json_object *json_binding = ipc_json_describe_binding(binding); + if (json_binding) { + json_object_array_add(bindings, json_binding); + } + } + + for (int i = 0; i < mode->switch_bindings->length; i++) { + struct sway_switch_binding *binding = mode->switch_bindings->items[i]; + json_object *json_binding = ipc_json_describe_switch_binding(binding); + if (json_binding) { + json_object_array_add(bindings, json_binding); + } + } + + json_object_object_add(json_mode, "bindings", bindings); + + return json_mode; +} diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 00b01d7dd..5d1ebd818 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -399,77 +399,17 @@ void ipc_event_binding(struct sway_binding *binding) { } sway_log(SWAY_DEBUG, "Sending binding event"); - json_object *json_binding = json_object_new_object(); - json_object_object_add(json_binding, "command", json_object_new_string(binding->command)); - - const char *names[10]; - int len = get_modifier_names(names, binding->modifiers); - json_object *modifiers = json_object_new_array(); - for (int i = 0; i < len; ++i) { - json_object_array_add(modifiers, json_object_new_string(names[i])); - } - json_object_object_add(json_binding, "event_state_mask", modifiers); - - json_object *input_codes = json_object_new_array(); - int input_code = 0; - json_object *symbols = json_object_new_array(); - json_object *symbol = NULL; - - switch (binding->type) { - case BINDING_KEYCODE:; // bindcode: populate input_codes - uint32_t keycode; - for (int i = 0; i < binding->keys->length; ++i) { - keycode = *(uint32_t *)binding->keys->items[i]; - json_object_array_add(input_codes, json_object_new_int(keycode)); - if (i == 0) { - input_code = keycode; - } - } - break; - - case BINDING_KEYSYM: - case BINDING_MOUSESYM: - case BINDING_MOUSECODE:; // bindsym/mouse: populate symbols - uint32_t keysym; - char buffer[64]; - for (int i = 0; i < binding->keys->length; ++i) { - keysym = *(uint32_t *)binding->keys->items[i]; - if (keysym >= BTN_LEFT && keysym <= BTN_LEFT + 8) { - snprintf(buffer, 64, "button%u", keysym - BTN_LEFT + 1); - } else if (xkb_keysym_get_name(keysym, buffer, 64) < 0) { - continue; - } - - json_object *str = json_object_new_string(buffer); - if (i == 0) { - // str is owned by both symbol and symbols. Make sure - // to bump the ref count. - json_object_array_add(symbols, json_object_get(str)); - symbol = str; - } else { - json_object_array_add(symbols, str); - } - } - break; - - default: + json_object *json_binding = ipc_json_describe_binding(binding); + if (!json_binding) { sway_log(SWAY_DEBUG, "Unsupported ipc binding event"); - json_object_put(input_codes); - json_object_put(symbols); - json_object_put(json_binding); return; // do not send any event } - json_object_object_add(json_binding, "input_codes", input_codes); - json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); - json_object_object_add(json_binding, "symbols", symbols); - json_object_object_add(json_binding, "symbol", symbol); - - bool mouse = binding->type == BINDING_MOUSECODE || - binding->type == BINDING_MOUSESYM; - json_object_object_add(json_binding, "input_type", mouse - ? json_object_new_string("mouse") - : json_object_new_string("keyboard")); + // Modifiers are "event_state_mask" in i3 ipc binding event + json_object *modifiers = json_object_object_get(json_binding, "modifiers"); + json_object_get(modifiers); + json_object_object_del(json_binding, "modifiers"); + json_object_object_add(json_binding, "event_state_mask", modifiers); json_object *json = json_object_new_object(); json_object_object_add(json, "change", json_object_new_string("run")); @@ -862,16 +802,39 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt case IPC_GET_BINDING_MODES: { - json_object *modes = json_object_new_array(); - for (int i = 0; i < config->modes->length; i++) { - struct sway_mode *mode = config->modes->items[i]; - json_object_array_add(modes, json_object_new_string(mode->name)); + if (!buf[0]) { + json_object *modes = json_object_new_array(); + for (int i = 0; i < config->modes->length; i++) { + struct sway_mode *mode = config->modes->items[i]; + json_object_array_add(modes, json_object_new_string(mode->name)); + } + const char *json_string = json_object_to_json_string(modes); + ipc_send_reply(client, payload_type, json_string, + (uint32_t)strlen(json_string)); + json_object_put(modes); // free + goto exit_cleanup; + } else { + struct sway_mode *mode = NULL; + for (int i = 0; i < config->modes->length; i++) { + mode = config->modes->items[i]; + if (strcmp(buf, mode->name) == 0) { + break; + } + mode = NULL; + } + if (!mode) { + const char *error = "{ \"success\": false, \"error\": \"No mode with that name\" }"; + ipc_send_reply(client, payload_type, error, + (uint32_t)strlen(error)); + goto exit_cleanup; + } else { + json_object *json_mode = ipc_json_describe_binding_mode(mode); + const char *json_string = json_object_to_json_string(json_mode); + ipc_send_reply(client, payload_type, json_string, (uint32_t)strlen(json_string)); + json_object_put(json_mode); + goto exit_cleanup; + } } - const char *json_string = json_object_to_json_string(modes); - ipc_send_reply(client, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(modes); // free - goto exit_cleanup; } case IPC_GET_BINDING_STATE: