From 493eaa78aaabae35a2f41acc887a5f9536de1b50 Mon Sep 17 00:00:00 2001 From: Bastien Dejean Date: Thu, 7 Nov 2013 14:28:39 +0100 Subject: [PATCH] Print status informations via control --subscribe --- Makefile | 2 +- bspc.c | 28 +++++-------- bspwm.c | 64 +++++++++-------------------- bspwm.h | 4 +- contrib/bash_completion | 2 +- contrib/lightdm/bspwm-session | 5 +-- contrib/zsh_completion | 2 +- doc/bspwm.1 | 39 +++++++----------- doc/bspwm.1.txt | 26 +++++------- examples/panel/panel | 8 +++- examples/panel/xinitrc | 3 -- messages.c | 16 ++++++-- messages.h | 4 +- settings.c | 1 + settings.h | 2 + subscribe.c | 77 +++++++++++++++++++++++++++++++++++ subscribe.h | 9 ++++ types.h | 8 ++++ 18 files changed, 180 insertions(+), 120 deletions(-) delete mode 100644 examples/panel/xinitrc create mode 100644 subscribe.c create mode 100644 subscribe.h diff --git a/Makefile b/Makefile index a355241..c790d05 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ BASHCPL = $(PREFIX)/share/bash-completion/completions ZSHCPL = $(PREFIX)/share/zsh/site-functions WM_SRC = bspwm.c helpers.c settings.c monitor.c desktop.c tree.c stack.c history.c \ - events.c pointer.c window.c messages.c query.c restore.c rule.c ewmh.c + events.c pointer.c window.c messages.c query.c restore.c rule.c ewmh.c subscribe.c WM_OBJ = $(WM_SRC:.c=.o) CL_SRC = bspc.c helpers.c CL_OBJ = $(CL_SRC:.c=.o) diff --git a/bspc.c b/bspc.c index 8fd7532..fd138f2 100644 --- a/bspc.c +++ b/bspc.c @@ -34,10 +34,9 @@ int main(int argc, char *argv[]) { - int sock_fd; + int fd; struct sockaddr_un sock_address; - char msg[BUFSIZ]; - char rsp[BUFSIZ]; + char msg[BUFSIZ], rsp[BUFSIZ]; if (argc < 2) err("No arguments given.\n"); @@ -55,31 +54,26 @@ int main(int argc, char *argv[]) msg_len += n; } - if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err("Failed to create the socket.\n"); - if (connect(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) + if (connect(fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) err("Failed to connect to the socket.\n"); - if (send(sock_fd, msg, msg_len, 0) == -1) + if (send(fd, msg, msg_len, 0) == -1) err("Failed to send the data.\n"); - int ret = EXIT_SUCCESS; - - int n = recv(sock_fd, rsp, sizeof(rsp), 0); - if (n == -1) { - err("Failed to get the response.\n"); - } else if (n > 0) { - if (n == 1 && rsp[0] == MESSAGE_FAILURE) { + int ret = EXIT_SUCCESS, nb; + while ((nb = recv(fd, rsp, sizeof(rsp), 0)) > 0) { + if (nb == 1 && rsp[0] == MESSAGE_FAILURE) { ret = EXIT_FAILURE; } else { - rsp[n] = '\0'; + rsp[nb] = '\0'; printf("%s\n", rsp); + fflush(stdout); } } - if (sock_fd) - close(sock_fd); - + close(fd); return ret; } diff --git a/bspwm.c b/bspwm.c index 606b4fd..342a06c 100644 --- a/bspwm.c +++ b/bspwm.c @@ -22,8 +22,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include #include #include #include @@ -33,15 +31,16 @@ #endif #include #include +#include #include #include "types.h" #include "desktop.h" #include "monitor.h" #include "settings.h" #include "messages.h" +#include "subscribe.h" #include "events.h" #include "common.h" -#include "tree.h" #include "window.h" #include "history.h" #include "stack.h" @@ -52,9 +51,7 @@ int main(int argc, char *argv[]) { fd_set descriptors; char socket_path[MAXLEN]; - char *fifo_path = NULL; config_path[0] = '\0'; - status_prefix = NULL; int sock_fd, ret_fd, dpy_fd, sel, n; struct sockaddr_un sock_address; size_t rsp_len = 0; @@ -63,10 +60,10 @@ int main(int argc, char *argv[]) xcb_generic_event_t *event; char opt; - while ((opt = getopt(argc, argv, "hvc:s:p:")) != -1) { + while ((opt = getopt(argc, argv, "hvc:")) != -1) { switch (opt) { case 'h': - printf(WM_NAME " [-h|-v|-c CONFIG_PATH|-s PANEL_FIFO|-p PANEL_PREFIX]\n"); + printf(WM_NAME " [-h|-v|-c CONFIG_PATH]\n"); exit(EXIT_SUCCESS); break; case 'v': @@ -76,12 +73,6 @@ int main(int argc, char *argv[]) case 'c': snprintf(config_path, sizeof(config_path), "%s", optarg); break; - case 's': - fifo_path = optarg; - break; - case 'p': - status_prefix = optarg; - break; } } @@ -122,14 +113,7 @@ int main(int argc, char *argv[]) sel = MAX(sock_fd, dpy_fd) + 1; - if (fifo_path != NULL) { - int fifo_fd = open(fifo_path, O_RDWR | O_NONBLOCK); - if (fifo_fd != -1) - status_fifo = fdopen(fifo_fd, "w"); - else - warn("Couldn't open status fifo.\n"); - } - + signal(SIGPIPE, SIG_IGN); load_settings(); run_config(); running = true; @@ -156,8 +140,12 @@ int main(int argc, char *argv[]) rsp[0] = MESSAGE_FAILURE; rsp_len = 1; } - send(ret_fd, rsp, rsp_len, 0); - close(ret_fd); + if (rsp_len == 1 && rsp[0] == MESSAGE_SUBSCRIBE) { + add_subscriber(ret_fd); + } else { + send(ret_fd, rsp, rsp_len, 0); + close(ret_fd); + } rsp[0] = '\0'; } } @@ -177,8 +165,6 @@ int main(int argc, char *argv[]) cleanup(); close(sock_fd); - if (status_fifo != NULL) - fclose(status_fifo); xcb_ewmh_connection_wipe(ewmh); xcb_destroy_window(dpy, motion_recorder); free(ewmh); @@ -194,7 +180,7 @@ void init(void) mon = mon_head = mon_tail = pri_mon = NULL; history_head = history_tail = history_needle = NULL; stack_head = stack_tail = NULL; - status_fifo = NULL; + subscribe_head = subscribe_tail = NULL; last_motion_time = last_motion_x = last_motion_y = 0; visible = auto_raise = sticky_still = record_history = true; randr_base = 0; @@ -296,30 +282,18 @@ void cleanup(void) remove_monitor(mon_head); while (stack_head != NULL) remove_stack(stack_head); + while (subscribe_head != NULL) + remove_subscriber(subscribe_head); empty_history(); free(frozen_pointer); } void put_status(void) { - if (status_fifo == NULL) - return; - if (status_prefix != NULL) - fprintf(status_fifo, "%s", status_prefix); - bool urgent = false; - for (monitor_t *m = mon_head; m != NULL; m = m->next) { - fprintf(status_fifo, "%c%s:", (mon == m ? 'M' : 'm'), m->name); - for (desktop_t *d = m->desk_head; d != NULL; d = d->next, urgent = false) { - for (node_t *n = first_extrema(d->root); n != NULL && !urgent; n = next_leaf(n, d->root)) - urgent |= n->client->urgent; - char c = (urgent ? 'u' : (d->root == NULL ? 'f' : 'o')); - if (m->desk == d) - c = toupper(c); - fprintf(status_fifo, "%c%s:", c, d->name); - } + subscriber_list_t *sb = subscribe_head; + while (sb != NULL) { + subscriber_list_t *next = sb->next; + feed_subscriber(sb); + sb = next; } - if (mon != NULL && mon->desk != NULL) - fprintf(status_fifo, "L%s", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle")); - fprintf(status_fifo, "\n"); - fflush(status_fifo); } diff --git a/bspwm.h b/bspwm.h index deae2ed..2e43c51 100644 --- a/bspwm.h +++ b/bspwm.h @@ -40,8 +40,6 @@ unsigned int desktop_uid; xcb_screen_t *screen; xcb_window_t root; uint8_t root_depth; -FILE *status_fifo; -char *status_prefix; char config_path[MAXLEN]; monitor_t *mon; @@ -53,6 +51,8 @@ history_t *history_tail; history_t *history_needle; stacking_list_t *stack_head; stacking_list_t *stack_tail; +subscriber_list_t *subscribe_head; +subscriber_list_t *subscribe_tail; pointer_state_t *frozen_pointer; xcb_window_t motion_recorder; diff --git a/contrib/bash_completion b/contrib/bash_completion index 2ffe109..17c3999 100644 --- a/contrib/bash_completion +++ b/contrib/bash_completion @@ -1,7 +1,7 @@ _bspc() { local commands='window desktop monitor query pointer restore control config quit' - local settings='rule_command focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color focused_sticky_border_color normal_sticky_border_color focused_private_border_color active_private_border_color normal_private_border_color urgent_border_color focused_frame_opacity active_frame_opacity normal_frame_opacity border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio growth_factor borderless_monocle gapless_monocle focus_follows_pointer pointer_follows_monitor apply_floating_atom auto_alternate auto_cancel history_aware_focus ignore_ewmh_focus' + local settings='rule_command status_prefix focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color focused_sticky_border_color normal_sticky_border_color focused_private_border_color active_private_border_color normal_private_border_color urgent_border_color focused_frame_opacity active_frame_opacity normal_frame_opacity border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio growth_factor borderless_monocle gapless_monocle focus_follows_pointer pointer_follows_monitor apply_floating_atom auto_alternate auto_cancel history_aware_focus ignore_ewmh_focus' COMPREPLY=() diff --git a/contrib/lightdm/bspwm-session b/contrib/lightdm/bspwm-session index b89359a..2df3501 100755 --- a/contrib/lightdm/bspwm-session +++ b/contrib/lightdm/bspwm-session @@ -34,9 +34,6 @@ if [ $? -ne 0 ]; then fi export BSPWM_SOCKET=${state_path}/bspwm-socket -export PANEL_FIFO=${state_path}/panel-fifo - -mkfifo "${PANEL_FIFO}" # Trap: make sure everything started in ~/.config/bspwm/autostart is # signalled when this script exits or dies. Also clean up $state_path. @@ -66,4 +63,4 @@ sxhkdrc_path=${XDG_CONFIG_HOME:-"$HOME/.config"}/bspwm/sxhkdrc [ -r "${sxhkdrc_path}" ] && sxhkd -c "${sxhkdrc_path}" & # Launch bspwm: -bspwm -s "${PANEL_FIFO}" -p W +bspwm diff --git a/contrib/zsh_completion b/contrib/zsh_completion index 0316176..3e0ae42 100644 --- a/contrib/zsh_completion +++ b/contrib/zsh_completion @@ -3,7 +3,7 @@ _bspc() { local -a commands settings commands=('window' 'desktop' 'monitor' 'query' 'pointer' 'restore' 'control' 'config' 'quit') - settings=('rule_command' 'focused_border_color' 'active_border_color' 'normal_border_color' 'presel_border_color' 'focused_locked_border_color' 'active_locked_border_color' 'normal_locked_border_color' 'focused_sticky_border_color' 'normal_sticky_border_color' 'focused_private_border_color' 'active_private_border_color' 'normal_private_border_color' 'urgent_border_color' 'focused_frame_opacity' 'active_frame_opacity' 'normal_frame_opacity' 'border_width' 'window_gap' 'top_padding' 'right_padding' 'bottom_padding' 'left_padding' 'split_ratio' 'growth_factor' 'borderless_monocle' 'gapless_monocle' 'focus_follows_pointer' 'pointer_follows_monitor' 'apply_floating_atom' 'auto_alternate' 'auto_cancel' 'history_aware_focus' 'ignore_ewmh_focus') + settings=('rule_command' 'status_prefix' 'focused_border_color' 'active_border_color' 'normal_border_color' 'presel_border_color' 'focused_locked_border_color' 'active_locked_border_color' 'normal_locked_border_color' 'focused_sticky_border_color' 'normal_sticky_border_color' 'focused_private_border_color' 'active_private_border_color' 'normal_private_border_color' 'urgent_border_color' 'focused_frame_opacity' 'active_frame_opacity' 'normal_frame_opacity' 'border_width' 'window_gap' 'top_padding' 'right_padding' 'bottom_padding' 'left_padding' 'split_ratio' 'growth_factor' 'borderless_monocle' 'gapless_monocle' 'focus_follows_pointer' 'pointer_follows_monitor' 'apply_floating_atom' 'auto_alternate' 'auto_cancel' 'history_aware_focus' 'ignore_ewmh_focus') if (( CURRENT == 2 )) ; then _values 'command' "$commands[@]" elif (( CURRENT == 3 )) ; then diff --git a/doc/bspwm.1 b/doc/bspwm.1 index 71b4d2b..5f6226c 100644 --- a/doc/bspwm.1 +++ b/doc/bspwm.1 @@ -2,12 +2,12 @@ .\" Title: bspwm .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.78.1 -.\" Date: 11/05/2013 +.\" Date: 11/07/2013 .\" Manual: Bspwm Manual .\" Source: Bspwm 0.8.6 .\" Language: English .\" -.TH "BSPWM" "1" "11/05/2013" "Bspwm 0\&.8\&.6" "Bspwm Manual" +.TH "BSPWM" "1" "11/07/2013" "Bspwm 0\&.8\&.6" "Bspwm Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -31,7 +31,7 @@ bspwm \- Binary space partitioning window manager .SH "SYNOPSIS" .sp -\fBbspwm\fR [\fB\-h\fR|\fB\-v\fR|\fB\-c\fR \fICONFIG_PATH\fR|\fB\-s\fR \fIPANEL_FIFO\fR|\fB\-p\fR \fIPANEL_PREFIX\fR] +\fBbspwm\fR [\fB\-h\fR|\fB\-v\fR|\fB\-c\fR \fICONFIG_PATH\fR] .sp \fBbspc\fR \fICOMMAND\fR [\fIARGUMENTS\fR] .SH "DESCRIPTION" @@ -55,18 +55,6 @@ Print the version and exit\&. .RS 4 Use the given configuration file\&. .RE -.PP -\fB\-s\fR \fIPANEL_FIFO\fR -.RS 4 -Write the internal state to the given FIFO\&. -.RE -.PP -\fB\-p\fR \fIPANEL_PREFIX\fR -.RS 4 -Start every line written to the -\fIPANEL_FIFO\fR -with the given prefix\&. -.RE .SH "CONFIGURATION" .sp \fBbspwm\fR has only two sources of informations: the X events it receives and the messages it reads on a dedicated socket\&. @@ -783,11 +771,6 @@ control \fIOPTIONS\fR Manage all the unmanaged windows remaining from a previous session\&. .RE .PP -\fB\-\-put\-status\fR -.RS 4 -Write the current internal state to the panel FIFO\&. -.RE -.PP \fB\-\-toggle\-visibility\fR .RS 4 Toggle the visibility of all the windows\&. @@ -797,6 +780,11 @@ Toggle the visibility of all the windows\&. .RS 4 Enable or disable the recording of window focus history\&. .RE +.PP +\fB\-\-subscribe\fR +.RS 4 +Continuously print status informations on standard output\&. +.RE .RE .SS "Pointer" .sp @@ -893,6 +881,11 @@ or \fImonitor\fR\&. .RE .PP +\fIstatus_prefix\fR +.RS 4 +Prefix prepended to each of the status lines\&. +.RE +.PP \fIfocused_border_color\fR .RS 4 Color of the border of a focused window of a focused monitor\&. @@ -1061,11 +1054,9 @@ Size of the gap that separates windows\&. .RS 4 Window border width\&. .RE -.SH "INTERNAL STATE FORMAT" -.sp -If a \fIPANEL_FIFO\fR is specified, \fBbspwm\fR will write informations regarding its current state to it\&. +.SH "STATUS FORMAT" .sp -Those informations are composed of items separated by colons\&. +Status informations are composed of items separated by colons\&. .sp Each item as the form \fI\fR where \fI\fR is the first character of the item\&. .PP diff --git a/doc/bspwm.1.txt b/doc/bspwm.1.txt index b630b9c..aa379b4 100644 --- a/doc/bspwm.1.txt +++ b/doc/bspwm.1.txt @@ -13,7 +13,7 @@ bspwm - Binary space partitioning window manager Synopsis -------- -*bspwm* [*-h*|*-v*|*-c* 'CONFIG_PATH'|*-s* 'PANEL_FIFO'|*-p* 'PANEL_PREFIX'] +*bspwm* [*-h*|*-v*|*-c* 'CONFIG_PATH'] *bspc* 'COMMAND' ['ARGUMENTS'] @@ -37,13 +37,6 @@ Options *-c* 'CONFIG_PATH':: Use the given configuration file. -*-s* 'PANEL_FIFO':: - Write the internal state to the given FIFO. - -*-p* 'PANEL_PREFIX':: - Start every line written to the 'PANEL_FIFO' with the given prefix. - - Configuration ------------- @@ -483,15 +476,15 @@ Options *--adopt-orphans*:: Manage all the unmanaged windows remaining from a previous session. -*--put-status*:: - Write the current internal state to the panel FIFO. - *--toggle-visibility*:: Toggle the visibility of all the windows. *--record-history* on|off:: Enable or disable the recording of window focus history. +*--subscribe*:: + Continuously print status informations on standard output. + Pointer ~~~~~~~ @@ -542,6 +535,9 @@ Global Settings 'rule_command':: External command used to retrieve rule consequences. It must contain at least one integer format directive which will be replaced by the ID of the window being processed. The output of that command must have the following format: *key1=value1 key2=value2 ...*, where *keyN* is one of 'floating', 'fullscreen', 'locked', 'sticky', 'private', 'frame', 'center', 'lower', 'follow', 'manage', 'focus', 'desktop' or 'monitor'. +'status_prefix':: + Prefix prepended to each of the status lines. + 'focused_border_color':: Color of the border of a focused window of a focused monitor. @@ -645,12 +641,10 @@ Desktop Settings Window border width. -Internal State Format ---------------------- - -If a 'PANEL_FIFO' is specified, *bspwm* will write informations regarding its current state to it. +Status Format +------------- -Those informations are composed of items separated by colons. +Status informations are composed of items separated by colons. Each item as the form '' where '' is the first character of the item. diff --git a/examples/panel/panel b/examples/panel/panel index 44de653..ce1ccb4 100755 --- a/examples/panel/panel +++ b/examples/panel/panel @@ -7,10 +7,16 @@ fi trap 'trap - TERM; kill 0' INT TERM QUIT EXIT +sleep 0.1 + flavor=${1:-bar} +[ -e "$PANEL_FIFO" ] && rm "$PANEL_FIFO" +mkfifo "$PANEL_FIFO" + bspc config top_padding $PANEL_HEIGHT -bspc control --put-status + +bspc control --subscribe > "$PANEL_FIFO" & xtitle -sf 'T%s' > "$PANEL_FIFO" & clock -sf 'S%a %H:%M' > "$PANEL_FIFO" & diff --git a/examples/panel/xinitrc b/examples/panel/xinitrc deleted file mode 100644 index 821d08d..0000000 --- a/examples/panel/xinitrc +++ /dev/null @@ -1,3 +0,0 @@ -[ -e "$PANEL_FIFO" ] && rm "$PANEL_FIFO" -mkfifo "$PANEL_FIFO" -exec bspwm -s "$PANEL_FIFO" -p W diff --git a/messages.c b/messages.c index 46e7415..9add04b 100644 --- a/messages.c +++ b/messages.c @@ -88,7 +88,7 @@ bool process_message(char **args, int num, char *rsp) } else if (streq("restore", *args)) { return cmd_restore(++args, --num); } else if (streq("control", *args)) { - return cmd_control(++args, --num); + return cmd_control(++args, --num, rsp); } else if (streq("pointer", *args)) { return cmd_pointer(++args, --num); } else if (streq("config", *args)) { @@ -690,7 +690,7 @@ bool cmd_restore(char **args, int num) return true; } -bool cmd_control(char **args, int num) +bool cmd_control(char **args, int num, char *rsp) { if (num < 1) return false; @@ -701,6 +701,8 @@ bool cmd_control(char **args, int num) put_status(); } else if (streq("--toggle-visibility", *args)) { toggle_visibility(); + } else if (streq("--subscribe", *args)) { + snprintf(rsp, BUFSIZ, "%c", MESSAGE_SUBSCRIBE); } else if (streq("--record-history", *args)) { num--, args++; if (num < 1) @@ -797,8 +799,12 @@ bool set_setting(coordinates_t loc, char *name, char *value) MONSET(bottom_padding) MONSET(left_padding) #undef MONSET - } else if (streq("rule_command", name)) { - return snprintf(rule_command, sizeof(rule_command), "%s", value) >= 0; +#define SETSTR(s) \ + } else if (streq(#s, name)) { \ + return snprintf(s, sizeof(s), "%s", value) >= 0; + SETSTR(rule_command) + SETSTR(status_prefix) +#undef SETSTR } else if (streq("split_ratio", name)) { double r; if (sscanf(value, "%lf", &r) == 1 && r > 0 && r < 1) @@ -907,6 +913,8 @@ bool get_setting(coordinates_t loc, char *name, char* rsp) snprintf(rsp, BUFSIZ, "%u", loc.desktop->border_width); else if (streq("rule_command", name)) snprintf(rsp, BUFSIZ, "%s", rule_command); + else if (streq("status_prefix", name)) + snprintf(rsp, BUFSIZ, "%s", status_prefix); #define MONGET(k) \ else if (streq(#k, name)) \ if (loc.monitor == NULL) \ diff --git a/messages.h b/messages.h index 099bae3..7da3ed5 100644 --- a/messages.h +++ b/messages.h @@ -31,6 +31,8 @@ #define CAT_CHR '.' #define EQL_TOK "=" +#define MESSAGE_SUBSCRIBE '\x01' + bool handle_message(char *msg, int msg_len, char *rsp); bool process_message(char **args, int num, char *rsp); bool cmd_window(char **args, int num); @@ -39,7 +41,7 @@ bool cmd_monitor(char **args, int num); bool cmd_query(char **args, int num, char *rsp); bool cmd_pointer(char **args, int num); bool cmd_restore(char **args, int num); -bool cmd_control(char **args, int num); +bool cmd_control(char **args, int num, char *rsp); bool cmd_config(char **args, int num, char *rsp); bool cmd_quit(char **args, int num); bool set_setting(coordinates_t loc, char *name, char *value); diff --git a/settings.c b/settings.c index 72bff63..4a8e8c4 100644 --- a/settings.c +++ b/settings.c @@ -47,6 +47,7 @@ void run_config(void) void load_settings(void) { snprintf(rule_command, sizeof(rule_command), "%s", RULE_COMMAND); + snprintf(status_prefix, sizeof(status_prefix), "%s", STATUS_PREFIX); snprintf(normal_border_color, sizeof(normal_border_color), "%s", NORMAL_BORDER_COLOR); snprintf(focused_border_color, sizeof(focused_border_color), "%s", FOCUSED_BORDER_COLOR); diff --git a/settings.h b/settings.h index 73a22ac..302a122 100644 --- a/settings.h +++ b/settings.h @@ -31,6 +31,7 @@ #define CONFIG_NAME WM_NAME "rc" #define CONFIG_HOME_ENV "XDG_CONFIG_HOME" #define RULE_COMMAND "true" +#define STATUS_PREFIX "W" #define FOCUSED_BORDER_COLOR "#7E7F89" #define ACTIVE_BORDER_COLOR "#545350" @@ -65,6 +66,7 @@ #define IGNORE_EWMH_FOCUS false char rule_command[MAXLEN]; +char status_prefix[MAXLEN]; char focused_border_color[MAXLEN]; char active_border_color[MAXLEN]; diff --git a/subscribe.c b/subscribe.c new file mode 100644 index 0000000..76c1544 --- /dev/null +++ b/subscribe.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include "bspwm.h" +#include "tree.h" +#include "settings.h" +#include "subscribe.h" + +subscriber_list_t *make_subscriber_list(int fd) +{ + subscriber_list_t *sb = malloc(sizeof(subscriber_list_t)); + sb->prev = sb->next = NULL; + sb->fd = fd; + sb->stream = fdopen(fd, "w"); + if (sb->stream == NULL) { + warn("Can't open subscriber %i\n", fd); + close(fd); + free(sb); + return NULL; + } + return sb; +} + +void remove_subscriber(subscriber_list_t *sb) +{ + if (sb == NULL) + return; + subscriber_list_t *a = sb->prev; + subscriber_list_t *b = sb->next; + if (a != NULL) + a->next = b; + if (b != NULL) + b->prev = a; + if (sb == subscribe_head) + subscribe_head = b; + if (sb == subscribe_tail) + subscribe_tail = a; + fclose(sb->stream); + free(sb); +} + +void add_subscriber(int fd) +{ + subscriber_list_t *sb = make_subscriber_list(fd); + if (sb == NULL) + return; + if (subscribe_head == NULL) { + subscribe_head = subscribe_tail = sb; + } else { + subscribe_tail->next = sb; + sb->prev = subscribe_tail; + subscribe_tail = sb; + } + feed_subscriber(sb); +} + +void feed_subscriber(subscriber_list_t *sb) +{ + fprintf(sb->stream, "%s", status_prefix); + bool urgent = false; + for (monitor_t *m = mon_head; m != NULL; m = m->next) { + fprintf(sb->stream, "%c%s:", (mon == m ? 'M' : 'm'), m->name); + for (desktop_t *d = m->desk_head; d != NULL; d = d->next, urgent = false) { + for (node_t *n = first_extrema(d->root); n != NULL && !urgent; n = next_leaf(n, d->root)) + urgent |= n->client->urgent; + char c = (urgent ? 'u' : (d->root == NULL ? 'f' : 'o')); + if (m->desk == d) + c = toupper(c); + fprintf(sb->stream, "%c%s:", c, d->name); + } + } + if (mon != NULL && mon->desk != NULL) + fprintf(sb->stream, "L%s", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle")); + int ret = fflush(sb->stream); + if (ret != 0) + remove_subscriber(sb); +} diff --git a/subscribe.h b/subscribe.h new file mode 100644 index 0000000..e5ce7de --- /dev/null +++ b/subscribe.h @@ -0,0 +1,9 @@ +#ifndef BSPWM_SUBSCRIBE_H +#define BSPWM_SUBSCRIBE_H + +subscriber_list_t *make_subscriber_list(int fd); +void remove_subscriber(subscriber_list_t *sb); +void add_subscriber(int fd); +void feed_subscriber(subscriber_list_t *sb); + +#endif diff --git a/types.h b/types.h index 67b78c7..408b338 100644 --- a/types.h +++ b/types.h @@ -239,6 +239,14 @@ struct stacking_list_t { stacking_list_t *next; }; +typedef struct subscriber_list_t subscriber_list_t; +struct subscriber_list_t { + int fd; + FILE *stream; + subscriber_list_t *prev; + subscriber_list_t *next; +}; + typedef struct { char desktop_desc[MAXLEN]; char monitor_desc[MAXLEN]; -- 2.44.0