X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fstartup.c;h=b0aa2ca3625bd4bc603172cbb3736c115da3b0a1;hb=8d2799c251cc1c44f1429c36817c346fa56b9701;hp=4b6c937dab6ad3e62ddb969bf20103a2c878236e;hpb=2ad4fbb34ae9110477be484f24c162bc5687253b;p=i3%2Fi3 diff --git a/src/startup.c b/src/startup.c index 4b6c937d..b0aa2ca3 100644 --- a/src/startup.c +++ b/src/startup.c @@ -1,23 +1,26 @@ +#undef I3__FILE__ +#define I3__FILE__ "startup.c" /* * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager + * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) * - * © 2009-2011 Michael Stapelberg and contributors - * - * See file LICENSE for license information. - * - * startup.c: Startup notification code + * startup.c: Startup notification code. Ensures a startup notification context + * is setup when launching applications. We store the current + * workspace to open windows in that startup notification context on + * the appropriate workspace. * */ +#include "all.h" +#include "sd-daemon.h" + #include #include #define SN_API_NOT_YET_FROZEN 1 #include -#include "all.h" - static TAILQ_HEAD(startup_sequence_head, Startup_Sequence) startup_sequences = TAILQ_HEAD_INITIALIZER(startup_sequences); @@ -63,52 +66,69 @@ static void startup_timeout(EV_P_ ev_timer *w, int revents) { * The shell is determined by looking for the SHELL environment variable. If it * does not exist, /bin/sh is used. * + * The no_startup_id flag determines whether a startup notification context + * (and ID) should be created, which is the default and encouraged behavior. + * */ -void start_application(const char *command) { - /* Create a startup notification context to monitor the progress of this - * startup. */ +void start_application(const char *command, bool no_startup_id) { SnLauncherContext *context; - context = sn_launcher_context_new(sndisplay, conn_screen); - sn_launcher_context_set_name(context, "i3"); - sn_launcher_context_set_description(context, "exec command in i3"); - /* Chop off everything starting from the first space (if there are any - * spaces in the command), since we don’t want the parameters. */ - char *first_word = sstrdup(command); - char *space = strchr(first_word, ' '); - if (space) - *space = '\0'; - sn_launcher_context_initiate(context, "i3", first_word, last_timestamp); - free(first_word); - - /* Trigger a timeout after 60 seconds */ - struct ev_timer *timeout = scalloc(sizeof(struct ev_timer)); - ev_timer_init(timeout, startup_timeout, 60.0, 0.); - timeout->data = context; - ev_timer_start(main_loop, timeout); - - LOG("startup id = %s\n", sn_launcher_context_get_startup_id(context)); - - /* Save the ID and current workspace in our internal list of startup - * sequences */ - Con *ws = con_get_workspace(focused); - struct Startup_Sequence *sequence = scalloc(sizeof(struct Startup_Sequence)); - sequence->id = sstrdup(sn_launcher_context_get_startup_id(context)); - sequence->workspace = sstrdup(ws->name); - sequence->context = context; - TAILQ_INSERT_TAIL(&startup_sequences, sequence, sequences); - - /* Increase the refcount once (it starts with 1, so it will be 2 now) for - * the timeout. Even if the sequence gets completed, the timeout still - * needs the context (but will unref it then) */ - sn_launcher_context_ref(context); + + if (!no_startup_id) { + /* Create a startup notification context to monitor the progress of this + * startup. */ + context = sn_launcher_context_new(sndisplay, conn_screen); + sn_launcher_context_set_name(context, "i3"); + sn_launcher_context_set_description(context, "exec command in i3"); + /* Chop off everything starting from the first space (if there are any + * spaces in the command), since we don’t want the parameters. */ + char *first_word = sstrdup(command); + char *space = strchr(first_word, ' '); + if (space) + *space = '\0'; + sn_launcher_context_initiate(context, "i3", first_word, last_timestamp); + free(first_word); + + /* Trigger a timeout after 60 seconds */ + struct ev_timer *timeout = scalloc(sizeof(struct ev_timer)); + ev_timer_init(timeout, startup_timeout, 60.0, 0.); + timeout->data = context; + ev_timer_start(main_loop, timeout); + + LOG("startup id = %s\n", sn_launcher_context_get_startup_id(context)); + + /* Save the ID and current workspace in our internal list of startup + * sequences */ + Con *ws = con_get_workspace(focused); + struct Startup_Sequence *sequence = scalloc(sizeof(struct Startup_Sequence)); + sequence->id = sstrdup(sn_launcher_context_get_startup_id(context)); + sequence->workspace = sstrdup(ws->name); + sequence->context = context; + TAILQ_INSERT_TAIL(&startup_sequences, sequence, sequences); + + /* Increase the refcount once (it starts with 1, so it will be 2 now) for + * the timeout. Even if the sequence gets completed, the timeout still + * needs the context (but will unref it then) */ + sn_launcher_context_ref(context); + } LOG("executing: %s\n", command); if (fork() == 0) { /* Child process */ setsid(); + setrlimit(RLIMIT_CORE, &original_rlimit_core); + /* Close all socket activation file descriptors explicitly, we disabled + * FD_CLOEXEC to keep them open when restarting i3. */ + for (int fd = SD_LISTEN_FDS_START; + fd < (SD_LISTEN_FDS_START + listen_fds); + fd++) { + close(fd); + } + unsetenv("LISTEN_PID"); + unsetenv("LISTEN_FDS"); if (fork() == 0) { /* Setup the environment variable(s) */ - sn_launcher_context_setup_child_process(context); + if (!no_startup_id) + sn_launcher_context_setup_child_process(context); /* Stores the path of the shell */ static const char *shell = NULL; @@ -121,9 +141,16 @@ void start_application(const char *command) { execl(shell, shell, "-c", command, (void*)NULL); /* not reached */ } - exit(0); + _exit(0); } wait(0); + + if (!no_startup_id) { + /* Change the pointer of the root window to indicate progress */ + if (xcursor_supported) + xcursor_set_root_cursor(XCURSOR_CURSOR_WATCH); + else xcb_set_root_cursor(XCURSOR_CURSOR_WATCH); + } } /* @@ -160,6 +187,14 @@ void startup_monitor_event(SnMonitorEvent *event, void *userdata) { /* Delete our internal sequence */ TAILQ_REMOVE(&startup_sequences, sequence, sequences); + + if (TAILQ_EMPTY(&startup_sequences)) { + DLOG("No more startup sequences running, changing root window cursor to default pointer.\n"); + /* Change the pointer of the root window to indicate progress */ + if (xcursor_supported) + xcursor_set_root_cursor(XCURSOR_CURSOR_POINTER); + else xcb_set_root_cursor(XCURSOR_CURSOR_POINTER); + } break; default: /* ignore */