diff options
author | Phil Jones <philj56@gmail.com> | 2022-07-27 15:00:05 +0100 |
---|---|---|
committer | Phil Jones <philj56@gmail.com> | 2022-07-27 15:12:26 +0100 |
commit | df3495a160878fd28e3642b47087024429bd512f (patch) | |
tree | 2f784c35706fec01fa34e410765deed61480b921 /src | |
parent | cf9669976601697be36e21e3359709f09c31d9da (diff) |
Fix window workspaces in drun mode.
Previously, tofi-drun would print the filename of the selected
.desktop file to stdout. This could then be passed to
`xargs swaymsg exec gio launch` to be executed.
The problem is that this ends up defeating the purpose of passing the
command to swaymsg exec, and the workspace the command was selected on
may not be the one that it starts up on, if for example it takes a long
time and the user switches workspaces in the meantime.
The solution is to instead print the Exec= line from the .desktop file,
and pass that directly to `xargs swaymsg exec --` for execution.
To avoid too much breaking of configs for the few people who use tofi
currently, this commit adds a new option, --drun-print-exec, to enable
the fixed behaviour. A future release will change this to be the
default, however.
Diffstat (limited to 'src')
-rw-r--r-- | src/config.c | 2 | ||||
-rw-r--r-- | src/drun.c | 64 | ||||
-rw-r--r-- | src/drun.h | 1 | ||||
-rw-r--r-- | src/main.c | 20 | ||||
-rw-r--r-- | src/tofi.h | 1 |
5 files changed, 85 insertions, 3 deletions
diff --git a/src/config.c b/src/config.c index a2e0f03..aebb8e1 100644 --- a/src/config.c +++ b/src/config.c @@ -293,6 +293,8 @@ bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const tofi->use_history = parse_bool(filename, lineno, value, &err); } else if (strcasecmp(option, "drun-launch") == 0) { tofi->drun_launch = parse_bool(filename, lineno, value, &err); + } else if (strcasecmp(option, "drun-print-exec") == 0) { + tofi->drun_print_exec = parse_bool(filename, lineno, value, &err); } else if (strcasecmp(option, "hint-font") == 0) { tofi->window.entry.harfbuzz.disable_hinting = !parse_bool(filename, lineno, value, &err); } else if (strcasecmp(option, "late-keyboard-init") == 0) { @@ -278,6 +278,70 @@ struct desktop_vec drun_generate_cached() return apps; } +void drun_print(const char *filename) +{ + GKeyFile *file = g_key_file_new(); + if (!g_key_file_load_from_file(file, filename, G_KEY_FILE_NONE, NULL)) { + log_error("Failed to open %s.\n", filename); + return; + } + const char *group = "Desktop Entry"; + + char *exec = g_key_file_get_string(file, group, "Exec", NULL); + if (exec == NULL) { + log_error("Failed to get Exec key from %s.\n", filename); + g_key_file_unref(file); + return; + } + + /* + * Build a string vector from the command line, replacing % field codes + * with the appropriate values. + */ + struct string_vec pieces = string_vec_create(); + char *search = exec; + char *last = search; + while ((search = strchr(search, '%')) != NULL) { + /* Add the string up to here to our vector. */ + search[0] = '\0'; + string_vec_add(&pieces, last); + search++; + last = search; + + switch (search[0]) { + case 'i': + if (g_key_file_has_key(file, group, "Icon", NULL)) { + string_vec_add(&pieces, "--icon "); + string_vec_add(&pieces, g_key_file_get_string(file, group, "Icon", NULL)); + } + break; + case 'c': + string_vec_add(&pieces, g_key_file_get_locale_string(file, group, "Name", NULL, NULL)); + break; + case 'k': + string_vec_add(&pieces, filename); + break; + } + } + if (last == exec) { + /* + * We didn't find any field codes, so just use the full exec + * string. + */ + fputs(exec, stdout); + } else { + /* Build the command line from our vector. */ + for (size_t i = 0; i < pieces.count; i++) { + fputs(pieces.buf[i].string, stdout); + } + } + fputc('\n', stdout); + + string_vec_destroy(&pieces); + free(exec); + g_key_file_unref(file); +} + void drun_launch(const char *filename) { GDesktopAppInfo *info = g_desktop_app_info_new_from_filename(filename); @@ -8,6 +8,7 @@ struct desktop_vec drun_generate(void); struct desktop_vec drun_generate_cached(void); void drun_history_sort(struct desktop_vec *apps, struct history *history); +void drun_print(const char *filename); void drun_launch(const char *filename); #endif /* DRUN_H */ @@ -707,6 +707,8 @@ static void usage() " --horizontal <true|false> List results horizontally.\n" " --history <true|false> Sort results by number of usages.\n" " --drun-launch <true|false> Launch apps directly in drun mode.\n" +" --drun-print-exec <true|false> Print a command line in drun mode.\n" +" This will become the default in future.\n" " --hint-font <true|false> Perform font hinting.\n" " --late-keyboard-init (EXPERIMENTAL) Delay keyboard\n" " initialisation until after the first\n" @@ -748,6 +750,7 @@ const struct option long_options[] = { {"hide-cursor", required_argument, NULL, 0}, {"history", required_argument, NULL, 0}, {"drun-launch", required_argument, NULL, 0}, + {"drun-print-exec", required_argument, NULL, 0}, {"hint-font", required_argument, NULL, 0}, {"output", required_argument, NULL, 'o'}, {"late-keyboard-init", no_argument, NULL, 'k'}, @@ -1257,12 +1260,23 @@ int main(int argc, char *argv[]) struct desktop_entry *app = desktop_vec_find(&tofi.window.entry.apps, res); if (app == NULL) { log_error("Couldn't find application file! This shouldn't happen.\n"); + break; } else { res = app->path; } - }; - if (tofi.window.entry.drun && tofi.drun_launch) { - drun_launch(res); + if (tofi.drun_launch) { + drun_launch(res); + } else if (tofi.drun_print_exec) { + drun_print(res); + } else { + log_warning("Using drun mode without --drun-print-exec=true is deprecated.\n" + " In the next version of tofi, this will become the default behaviour,\n" + " so fix your compositor configs now e.g. by replacing\n" + " tofi-drun | xargs swaymsg exec gio launch\n" + " with\n" + " tofi-drun --drun-print-exec=true | xargs swaymsg exec --\n"); + printf("%s\n", res); + } } else { printf("%s\n", res); } @@ -67,6 +67,7 @@ struct tofi { bool use_history; bool late_keyboard_init; bool drun_launch; + bool drun_print_exec; char target_output_name[MAX_OUTPUT_NAME_LEN]; }; |