X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fmain.c;h=7eb47c822fa83550b0d61df0f8d127a27cac1e8d;hb=e4d2b385529847b926a716731be4a8c22ed79007;hp=d87b9a29b0bcb75febe7e60b91b52bb220b50e97;hpb=c207921949440b0d7045bdf1f85c309a25bebdf0;p=i3%2Fi3 diff --git a/src/main.c b/src/main.c index d87b9a29..7eb47c82 100644 --- a/src/main.c +++ b/src/main.c @@ -32,15 +32,13 @@ * RLIM_INFINITY for i3 debugging versions. */ struct rlimit original_rlimit_core; -/** The number of file descriptors passed via socket activation. */ +/* The number of file descriptors passed via socket activation. */ int listen_fds; /* We keep the xcb_prepare watcher around to be able to enable and disable it * temporarily for drag_pointer(). */ static struct ev_prepare *xcb_prepare; -extern Con *focused; - char **start_argv; xcb_connection_t *conn; @@ -174,21 +172,64 @@ static void i3_exit(void) { fflush(stderr); shm_unlink(shmlogname); } + ipc_shutdown(SHUTDOWN_REASON_EXIT); + unlink(config.ipc_socket_path); } /* - * (One-shot) Handler for all signals with default action "Term", see signal(7) + * (One-shot) Handler for all signals with default action "Core", see signal(7) * * Unlinks the SHM log and re-raises the signal. * */ -static void handle_signal(int sig, siginfo_t *info, void *data) { +static void handle_core_signal(int sig, siginfo_t *info, void *data) { if (*shmlogname != '\0') { shm_unlink(shmlogname); } raise(sig); } +/* + * (One-shot) Handler for all signals with default action "Term", see signal(7) + * + * Exits the program gracefully. + * + */ +static void handle_term_signal(struct ev_loop *loop, ev_signal *signal, int revents) { + /* We exit gracefully here in the sense that cleanup handlers + * installed via atexit are invoked. */ + exit(128 + signal->signum); +} + +/* + * Set up handlers for all signals with default action "Term", see signal(7) + * + */ +static void setup_term_handlers(void) { + static struct ev_signal signal_watchers[6]; + size_t num_watchers = sizeof(signal_watchers) / sizeof(signal_watchers[0]); + + /* We have to rely on libev functionality here and should not use + * sigaction handlers because we need to invoke the exit handlers + * and cannot do so from an asynchronous signal handling context as + * not all code triggered during exit is signal safe (and exiting + * the main loop from said handler is not easily possible). libev's + * signal handlers does not impose such a constraint on us. */ + ev_signal_init(&signal_watchers[0], handle_term_signal, SIGHUP); + ev_signal_init(&signal_watchers[1], handle_term_signal, SIGINT); + ev_signal_init(&signal_watchers[2], handle_term_signal, SIGALRM); + ev_signal_init(&signal_watchers[3], handle_term_signal, SIGTERM); + ev_signal_init(&signal_watchers[4], handle_term_signal, SIGUSR1); + ev_signal_init(&signal_watchers[5], handle_term_signal, SIGUSR1); + for (size_t i = 0; i < num_watchers; i++) { + ev_signal_start(main_loop, &signal_watchers[i]); + /* The signal handlers should not block ev_run from returning + * and so none of the signal handlers should hold a reference to + * the main loop. */ + ev_unref(main_loop); + } +} + int main(int argc, char *argv[]) { /* Keep a symbol pointing to the I3_VERSION string constant so that we have * it in gdb backtraces. */ @@ -600,8 +641,16 @@ int main(int argc, char *argv[]) { /* Setting both, XCB_XKB_PER_CLIENT_FLAG_GRABS_USE_XKB_STATE and * XCB_XKB_PER_CLIENT_FLAG_LOOKUP_STATE_WHEN_GRABBED, will lead to the * X server sending us the full XKB state in KeyPress and KeyRelease: - * https://sources.debian.net/src/xorg-server/2:1.17.2-1.1/xkb/xkbEvents.c/?hl=927#L927 + * https://cgit.freedesktop.org/xorg/xserver/tree/xkb/xkbEvents.c?h=xorg-server-1.20.0#n927 + * + * XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT enable detectable autorepeat: + * https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Detectable_Autorepeat + * This affects bindings using the --release flag: instead of getting multiple KeyRelease + * events we get only one event when the key is physically released by the user. */ + const uint32_t mask = XCB_XKB_PER_CLIENT_FLAG_GRABS_USE_XKB_STATE | + XCB_XKB_PER_CLIENT_FLAG_LOOKUP_STATE_WHEN_GRABBED | + XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT; xcb_xkb_per_client_flags_reply_t *pcf_reply; /* The last three parameters are unset because they are only relevant * when using a feature called “automatic reset of boolean controls”: @@ -612,20 +661,24 @@ int main(int argc, char *argv[]) { xcb_xkb_per_client_flags( conn, XCB_XKB_ID_USE_CORE_KBD, - XCB_XKB_PER_CLIENT_FLAG_GRABS_USE_XKB_STATE | XCB_XKB_PER_CLIENT_FLAG_LOOKUP_STATE_WHEN_GRABBED, - XCB_XKB_PER_CLIENT_FLAG_GRABS_USE_XKB_STATE | XCB_XKB_PER_CLIENT_FLAG_LOOKUP_STATE_WHEN_GRABBED, + mask, + mask, 0 /* uint32_t ctrlsToChange */, 0 /* uint32_t autoCtrls */, 0 /* uint32_t autoCtrlsValues */), NULL); - if (pcf_reply == NULL || - !(pcf_reply->value & XCB_XKB_PER_CLIENT_FLAG_GRABS_USE_XKB_STATE)) { - ELOG("Could not set XCB_XKB_PER_CLIENT_FLAG_GRABS_USE_XKB_STATE\n"); - } - if (pcf_reply == NULL || - !(pcf_reply->value & XCB_XKB_PER_CLIENT_FLAG_LOOKUP_STATE_WHEN_GRABBED)) { - ELOG("Could not set XCB_XKB_PER_CLIENT_FLAG_LOOKUP_STATE_WHEN_GRABBED\n"); - } + +#define PCF_REPLY_ERROR(_value) \ + do { \ + if (pcf_reply == NULL || !(pcf_reply->value & (_value))) { \ + ELOG("Could not set " #_value "\n"); \ + } \ + } while (0) + + PCF_REPLY_ERROR(XCB_XKB_PER_CLIENT_FLAG_GRABS_USE_XKB_STATE); + PCF_REPLY_ERROR(XCB_XKB_PER_CLIENT_FLAG_LOOKUP_STATE_WHEN_GRABBED); + PCF_REPLY_ERROR(XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT); + free(pcf_reply); xkb_base = extreply->first_event; } @@ -723,7 +776,7 @@ int main(int argc, char *argv[]) { output = get_first_output(); } - con_focus(con_descend_focused(output_get_content(output->con))); + con_activate(con_descend_focused(output_get_content(output->con))); free(pointerreply); } @@ -853,15 +906,15 @@ int main(int argc, char *argv[]) { err(EXIT_FAILURE, "pledge"); #endif - struct sigaction action; - - action.sa_sigaction = handle_signal; - action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; - sigemptyset(&action.sa_mask); - if (!disable_signalhandler) setup_signal_handler(); else { + struct sigaction action; + + action.sa_sigaction = handle_core_signal; + action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; + sigemptyset(&action.sa_mask); + /* Catch all signals with default action "Core", see signal(7) */ if (sigaction(SIGQUIT, &action, NULL) == -1 || sigaction(SIGILL, &action, NULL) == -1 || @@ -871,14 +924,7 @@ int main(int argc, char *argv[]) { ELOG("Could not setup signal handler.\n"); } - /* Catch all signals with default action "Term", see signal(7) */ - if (sigaction(SIGHUP, &action, NULL) == -1 || - sigaction(SIGINT, &action, NULL) == -1 || - sigaction(SIGALRM, &action, NULL) == -1 || - sigaction(SIGUSR1, &action, NULL) == -1 || - sigaction(SIGUSR2, &action, NULL) == -1) - ELOG("Could not setup signal handler.\n"); - + setup_term_handlers(); /* Ignore SIGPIPE to survive errors when an IPC client disconnects * while we are sending them a message */ signal(SIGPIPE, SIG_IGN); @@ -913,15 +959,16 @@ int main(int argc, char *argv[]) { Barconfig *barconfig; TAILQ_FOREACH(barconfig, &barconfigs, configs) { char *command = NULL; - sasprintf(&command, "%s --bar_id=%s --socket=\"%s\"", + sasprintf(&command, "%s %s --bar_id=%s --socket=\"%s\"", barconfig->i3bar_command ? barconfig->i3bar_command : "i3bar", + barconfig->verbose ? "-V" : "", barconfig->id, current_socketpath); LOG("Starting bar process: %s\n", command); start_application(command, true); free(command); } - /* Make sure to destroy the event loop to invoke the cleeanup callbacks + /* Make sure to destroy the event loop to invoke the cleanup callbacks * when calling exit() */ atexit(i3_exit);