Merge branch 'exec_nosn' into next

This commit is contained in:
Michael Stapelberg 2011-10-25 22:23:35 +01:00
commit 704c9967b2
9 changed files with 147 additions and 47 deletions

View File

@ -541,16 +541,21 @@ keyword. These commands will be run in order.
*Syntax*:
-------------------
exec command
exec_always command
exec [--no-startup-id] command
exec_always [--no-startup-id] command
-------------------
*Examples*:
--------------------------------
exec chromium
exec_always ~/my_script.sh
# Execute the terminal emulator urxvt, which is not yet startup-notification aware.
exec --no-startup-id urxvt
--------------------------------
The flag --no-startup-id is explained in <<exec>>.
[[workspace_screen]]
=== Automatically putting workspaces on specific screens
@ -1034,6 +1039,37 @@ The criteria +class+, +instance+, +role+, +title+ and +mark+ are actually
regular expressions (PCRE). See +pcresyntax(3)+ or +perldoc perlre+ for
information on how to use them.
[[exec]]
=== Executing applications (exec)
What good is a window manager if you cant actually start any applications?
The exec command starts an application by passing the command you specify to a
shell. This implies that you can use globbing (wildcards) and programs will be
searched in your $PATH.
*Syntax*:
------------------------------
exec [--no-startup-id] command
------------------------------
*Example*:
------------------------------
# Start the GIMP
bindsym mod+g exec gimp
# Start the terminal emulator urxvt which is not yet startup-notification-aware
bindsym mod+enter exec --no-startup-id urxvt
------------------------------
The +--no-startup-id+ parameter disables startup-notification support for this
particular exec command. With startup-notification, i3 can make sure that a
window appears on the workspace on which you used the exec command. Also, it
will change the X11 cursor to +watch+ (a clock) while the application is
launching. So, if an application is not startup-notification aware (most GTK
and Qt using applications seem to be, though), you will end up with a watch
cursor for 60 seconds.
=== Splitting containers
The split command makes the current window a split container. Split containers

View File

@ -218,6 +218,9 @@ struct Binding {
struct Autostart {
/** Command, like in command mode */
char *command;
/** no_startup_id flag for start_application(). Determines whether a
* startup notification context/ID should be created. */
bool no_startup_id;
TAILQ_ENTRY(Autostart) autostarts;
TAILQ_ENTRY(Autostart) autostarts_always;
};

View File

@ -25,8 +25,11 @@
* 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);
void start_application(const char *command, bool no_startup_id);
/**
* Called by libstartup-notification when something happens

View File

@ -1507,8 +1507,19 @@ restart_state:
exec:
TOKEXEC STR
{
char *command = $2;
bool no_startup_id = false;
if (strncasecmp($2, "--no-startup-id ", strlen("--no-startup-id ")) == 0) {
no_startup_id = true;
/* We need to make a copy here, otherwise we leak the
* --no-startup-id bytes in the beginning of the string */
command = sstrdup(command + strlen("--no-startup-id "));
free($2);
}
struct Autostart *new = smalloc(sizeof(struct Autostart));
new->command = $2;
new->command = command;
new->no_startup_id = no_startup_id;
TAILQ_INSERT_TAIL(&autostarts, new, autostarts);
}
;
@ -1516,8 +1527,19 @@ exec:
exec_always:
TOKEXEC_ALWAYS STR
{
char *command = $2;
bool no_startup_id = false;
if (strncasecmp($2, "--no-startup-id ", strlen("--no-startup-id ")) == 0) {
no_startup_id = true;
/* We need to make a copy here, otherwise we leak the
* --no-startup-id bytes in the beginning of the string */
command = sstrdup(command + strlen("--no-startup-id "));
free($2);
}
struct Autostart *new = smalloc(sizeof(struct Autostart));
new->command = $2;
new->command = command;
new->no_startup_id = no_startup_id;
TAILQ_INSERT_TAIL(&autostarts_always, new, autostarts_always);
}
;

View File

@ -389,8 +389,15 @@ operation:
exec:
TOK_EXEC STR
{
printf("should execute %s\n", $2);
start_application($2);
char *command = $2;
bool no_startup_id = false;
if (strncasecmp($2, "--no-startup-id ", strlen("--no-startup-id ")) == 0) {
no_startup_id = true;
command += strlen("--no-startup-id ");
}
printf("should execute %s, no_startup_id = %d\n", command, no_startup_id);
start_application(command, no_startup_id);
free($2);
}
;

View File

@ -635,7 +635,7 @@ int main(int argc, char *argv[]) {
struct Autostart *exec;
TAILQ_FOREACH(exec, &autostarts, autostarts) {
LOG("auto-starting %s\n", exec->command);
start_application(exec->command);
start_application(exec->command, exec->no_startup_id);
}
}
@ -643,7 +643,7 @@ int main(int argc, char *argv[]) {
struct Autostart *exec_always;
TAILQ_FOREACH(exec_always, &autostarts_always, autostarts_always) {
LOG("auto-starting (always!) %s\n", exec_always->command);
start_application(exec_always->command);
start_application(exec_always->command, exec_always->no_startup_id);
}
/* Start i3bar processes for all configured bars */
@ -653,7 +653,7 @@ int main(int argc, char *argv[]) {
sasprintf(&command, "i3bar --bar_id=%s --socket=\"%s\"",
barconfig->id, current_socketpath);
LOG("Starting bar process: %s\n", command);
start_application(command);
start_application(command, true);
free(command);
}

View File

@ -63,44 +63,50 @@ 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 dont 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);
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 dont 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);
LOG("startup id = %s\n", sn_launcher_context_get_startup_id(context));
/* 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);
/* 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);
LOG("startup id = %s\n", sn_launcher_context_get_startup_id(context));
/* 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);
/* 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) {
@ -108,7 +114,8 @@ void start_application(const char *command) {
setsid();
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;
@ -125,10 +132,12 @@ void start_application(const char *command) {
}
wait(0);
/* 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);
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);
}
}
/*

View File

@ -53,6 +53,7 @@ sub activate_i3 {
if ($pid == 0) {
$ENV{LISTEN_PID} = $$;
$ENV{LISTEN_FDS} = 1;
delete $ENV{DESKTOP_STARTUP_ID};
$ENV{DISPLAY} = $args{display};
$ENV{PATH} = join(':',
'../i3-nagbar',

View File

@ -84,6 +84,8 @@ close($fh);
unlink($tmp);
isnt($startup_id, '', 'startup_id not empty');
$ENV{DESKTOP_STARTUP_ID} = $startup_id;
# Create a new libstartup-notification launchee context
@ -132,4 +134,21 @@ sync_with_i3($x);
my $otherwin = open_window($x);
is(@{get_ws_content($second_ws)}, 1, 'one container on the second workspace');
######################################################################
# 3) test that the --no-startup-id flag for exec leads to no DESKTOP_STARTUP_ID
# environment variable.
######################################################################
mkfifo($tmp, 0600) or die "Could not create FIFO in $tmp";
cmd qq|exec --no-startup-id echo \$DESKTOP_STARTUP_ID >$tmp|;
open($fh, '<', $tmp);
chomp($startup_id = <$fh>);
close($fh);
unlink($tmp);
is($startup_id, '', 'startup_id empty');
done_testing;