Closes #904.
'*'{-O,--reorder-monitors}'[Reorder the list of monitors to match the given order]:*: :_bspc_query_names -- monitors -M'\
'*'{-o,--adopt-orphans}'[Manage all the unmanaged windows remaining from a previous session]'\
'*'{-h,--record-history}'[Enable or disable the recording of node focus history]:history:(on off)'\
- '*'{-g,--get-status}'[Print the current status information]'
+ '*'{-g,--get-status}'[Print the current status information]'\
+ '*'{-r,--restart}'[Restart the window manager]'
;;
(subscribe)
if [[ "$words[CURRENT-1]" != (-c|--count) ]] ;then
.\" Title: bspwm
.\" Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\" Date: 01/29/2019
+.\" Date: 01/30/2019
.\" Manual: Bspwm Manual
-.\" Source: Bspwm 0.9.5-35-g32ff624
+.\" Source: Bspwm 0.9.5-44-gd36664b
.\" Language: English
.\"
-.TH "BSPWM" "1" "01/29/2019" "Bspwm 0\&.9\&.5\-35\-g32ff624" "Bspwm Manual"
+.TH "BSPWM" "1" "01/30/2019" "Bspwm 0\&.9\&.5\-44\-gd36664b" "Bspwm Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.RS 4
Print the current status information\&.
.RE
+.PP
+\fB\-r\fR, \fB\-\-restart\fR
+.RS 4
+Restart the window manager
+.RE
.RE
.SS "Rule"
.sp
*-g*, *--get-status*::
Print the current status information.
+*-r*, *--restart*::
+ Restart the window manager
+
Rule
~~~~
+++ /dev/null
-#! /bin/sh
-
-if [ -e "$BSPWM_STATE" ] ; then
- bspc wm -l "$BSPWM_STATE"
- rm "$BSPWM_STATE"
-fi
+++ /dev/null
-export BSPWM_STATE=/tmp/bspwm-state.json
+++ /dev/null
-# refresh or quit bspwm
-super + alt + {_,shift + }Escape
- {bspc wm -d > "$BSPWM_STATE" && bspc quit, \
- bspc quit 1}
+++ /dev/null
-#! /bin/sh
-
-while true ; do
- bspwm || break
-done
# bspwm hotkeys
#
-# quit bspwm normally
-super + alt + Escape
- bspc quit
+# quit/restart bspwm
+super + alt + {q,r}
+ bspc {quit,wm -r}
# close and kill
super + {_,shift + }w
#include <signal.h>
#include <unistd.h>
#include <stdbool.h>
+#include <string.h>
#include <xcb/xinerama.h>
#include "types.h"
#include "desktop.h"
#include "history.h"
#include "ewmh.h"
#include "rule.h"
+#include "restore.h"
+#include "query.h"
#include "bspwm.h"
int main(int argc, char *argv[])
{
fd_set descriptors;
char socket_path[MAXLEN];
+ char state_path[MAXLEN] = {0};
config_path[0] = '\0';
- int sock_fd, cli_fd, dpy_fd, max_fd, n;
+ int sock_fd = -1, cli_fd, dpy_fd, max_fd, n;
struct sockaddr_un sock_address;
char msg[BUFSIZ] = {0};
xcb_generic_event_t *event;
+ char *end;
int opt;
- while ((opt = getopt(argc, argv, "hvc:")) != -1) {
+ while ((opt = getopt(argc, argv, "hvc:s:o:")) != -1) {
switch (opt) {
case 'h':
printf(WM_NAME " [-h|-v|-c CONFIG_PATH]\n");
case 'c':
snprintf(config_path, sizeof(config_path), "%s", optarg);
break;
+ case 's':
+ snprintf(state_path, sizeof(state_path), "%s", optarg);
+ break;
+ case 'o':
+ sock_fd = strtol(optarg, &end, 0);
+ if (*end != '\0') {
+ sock_fd = -1;
+ }
+ break;
}
}
load_settings();
setup();
+ if (state_path[0] != '\0') {
+ restore_state(state_path);
+ unlink(state_path);
+ }
+
dpy_fd = xcb_get_file_descriptor(dpy);
- char *sp = getenv(SOCKET_ENV_VAR);
- if (sp != NULL) {
- snprintf(socket_path, sizeof(socket_path), "%s", sp);
- } else {
- char *host = NULL;
- int dn = 0, sn = 0;
- if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
- snprintf(socket_path, sizeof(socket_path), SOCKET_PATH_TPL, host, dn, sn);
+ if (sock_fd == -1) {
+ char *sp = getenv(SOCKET_ENV_VAR);
+ if (sp != NULL) {
+ snprintf(socket_path, sizeof(socket_path), "%s", sp);
+ } else {
+ char *host = NULL;
+ int dn = 0, sn = 0;
+ if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
+ snprintf(socket_path, sizeof(socket_path), SOCKET_PATH_TPL, host, dn, sn);
+ }
+ free(host);
}
- free(host);
- }
- sock_address.sun_family = AF_UNIX;
- snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", socket_path);
+ sock_address.sun_family = AF_UNIX;
+ snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", socket_path);
- sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock_fd == -1) {
- err("Couldn't create the socket.\n");
- }
+ if (sock_fd == -1) {
+ err("Couldn't create the socket.\n");
+ }
- unlink(socket_path);
- if (bind(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) {
- err("Couldn't bind a name to the socket.\n");
- }
+ unlink(socket_path);
+
+ if (bind(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) {
+ err("Couldn't bind a name to the socket.\n");
+ }
- if (listen(sock_fd, SOMAXCONN) == -1) {
- err("Couldn't listen to the socket.\n");
+ if (listen(sock_fd, SOMAXCONN) == -1) {
+ err("Couldn't listen to the socket.\n");
+ }
}
signal(SIGINT, sig_handler);
}
}
+ if (restart) {
+ char *host = NULL;
+ int dn = 0, sn = 0;
+ if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
+ snprintf(state_path, sizeof(state_path), STATE_PATH_TPL, host, dn, sn);
+ }
+ free(host);
+ FILE *f = fopen(state_path, "w");
+ query_state(f);
+ fclose(f);
+ }
+
cleanup();
- close(sock_fd);
- unlink(socket_path);
ungrab_buttons();
xcb_ewmh_connection_wipe(ewmh);
xcb_destroy_window(dpy, meta_window);
free(ewmh);
xcb_flush(dpy);
xcb_disconnect(dpy);
+
+ if (restart) {
+ int rargc;
+ for (rargc = 0; rargc < argc; rargc++) {
+ if (streq("-s", argv[rargc])) {
+ break;
+ }
+ }
+
+ int len = (argc + 1 + (rargc < argc ? 4 : 0));
+ char **rargv = malloc(len * sizeof(char *));
+
+ for (int i = 0; i < rargc; i++) {
+ rargv[i] = argv[i];
+ }
+
+ char sock_fd_arg[SMALEN];
+ snprintf(sock_fd_arg, sizeof(sock_fd_arg), "%i", sock_fd);
+
+ rargv[rargc] = "-s";
+ rargv[rargc + 1] = state_path;
+ rargv[rargc + 2] = "-o";
+ rargv[rargc + 3] = sock_fd_arg;
+ rargv[rargc + 4] = 0;
+
+ exit_status = execvp(*rargv, rargv);
+ free(rargv);
+ }
+
+ close(sock_fd);
+ unlink(socket_path);
+
return exit_status;
}
auto_raise = sticky_still = hide_sticky = record_history = true;
randr_base = 0;
exit_status = 0;
+ restart = false;
}
void setup(void)
#define CONFIG_HOME_ENV "XDG_CONFIG_HOME"
#define RUNTIME_DIR_ENV "XDG_RUNTIME_DIR"
+#define STATE_PATH_TPL "/tmp/bspwm%s_%i_%i-state"
+
#define ROOT_EVENT_MASK (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_BUTTON_PRESS)
#define CLIENT_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE)
#define BSPWM_CLASS_NAME "Bspwm"
bool hide_sticky;
bool record_history;
bool running;
+bool restart;
bool randr;
void init(void);
while (num > 0) {
if (streq("-d", *args) || streq("--dump-state", *args)) {
- query_tree(rsp);
+ query_state(rsp);
fprintf(rsp, "\n");
} else if (streq("-l", *args) || streq("--load-state", *args)) {
num--, args++;
fail(rsp, "wm %s: Not enough arguments.\n", *(args - 1));
break;
}
- if (!restore_tree(*args)) {
+ if (!restore_state(*args)) {
fail(rsp, "");
break;
}
fail(rsp, "wm %s: Invalid argument: '%s'.\n", *(args - 1), *args);
break;
}
+ } else if (streq("-r", *args) || streq("--restart", *args)) {
+ running = false;
+ restart = true;
+ break;
} else {
fail(rsp, "wm: Unknown command: '%s'.\n", *args);
break;
}
}
- add_subscriber(stream, fifo_path, field, count);
+ subscriber_list_t *sb = make_subscriber(stream, fifo_path, field, count);
+ add_subscriber(sb);
return;
failed:
#include "query.h"
#include "geometry.h"
-void query_tree(FILE *rsp)
+void query_state(FILE *rsp)
{
fprintf(rsp, "{");
fprintf(rsp, "\"focusedMonitorId\":%u,", mon->id);
fprintf(rsp,",");
fprintf(rsp, "\"stackingList\":");
query_stack(rsp);
+ if (restart) {
+ fprintf(rsp,",");
+ fprintf(rsp, "\"eventSubscribers\":");
+ query_subscribers(rsp);
+ }
fprintf(rsp, "}");
-
}
void query_monitor(monitor_t *m, FILE *rsp)
fprintf(rsp, "]");
}
+void query_subscribers(FILE *rsp)
+{
+ fprintf(rsp, "[");
+ for (subscriber_list_t *s = subscribe_head; s != NULL; s = s->next) {
+ fprintf(rsp, "{\"fileDescriptor\": %i", fileno(s->stream));
+ if (s->fifo_path != NULL) {
+ fprintf(rsp, ",\"fifoPath\":\"%s\"", s->fifo_path);
+ }
+ fprintf(rsp, ",\"field\":%i,\"count\":%i}", s->field, s->count);
+ if (s->next != NULL) {
+ fprintf(rsp, ",");
+ }
+ }
+ fprintf(rsp, "]");
+}
+
int query_node_ids(coordinates_t *ref, coordinates_t *trg, node_select_t *sel, FILE *rsp)
{
int count = 0;
typedef void (*monitor_printer_t)(monitor_t *m, FILE *rsp);
typedef void (*desktop_printer_t)(desktop_t *m, FILE *rsp);
-void query_tree(FILE *rsp);
+void query_state(FILE *rsp);
void query_monitor(monitor_t *m, FILE *rsp);
void query_desktop(desktop_t *d, FILE *rsp);
void query_node(node_t *n, FILE *rsp);
void query_history(FILE *rsp);
void query_coordinates(coordinates_t *loc, FILE *rsp);
void query_stack(FILE *rsp);
+void query_subscribers(FILE *rsp);
int query_node_ids(coordinates_t *ref, coordinates_t *trg, node_select_t *sel, FILE *rsp);
int query_node_ids_in(node_t *n, desktop_t *d, monitor_t *m, coordinates_t *ref, coordinates_t *trg, node_select_t *sel, FILE *rsp);
int query_desktop_ids(coordinates_t *ref, coordinates_t *trg, desktop_select_t *sel, desktop_printer_t printer, FILE *rsp);
#include "stack.h"
#include "tree.h"
#include "settings.h"
+#include "subscribe.h"
#include "restore.h"
#include "window.h"
#include "parse.h"
-bool restore_tree(const char *file_path)
+bool restore_state(const char *file_path)
{
size_t jslen;
char *json = read_string(file_path, &jslen);
}
restore_stack(&t, json);
continue;
+ } else if (keyeq("eventSubscribers", t, json)) {
+ t++;
+ restore_subscribers(&t, json);
+ continue;
}
t++;
}
}
}
+void restore_subscribers(jsmntok_t **t, char *json)
+{
+ int s = (*t)->size;
+ (*t)++;
+
+ for (int i = 0; i < s; i++) {
+ subscriber_list_t *s = make_subscriber(NULL, NULL, 0, 0);
+ restore_subscriber(s, t, json);
+ add_subscriber(s);
+ }
+}
+
+void restore_subscriber(subscriber_list_t *s, jsmntok_t **t, char *json)
+{
+ int n = (*t)->size;
+ (*t)++;
+
+ for (int i = 0; i < n; i++) {
+ if (keyeq("fileDescriptor", *t, json)) {
+ (*t)++;
+ int fd;
+ sscanf(json + (*t)->start, "%i", &fd);
+ s->stream = fdopen(fd, "w");
+ } else if (keyeq("fifoPath", *t, json)) {
+ (*t)++;
+ free(s->fifo_path);
+ s->fifo_path = copy_string(json + (*t)->start, (*t)->end - (*t)->start);
+ RESTORE_INT(field, &s->field)
+ RESTORE_INT(count, &s->count)
+ }
+ (*t)++;
+ }
+}
+
void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
{
int s = (*t)->size;
#include "jsmn.h"
-bool restore_tree(const char *file_path);
+bool restore_state(const char *file_path);
monitor_t *restore_monitor(jsmntok_t **t, char *json);
desktop_t *restore_desktop(jsmntok_t **t, char *json);
node_t *restore_node(jsmntok_t **t, char *json);
void restore_constraints(constraints_t *c, jsmntok_t **t, char *json);
void restore_padding(padding_t *p, jsmntok_t **t, char *json);
void restore_history(jsmntok_t **t, char *json);
+void restore_subscribers(jsmntok_t **t, char *json);
+void restore_subscriber(subscriber_list_t *s, jsmntok_t **t, char *json);
void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json);
void restore_stack(jsmntok_t **t, char *json);
bool keyeq(char *s, jsmntok_t *key, char *json);
#include "subscribe.h"
#include "tree.h"
-subscriber_list_t *make_subscriber_list(FILE *stream, char *fifo_path, int field, int count)
+subscriber_list_t *make_subscriber(FILE *stream, char *fifo_path, int field, int count)
{
subscriber_list_t *sb = calloc(1, sizeof(subscriber_list_t));
sb->prev = sb->next = NULL;
if (sb == subscribe_tail) {
subscribe_tail = a;
}
- fclose(sb->stream);
- unlink(sb->fifo_path);
+ if (!restart) {
+ fclose(sb->stream);
+ unlink(sb->fifo_path);
+ }
free(sb->fifo_path);
free(sb);
}
-void add_subscriber(FILE *stream, char* fifo_path, int field, int count)
+void add_subscriber(subscriber_list_t *sb)
{
- subscriber_list_t *sb = make_subscriber_list(stream, fifo_path, field, count);
if (subscribe_head == NULL) {
subscribe_head = subscribe_tail = sb;
} else {
SBSC_MASK_ALL = (1 << 28) - 1
} subscriber_mask_t;
-subscriber_list_t *make_subscriber_list(FILE *stream, char *fifo_path, int field, int count);
+subscriber_list_t *make_subscriber(FILE *stream, char *fifo_path, int field, int count);
void remove_subscriber(subscriber_list_t *sb);
-void add_subscriber(FILE *stream, char* fifo_path, int field, int count);
+void add_subscriber(subscriber_list_t *sb);
int print_report(FILE *stream);
void put_status(subscriber_mask_t mask, ...);