summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/ipc-server.h4
-rw-r--r--sway/commands.c154
-rw-r--r--sway/config.c2
-rw-r--r--sway/focus.c15
-rw-r--r--sway/ipc-server.c171
-rw-r--r--sway/layout.c7
-rw-r--r--swaybar/main.c30
7 files changed, 273 insertions, 110 deletions
diff --git a/include/ipc-server.h b/include/ipc-server.h
index 5ac255cf..ab9807ef 100644
--- a/include/ipc-server.h
+++ b/include/ipc-server.h
@@ -2,13 +2,15 @@
2#define _SWAY_IPC_SERVER_H 2#define _SWAY_IPC_SERVER_H
3 3
4#include "container.h" 4#include "container.h"
5#include "config.h"
5#include "ipc.h" 6#include "ipc.h"
6 7
7void ipc_init(void); 8void ipc_init(void);
8void ipc_terminate(void); 9void ipc_terminate(void);
9struct sockaddr_un *ipc_user_sockaddr(void); 10struct sockaddr_un *ipc_user_sockaddr(void);
10 11
11void ipc_event_workspace(swayc_t *old, swayc_t *new); 12void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change);
13void ipc_event_barconfig_update(struct bar_config *bar);
12const char *swayc_type_string(enum swayc_types type); 14const char *swayc_type_string(enum swayc_types type);
13 15
14#endif 16#endif
diff --git a/sway/commands.c b/sway/commands.c
index f6d9b947..b1b1c5b6 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -25,6 +25,7 @@
25#include "resize.h" 25#include "resize.h"
26#include "input_state.h" 26#include "input_state.h"
27#include "criteria.h" 27#include "criteria.h"
28#include "ipc-server.h"
28 29
29typedef struct cmd_results *sway_cmd(int argc, char **argv); 30typedef struct cmd_results *sway_cmd(int argc, char **argv);
30 31
@@ -1147,16 +1148,26 @@ static struct cmd_results *cmd_resize(int argc, char **argv) {
1147 1148
1148static struct cmd_results *cmd_bar(int argc, char **argv) { 1149static struct cmd_results *cmd_bar(int argc, char **argv) {
1149 struct cmd_results *error = NULL; 1150 struct cmd_results *error = NULL;
1150 if ((error = checkarg(argc, "bar", EXPECTED_EQUAL_TO, 1))) { 1151 if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) {
1151 return error; 1152 return error;
1152 } 1153 }
1153 1154
1154 if (strcmp("{", argv[0]) != 0) { 1155 if (config->reading && strcmp("{", argv[0]) != 0) {
1155 return cmd_results_new(CMD_INVALID, "bar", 1156 return cmd_results_new(CMD_INVALID, "bar",
1156 "Expected '{' at start of bar config definition."); 1157 "Expected '{' at start of bar config definition.");
1157 } 1158 }
1158 1159
1159 if (!config->reading) { 1160 if (!config->reading) {
1161 if (argc > 1) {
1162 if (strcasecmp("mode", argv[0]) == 0) {
1163 return bar_cmd_mode(argc-1, argv + 1);
1164 }
1165
1166 if (strcasecmp("hidden_state", argv[0]) == 0) {
1167 return bar_cmd_hidden_state(argc-1, argv + 1);
1168 }
1169 }
1170
1160 return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file."); 1171 return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file.");
1161 } 1172 }
1162 1173
@@ -1679,53 +1690,144 @@ static struct cmd_results *bar_cmd_height(int argc, char **argv) {
1679 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 1690 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1680} 1691}
1681 1692
1693static struct cmd_results *bar_set_hidden_state(struct bar_config *bar, const char *hidden_state) {
1694 char *old_state = bar->hidden_state;
1695 if (strcasecmp("toggle", hidden_state) == 0 && !config->reading) {
1696 if (strcasecmp("hide", bar->hidden_state) == 0) {
1697 bar->hidden_state = strdup("show");
1698 } else if (strcasecmp("show", bar->hidden_state) == 0) {
1699 bar->hidden_state = strdup("hide");
1700 }
1701 } else if (strcasecmp("hide", hidden_state) == 0) {
1702 bar->hidden_state = strdup("hide");
1703 } else if (strcasecmp("show", hidden_state) == 0) {
1704 bar->hidden_state = strdup("show");
1705 } else {
1706 return cmd_results_new(CMD_INVALID, "hidden_state", "Invalid value %s", hidden_state);
1707 }
1708
1709 if (strcmp(old_state, bar->hidden_state) != 0) {
1710 if (!config->reading) {
1711 ipc_event_barconfig_update(bar);
1712 }
1713 sway_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s", bar->hidden_state, bar->id);
1714 }
1715
1716 // free old mode
1717 free(old_state);
1718 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1719}
1720
1721
1682static struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { 1722static struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
1683 struct cmd_results *error = NULL; 1723 struct cmd_results *error = NULL;
1684 if ((error = checkarg(argc, "hidden_state", EXPECTED_EQUAL_TO, 1))) { 1724 if ((error = checkarg(argc, "hidden_state", EXPECTED_AT_LEAST, 1))) {
1725 return error;
1726 }
1727 if ((error = checkarg(argc, "hidden_state", EXPECTED_LESS_THAN, 3))) {
1685 return error; 1728 return error;
1686 } 1729 }
1687 1730
1731 if (config->reading && argc > 1) {
1732 return cmd_results_new(CMD_INVALID, "hidden_state", "Unexpected value %s in config mode", argv[1]);
1733 }
1734
1688 const char *state = argv[0]; 1735 const char *state = argv[0];
1689 char *old_state = config->current_bar->hidden_state;
1690 1736
1691 if (strcasecmp("hide", state) == 0) { 1737 if (config->reading) {
1692 config->current_bar->hidden_state = strdup(state); 1738 return bar_set_hidden_state(config->current_bar, state);
1693 } else if(strcmp("show", state) == 0) { 1739 }
1694 config->current_bar->hidden_state = strdup(state); 1740
1741 const char *id;
1742 if (argc == 2) {
1743 id = argv[1];
1744 }
1745
1746 int i;
1747 struct bar_config *bar;
1748 for (i = 0; i < config->bars->length; ++i) {
1749 bar = config->bars->items[i];
1750 if (id && strcmp(id, bar->id) == 0) {
1751 return bar_set_hidden_state(bar, state);
1752 }
1753
1754 error = bar_set_hidden_state(bar, state);
1755 if (error) {
1756 return error;
1757 }
1758 }
1759
1760 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1761}
1762
1763static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode) {
1764 char *old_mode = bar->mode;
1765 if (strcasecmp("toggle", mode) == 0 && !config->reading) {
1766 if (strcasecmp("dock", bar->mode) == 0) {
1767 bar->mode = strdup("hide");
1768 } else if (strcasecmp("hide", bar->mode) == 0) {
1769 bar->mode = strdup("dock");
1770 }
1771 } else if (strcasecmp("dock", mode) == 0) {
1772 bar->mode = strdup("dock");
1773 } else if (strcasecmp("hide", mode) == 0) {
1774 bar->mode = strdup("hide");
1775 } else if (strcasecmp("invisible", mode) == 0) {
1776 bar->mode = strdup("invisible");
1695 } else { 1777 } else {
1696 return cmd_results_new(CMD_INVALID, "hidden_state", "Invalid value %s", state); 1778 return cmd_results_new(CMD_INVALID, "mode", "Invalid value %s", mode);
1697 } 1779 }
1698 1780
1699 sway_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s", state, config->current_bar->id); 1781 if (strcmp(old_mode, bar->mode) != 0) {
1782 if (!config->reading) {
1783 ipc_event_barconfig_update(bar);
1784 }
1785 sway_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id);
1786 }
1700 1787
1701 // free old state 1788 // free old mode
1702 free(old_state); 1789 free(old_mode);
1703 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 1790 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1704} 1791}
1705 1792
1706static struct cmd_results *bar_cmd_mode(int argc, char **argv) { 1793static struct cmd_results *bar_cmd_mode(int argc, char **argv) {
1707 struct cmd_results *error = NULL; 1794 struct cmd_results *error = NULL;
1708 if ((error = checkarg(argc, "mode", EXPECTED_EQUAL_TO, 1))) { 1795 if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) {
1796 return error;
1797 }
1798 if ((error = checkarg(argc, "mode", EXPECTED_LESS_THAN, 3))) {
1709 return error; 1799 return error;
1710 } 1800 }
1711 1801
1802 if (config->reading && argc > 1) {
1803 return cmd_results_new(CMD_INVALID, "mode", "Unexpected value %s in config mode", argv[1]);
1804 }
1805
1712 const char *mode = argv[0]; 1806 const char *mode = argv[0];
1713 char *old_mode = config->current_bar->mode; 1807
1714 1808 if (config->reading) {
1715 if (strcasecmp("dock", mode) == 0) { 1809 return bar_set_mode(config->current_bar, mode);
1716 config->current_bar->mode = strdup(mode);
1717 } else if(strcmp("hide", mode) == 0) {
1718 config->current_bar->mode = strdup(mode);
1719 } else if(strcmp("invisible", mode) == 0) {
1720 config->current_bar->mode = strdup(mode);
1721 } else {
1722 return cmd_results_new(CMD_INVALID, "mode", "Invalid value %s", mode);
1723 } 1810 }
1724 1811
1725 sway_log(L_DEBUG, "Setting mode: '%s' for bar: %s", mode, config->current_bar->id); 1812 const char *id;
1813 if (argc == 2) {
1814 id = argv[1];
1815 }
1816
1817 int i;
1818 struct bar_config *bar;
1819 for (i = 0; i < config->bars->length; ++i) {
1820 bar = config->bars->items[i];
1821 if (id && strcmp(id, bar->id) == 0) {
1822 return bar_set_mode(bar, mode);
1823 }
1824
1825 error = bar_set_mode(bar, mode);
1826 if (error) {
1827 return error;
1828 }
1829 }
1726 1830
1727 // free old mode
1728 free(old_mode);
1729 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 1831 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1730} 1832}
1731 1833
diff --git a/sway/config.c b/sway/config.c
index e86eda53..853a7111 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -701,7 +701,7 @@ struct bar_config *default_bar_config(void) {
701 bar->bindings = create_list(); 701 bar->bindings = create_list();
702 bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p' && sleep 1; done"); 702 bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p' && sleep 1; done");
703 bar->swaybar_command = NULL; 703 bar->swaybar_command = NULL;
704 bar->font = strdup("monospace 10"); 704 bar->font = strdup("pango:monospace 10");
705 bar->height = -1; 705 bar->height = -1;
706 bar->workspace_buttons = true; 706 bar->workspace_buttons = true;
707 bar->separator_symbol = NULL; 707 bar->separator_symbol = NULL;
diff --git a/sway/focus.c b/sway/focus.c
index c1170ca4..cf0ee7f6 100644
--- a/sway/focus.c
+++ b/sway/focus.c
@@ -34,7 +34,7 @@ static void update_focus(swayc_t *c) {
34 // Case where workspace changes 34 // Case where workspace changes
35 case C_WORKSPACE: 35 case C_WORKSPACE:
36 if (prev) { 36 if (prev) {
37 ipc_event_workspace(prev, c); 37 ipc_event_workspace(prev, c, "focus");
38 // update visibility of old workspace 38 // update visibility of old workspace
39 update_visibility(prev); 39 update_visibility(prev);
40 40
@@ -122,11 +122,6 @@ bool set_focused_container(swayc_t *c) {
122 p = p->parent; 122 p = p->parent;
123 p->is_focused = false; 123 p->is_focused = false;
124 } 124 }
125 // active_ws might have been destroyed by now
126 // (focus swap away from empty ws = destroy ws)
127 if (active_ws_child_count == 0) {
128 active_ws = NULL;
129 }
130 125
131 // get new focused view and set focus to it. 126 // get new focused view and set focus to it.
132 p = get_focused_view(c); 127 p = get_focused_view(c);
@@ -146,7 +141,13 @@ bool set_focused_container(swayc_t *c) {
146 } 141 }
147 142
148 if (active_ws != workspace) { 143 if (active_ws != workspace) {
149 ipc_event_workspace(active_ws, workspace); 144 // active_ws might have been destroyed by now
145 // (focus swap away from empty ws = destroy ws)
146 if (active_ws_child_count == 0) {
147 active_ws = NULL;
148 }
149
150 ipc_event_workspace(active_ws, workspace, "focus");
150 } 151 }
151 return true; 152 return true;
152} 153}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 9dd3e1a5..e161c756 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -43,6 +43,7 @@ void ipc_client_handle_command(struct ipc_client *client);
43bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); 43bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length);
44void ipc_get_workspaces_callback(swayc_t *workspace, void *data); 44void ipc_get_workspaces_callback(swayc_t *workspace, void *data);
45void ipc_get_outputs_callback(swayc_t *container, void *data); 45void ipc_get_outputs_callback(swayc_t *container, void *data);
46json_object *ipc_json_describe_bar_config(struct bar_config *bar);
46 47
47void ipc_init(void) { 48void ipc_init(void) {
48 ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); 49 ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
@@ -290,8 +291,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
290 const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); 291 const char *event_type = json_object_get_string(json_object_array_get_idx(request, i));
291 if (strcmp(event_type, "workspace") == 0) { 292 if (strcmp(event_type, "workspace") == 0) {
292 client->subscribed_events |= IPC_GET_WORKSPACES; 293 client->subscribed_events |= IPC_GET_WORKSPACES;
293 } 294 } else if (strcmp(event_type, "barconfig_update") == 0) {
294 else { 295 client->subscribed_events |= IPC_GET_BAR_CONFIG;
296 } else {
295 ipc_send_reply(client, "{\"success\": false}", 18); 297 ipc_send_reply(client, "{\"success\": false}", 18);
296 ipc_client_disconnect(client); 298 ipc_client_disconnect(client);
297 json_object_put(request); 299 json_object_put(request);
@@ -397,64 +399,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
397 ipc_send_reply(client, error, (uint32_t)strlen(error)); 399 ipc_send_reply(client, error, (uint32_t)strlen(error));
398 break; 400 break;
399 } 401 }
400 json_object *json = json_object_new_object(); 402 json_object *json = ipc_json_describe_bar_config(bar);
401 json_object_object_add(json, "id", json_object_new_string(bar->id));
402 json_object_object_add(json, "tray_output", NULL);
403 json_object_object_add(json, "mode", json_object_new_string(bar->mode));
404 json_object_object_add(json, "hidden_state", json_object_new_string(bar->hidden_state));
405 //json_object_object_add(json, "modifier", json_object_new_string(bar->modifier)); // TODO: Fix modifier
406 switch (bar->position) {
407 case DESKTOP_SHELL_PANEL_POSITION_TOP:
408 json_object_object_add(json, "position", json_object_new_string("top"));
409 break;
410 case DESKTOP_SHELL_PANEL_POSITION_BOTTOM:
411 json_object_object_add(json, "position", json_object_new_string("bottom"));
412 break;
413 case DESKTOP_SHELL_PANEL_POSITION_LEFT:
414 json_object_object_add(json, "position", json_object_new_string("left"));
415 break;
416 case DESKTOP_SHELL_PANEL_POSITION_RIGHT:
417 json_object_object_add(json, "position", json_object_new_string("right"));
418 break;
419 }
420 json_object_object_add(json, "status_command", json_object_new_string(bar->status_command));
421 json_object_object_add(json, "font", json_object_new_string(bar->font));
422 if (bar->separator_symbol) {
423 json_object_object_add(json, "separator_symbol", json_object_new_string(bar->separator_symbol));
424 }
425 json_object_object_add(json, "bar_height", json_object_new_int(bar->height));
426 json_object_object_add(json, "workspace_buttons", json_object_new_boolean(bar->workspace_buttons));
427 json_object_object_add(json, "strip_workspace_numbers", json_object_new_boolean(bar->strip_workspace_numbers));
428 json_object_object_add(json, "binding_mode_indicator", json_object_new_boolean(bar->binding_mode_indicator));
429 json_object_object_add(json, "verbose", json_object_new_boolean(bar->verbose));
430
431 json_object *colors = json_object_new_object();
432 json_object_object_add(colors, "background", json_object_new_string(bar->colors.background));
433 json_object_object_add(colors, "statusline", json_object_new_string(bar->colors.statusline));
434 json_object_object_add(colors, "separator", json_object_new_string(bar->colors.separator));
435
436 json_object_object_add(colors, "focused_workspace_border", json_object_new_string(bar->colors.focused_workspace_border));
437 json_object_object_add(colors, "focused_workspace_bg", json_object_new_string(bar->colors.focused_workspace_bg));
438 json_object_object_add(colors, "focused_workspace_text", json_object_new_string(bar->colors.focused_workspace_text));
439
440 json_object_object_add(colors, "inactive_workspace_border", json_object_new_string(bar->colors.inactive_workspace_border));
441 json_object_object_add(colors, "inactive_workspace_bg", json_object_new_string(bar->colors.inactive_workspace_bg));
442 json_object_object_add(colors, "inactive_workspace_text", json_object_new_string(bar->colors.inactive_workspace_text));
443
444 json_object_object_add(colors, "active_workspace_border", json_object_new_string(bar->colors.active_workspace_border));
445 json_object_object_add(colors, "active_workspace_bg", json_object_new_string(bar->colors.active_workspace_bg));
446 json_object_object_add(colors, "active_workspace_text", json_object_new_string(bar->colors.active_workspace_text));
447
448 json_object_object_add(colors, "urgent_workspace_border", json_object_new_string(bar->colors.urgent_workspace_border));
449 json_object_object_add(colors, "urgent_workspace_bg", json_object_new_string(bar->colors.urgent_workspace_bg));
450 json_object_object_add(colors, "urgent_workspace_text", json_object_new_string(bar->colors.urgent_workspace_text));
451
452 json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.binding_mode_border));
453 json_object_object_add(colors, "binding_mode_bg", json_object_new_string(bar->colors.binding_mode_bg));
454 json_object_object_add(colors, "binding_mode_text", json_object_new_string(bar->colors.binding_mode_text));
455
456 json_object_object_add(json, "colors", colors);
457
458 const char *json_string = json_object_to_json_string(json); 403 const char *json_string = json_object_to_json_string(json);
459 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 404 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
460 json_object_put(json); // free 405 json_object_put(json); // free
@@ -551,22 +496,114 @@ void ipc_get_outputs_callback(swayc_t *container, void *data) {
551 } 496 }
552} 497}
553 498
554void ipc_event_workspace(swayc_t *old, swayc_t *new) { 499json_object *ipc_json_describe_bar_config(struct bar_config *bar) {
500 if (!sway_assert(bar, "Bar must not be NULL")) {
501 return NULL;
502 }
503
504 json_object *json = json_object_new_object();
505 json_object_object_add(json, "id", json_object_new_string(bar->id));
506 json_object_object_add(json, "tray_output", NULL);
507 json_object_object_add(json, "mode", json_object_new_string(bar->mode));
508 json_object_object_add(json, "hidden_state", json_object_new_string(bar->hidden_state));
509 //json_object_object_add(json, "modifier", json_object_new_string(bar->modifier)); // TODO: Fix modifier
510 switch (bar->position) {
511 case DESKTOP_SHELL_PANEL_POSITION_TOP:
512 json_object_object_add(json, "position", json_object_new_string("top"));
513 break;
514 case DESKTOP_SHELL_PANEL_POSITION_BOTTOM:
515 json_object_object_add(json, "position", json_object_new_string("bottom"));
516 break;
517 case DESKTOP_SHELL_PANEL_POSITION_LEFT:
518 json_object_object_add(json, "position", json_object_new_string("left"));
519 break;
520 case DESKTOP_SHELL_PANEL_POSITION_RIGHT:
521 json_object_object_add(json, "position", json_object_new_string("right"));
522 break;
523 }
524 json_object_object_add(json, "status_command", json_object_new_string(bar->status_command));
525 json_object_object_add(json, "font", json_object_new_string(bar->font));
526 if (bar->separator_symbol) {
527 json_object_object_add(json, "separator_symbol", json_object_new_string(bar->separator_symbol));
528 }
529 json_object_object_add(json, "bar_height", json_object_new_int(bar->height));
530 json_object_object_add(json, "workspace_buttons", json_object_new_boolean(bar->workspace_buttons));
531 json_object_object_add(json, "strip_workspace_numbers", json_object_new_boolean(bar->strip_workspace_numbers));
532 json_object_object_add(json, "binding_mode_indicator", json_object_new_boolean(bar->binding_mode_indicator));
533 json_object_object_add(json, "verbose", json_object_new_boolean(bar->verbose));
534
535 json_object *colors = json_object_new_object();
536 json_object_object_add(colors, "background", json_object_new_string(bar->colors.background));
537 json_object_object_add(colors, "statusline", json_object_new_string(bar->colors.statusline));
538 json_object_object_add(colors, "separator", json_object_new_string(bar->colors.separator));
539
540 json_object_object_add(colors, "focused_workspace_border", json_object_new_string(bar->colors.focused_workspace_border));
541 json_object_object_add(colors, "focused_workspace_bg", json_object_new_string(bar->colors.focused_workspace_bg));
542 json_object_object_add(colors, "focused_workspace_text", json_object_new_string(bar->colors.focused_workspace_text));
543
544 json_object_object_add(colors, "inactive_workspace_border", json_object_new_string(bar->colors.inactive_workspace_border));
545 json_object_object_add(colors, "inactive_workspace_bg", json_object_new_string(bar->colors.inactive_workspace_bg));
546 json_object_object_add(colors, "inactive_workspace_text", json_object_new_string(bar->colors.inactive_workspace_text));
547
548 json_object_object_add(colors, "active_workspace_border", json_object_new_string(bar->colors.active_workspace_border));
549 json_object_object_add(colors, "active_workspace_bg", json_object_new_string(bar->colors.active_workspace_bg));
550 json_object_object_add(colors, "active_workspace_text", json_object_new_string(bar->colors.active_workspace_text));
551
552 json_object_object_add(colors, "urgent_workspace_border", json_object_new_string(bar->colors.urgent_workspace_border));
553 json_object_object_add(colors, "urgent_workspace_bg", json_object_new_string(bar->colors.urgent_workspace_bg));
554 json_object_object_add(colors, "urgent_workspace_text", json_object_new_string(bar->colors.urgent_workspace_text));
555
556 json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.binding_mode_border));
557 json_object_object_add(colors, "binding_mode_bg", json_object_new_string(bar->colors.binding_mode_bg));
558 json_object_object_add(colors, "binding_mode_text", json_object_new_string(bar->colors.binding_mode_text));
559
560 json_object_object_add(json, "colors", colors);
561
562 return json;
563}
564
565void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) {
555 json_object *obj = json_object_new_object(); 566 json_object *obj = json_object_new_object();
556 json_object_object_add(obj, "change", json_object_new_string("focus")); 567 json_object_object_add(obj, "change", json_object_new_string(change));
557 if (old) { 568 if (strcmp("focus", change) == 0) {
558 json_object_object_add(obj, "old", ipc_json_describe_workspace(old)); 569 if (old) {
570 json_object_object_add(obj, "old", ipc_json_describe_workspace(old));
571 } else {
572 json_object_object_add(obj, "old", NULL);
573 }
574 }
575
576 if (new) {
577 json_object_object_add(obj, "current", ipc_json_describe_workspace(new));
559 } else { 578 } else {
560 json_object_object_add(obj, "old", NULL); 579 json_object_object_add(obj, "current", NULL);
561 } 580 }
562 json_object_object_add(obj, "current", ipc_json_describe_workspace(new)); 581
563 const char *json_string = json_object_to_json_string(obj); 582 const char *json_string = json_object_to_json_string(obj);
564 583
565 for (int i = 0; i < ipc_client_list->length; i++) { 584 for (int i = 0; i < ipc_client_list->length; i++) {
566 struct ipc_client *client = ipc_client_list->items[i]; 585 struct ipc_client *client = ipc_client_list->items[i];
567 if ((client->subscribed_events & IPC_GET_WORKSPACES) == 0) break; 586 if ((client->subscribed_events & IPC_GET_WORKSPACES) == 0) {
587 continue;
588 }
568 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); 589 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
569 } 590 }
570 591
571 json_object_put(obj); // free 592 json_object_put(obj); // free
572} 593}
594
595void ipc_event_barconfig_update(struct bar_config *bar) {
596 json_object *json = ipc_json_describe_bar_config(bar);
597 const char *json_string = json_object_to_json_string(json);
598 int i;
599 struct ipc_client *client;
600 for (i = 0; i < ipc_client_list->length; ++i) {
601 client = ipc_client_list->items[i];
602 if ((client->subscribed_events & IPC_GET_BAR_CONFIG) == 0) {
603 continue;
604 }
605 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
606 }
607
608 json_object_put(json); // free
609}
diff --git a/sway/layout.c b/sway/layout.c
index a9e7c7f1..563e9d11 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -10,6 +10,7 @@
10#include "workspace.h" 10#include "workspace.h"
11#include "focus.h" 11#include "focus.h"
12#include "output.h" 12#include "output.h"
13#include "ipc-server.h"
13 14
14swayc_t root_container; 15swayc_t root_container;
15list_t *scratchpad; 16list_t *scratchpad;
@@ -312,6 +313,12 @@ void move_container_to(swayc_t* container, swayc_t* destination) {
312 // reset container geometry 313 // reset container geometry
313 container->width = container->height = 0; 314 container->width = container->height = 0;
314 add_child(destination, container); 315 add_child(destination, container);
316
317 // If the workspace only has one child after adding one, it
318 // means that the workspace was just initialized.
319 if (destination->children->length + destination->floating->length == 1) {
320 ipc_event_workspace(NULL, destination, "init");
321 }
315 } else { 322 } else {
316 // reset container geometry 323 // reset container geometry
317 container->width = container->height = 0; 324 container->width = container->height = 0;
diff --git a/swaybar/main.c b/swaybar/main.c
index 88cd1dbe..4323d370 100644
--- a/swaybar/main.c
+++ b/swaybar/main.c
@@ -5,6 +5,7 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include <unistd.h> 6#include <unistd.h>
7#include <sys/select.h> 7#include <sys/select.h>
8#include <sys/wait.h>
8#include <errno.h> 9#include <errno.h>
9#include <json-c/json.h> 10#include <json-c/json.h>
10#include <sys/un.h> 11#include <sys/un.h>
@@ -87,7 +88,7 @@ struct colors colors = {
87 }, 88 },
88}; 89};
89 90
90void sway_terminate(void) { 91void swaybar_teardown() {
91 window_teardown(window); 92 window_teardown(window);
92 if (registry) { 93 if (registry) {
93 registry_teardown(registry); 94 registry_teardown(registry);
@@ -99,16 +100,31 @@ void sway_terminate(void) {
99 100
100 if (pid) { 101 if (pid) {
101 // terminate status_command process 102 // terminate status_command process
102 kill(pid, SIGTERM); 103 int ret = kill(pid, SIGTERM);
104 if (ret != 0) {
105 sway_log(L_ERROR, "Unable to terminate status_command [pid: %d]", pid);
106 } else {
107 int status;
108 waitpid(pid, &status, 0);
109 }
103 } 110 }
104 111
105 if (pipefd[0]) { 112 if (pipefd[0]) {
106 close(pipefd[0]); 113 close(pipefd[0]);
107 } 114 }
115}
116
108 117
118void sway_terminate(void) {
119 swaybar_teardown();
109 exit(EXIT_FAILURE); 120 exit(EXIT_FAILURE);
110} 121}
111 122
123void sig_handler(int signal) {
124 swaybar_teardown();
125 exit(0);
126}
127
112void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { 128void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
113 cairo_set_source_rgba(cairo, 129 cairo_set_source_rgba(cairo,
114 ((color & 0xFF000000) >> 24) / 256.0, 130 ((color & 0xFF000000) >> 24) / 256.0,
@@ -525,14 +541,12 @@ int main(int argc, char **argv) {
525 line[0] = '\0'; 541 line[0] = '\0';
526 } 542 }
527 543
544 signal(SIGTERM, sig_handler);
545
528 poll_for_update(); 546 poll_for_update();
529 547
530 window_teardown(window); 548 // gracefully shutdown swaybar and status_command
531 registry_teardown(registry); 549 swaybar_teardown();
532 fclose(command);
533 // terminate status_command process
534 kill(pid, SIGTERM);
535 close(pipefd[0]);
536 550
537 return 0; 551 return 0;
538} 552}