From d49adfdef3a91c6ad6b7de07ac151ebe882326f4 Mon Sep 17 00:00:00 2001 From: o9000 Date: Sat, 2 Sep 2017 13:04:01 +0200 Subject: [PATCH] Launcher: Support %f and %F --- src/drag_and_drop.c | 61 +++++++++++++++++++++----------------- src/launcher/apps-common.c | 4 +++ src/launcher/launcher.c | 24 +++++++++++++-- src/main.c | 1 - src/util/common.c | 26 +++++++++++++--- src/util/common.h | 2 ++ 6 files changed, 82 insertions(+), 36 deletions(-) diff --git a/src/drag_and_drop.c b/src/drag_and_drop.c index e479276..534b64e 100644 --- a/src/drag_and_drop.c +++ b/src/drag_and_drop.c @@ -298,23 +298,6 @@ void handle_dnd_drop(XClientMessageEvent *e) } } -GString *tint2_g_string_replace(GString *s, const char *from, const char *to) -{ - GString *result = g_string_new(""); - for (char *p = s->str; *p;) { - if (strstr(p, from) == p) { - g_string_append(result, to); - p += strlen(from); - } else { - g_string_append_c(result, *p); - p += 1; - } - } - g_string_assign(s, result->str); - g_string_free(result, TRUE); - return s; -} - void handle_dnd_selection_notify(XSelectionEvent *e) { Atom target = e->target; @@ -326,11 +309,7 @@ void handle_dnd_selection_notify(XSelectionEvent *e) __FILE__, __LINE__, GetAtomName(server.display, e->selection)); - fprintf(stderr, - "tint2: DnD %s:%d: Target atom = %s\n", - __FILE__, - __LINE__, - GetAtomName(server.display, target)); + fprintf(stderr, "tint2: DnD %s:%d: Target atom = %s\n", __FILE__, __LINE__, GetAtomName(server.display, target)); fprintf(stderr, "DnD %s:%d: Property atom = %s\n", __FILE__, @@ -371,25 +350,49 @@ void handle_dnd_selection_notify(XSelectionEvent *e) fprintf(stderr, "tint2: --------\n"); } - // TODO: support %r nd %F // https://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables GString *cmd = g_string_new(dnd_launcher_icon->cmd); const char *atom_name = GetAtomName(server.display, prop.type); - if (strcasecmp(atom_name, "STRING") == 0 || - strcasecmp(atom_name, "text/uri-list") == 0) { + if (strcasecmp(atom_name, "STRING") == 0 || strcasecmp(atom_name, "text/uri-list") == 0) { GString *url = g_string_new(""); GString *prev_url = g_string_new(""); + gboolean must_unescape = strcasecmp(atom_name, "text/uri-list") == 0; for (int i = 0; i < prop.nitems * prop.format / 8; i++) { char c = ((char *)prop.data)[i]; if (c == '\n') { + if (must_unescape) { + char *raw = g_uri_unescape_string(url->str, NULL); + if (raw) { + g_string_assign(url, raw); + } + free(raw); + } // Many programs cannot handle this prefix tint2_g_string_replace(url, "file://", ""); // Some programs put duplicates in the list, we remove them if (strcmp(url->str, prev_url->str) != 0) { - g_string_append(cmd, " \""); - g_string_append(cmd, url->str); - g_string_append(cmd, "\""); + if (strstr(cmd->str, "%F")) { + GString *piece = g_string_new(""); + g_string_append(piece, " \""); + g_string_append(piece, url->str); + g_string_append(piece, "\""); + g_string_append(piece, " %F"); + tint2_g_string_replace(cmd, "%F", piece->str); + g_string_free(piece, TRUE); + } else if (strstr(cmd->str, "%f")) { + GString *piece = g_string_new(""); + g_string_append(piece, " \""); + g_string_append(piece, url->str); + g_string_append(piece, "\""); + tint2_g_string_replace(cmd, "%f", piece->str); + g_string_free(piece, TRUE); + break; + } else { + g_string_append(cmd, " \""); + g_string_append(cmd, url->str); + g_string_append(cmd, "\""); + } } g_string_assign(prev_url, url->str); g_string_assign(url, ""); @@ -405,6 +408,8 @@ void handle_dnd_selection_notify(XSelectionEvent *e) g_string_free(url, TRUE); g_string_free(prev_url, TRUE); } + tint2_g_string_replace(cmd, "%F", ""); + tint2_g_string_replace(cmd, "%f", ""); if (debug_dnd) fprintf(stderr, "tint2: DnD %s:%d: Running command: %s\n", __FILE__, __LINE__, cmd->str); tint_exec(cmd->str, diff --git a/src/launcher/apps-common.c b/src/launcher/apps-common.c index e8de09e..7acfc31 100644 --- a/src/launcher/apps-common.c +++ b/src/launcher/apps-common.c @@ -96,6 +96,10 @@ void expand_exec(DesktopEntry *entry, const char *path) q += strlen("''"); q += strlen(path); q--; // To balance the q++ in the for + } else if (*p == 'f' || *p == 'F') { + sprintf(q, "%c%c", '%', *p); + q += 2; + q--; // To balance the q++ in the for } else { // We don't care about other expansions q--; // Delete the last % from q diff --git a/src/launcher/launcher.c b/src/launcher/launcher.c index 994837f..8e9ae29 100644 --- a/src/launcher/launcher.c +++ b/src/launcher/launcher.c @@ -385,7 +385,12 @@ void draw_launcher_icon(void *obj, cairo_t *c) void launcher_icon_dump_geometry(void *obj, int indent) { LauncherIcon *launcherIcon = (LauncherIcon *)obj; - fprintf(stderr, "tint2: %*sIcon: w = h = %d, name = %s\n", indent, "", launcherIcon->icon_size, launcherIcon->icon_name); + fprintf(stderr, + "tint2: %*sIcon: w = h = %d, name = %s\n", + indent, + "", + launcherIcon->icon_size, + launcherIcon->icon_name); } Imlib_Image scale_icon(Imlib_Image original, int icon_size) @@ -434,8 +439,21 @@ void launcher_action(LauncherIcon *icon, XEvent *evt, int x, int y) launcher_reload_icon((Launcher *)icon->area.parent, icon); launcher_reload_hidden_icons((Launcher *)icon->area.parent); - if (evt->type == ButtonPress || evt->type == ButtonRelease) - tint_exec(icon->cmd, icon->cwd, icon->icon_tooltip, evt->xbutton.time, &icon->area, x, y, icon->start_in_terminal, icon->startup_notification); + if (evt->type == ButtonPress || evt->type == ButtonRelease) { + GString *cmd = g_string_new(icon->cmd); + tint2_g_string_replace(cmd, "%f", ""); + tint2_g_string_replace(cmd, "%F", ""); + tint_exec(cmd->str, + icon->cwd, + icon->icon_tooltip, + evt->xbutton.time, + &icon->area, + x, + y, + icon->start_in_terminal, + icon->startup_notification); + g_string_free(cmd, TRUE); + } } // Populates the list_icons list from the list_apps list diff --git a/src/main.c b/src/main.c index f24af2c..8af7602 100644 --- a/src/main.c +++ b/src/main.c @@ -536,7 +536,6 @@ void handle_x_event(XEvent *e) emit_self_restart("compositor changed"); } } - fprintf(stderr, "tint2: ClientMessage %s\n", GetAtomName(server.display, ev->message_type)); if (systray_enabled && e->xclient.message_type == server.atom._NET_SYSTEM_TRAY_OPCODE && e->xclient.format == 32 && e->xclient.window == net_sel_win) { handle_systray_event(&e->xclient); diff --git a/src/util/common.c b/src/util/common.c index c9fed70..671a42d 100644 --- a/src/util/common.c +++ b/src/util/common.c @@ -400,10 +400,11 @@ pid_t tint_exec(const char *command, fprintf(stderr, "tint2: executing in x-terminal-emulator: %s\n", command); wordexp_t words; words.we_offs = 2; - wordexp(command, &words, WRDE_DOOFFS | WRDE_SHOWERR); - words.we_wordv[0] = (char*)"x-terminal-emulator"; - words.we_wordv[1] = (char*)"-e"; - execvp("x-terminal-emulator", words.we_wordv); + if (wordexp(command, &words, WRDE_DOOFFS | WRDE_SHOWERR) == 0) { + words.we_wordv[0] = (char*)"x-terminal-emulator"; + words.we_wordv[1] = (char*)"-e"; + execvp("x-terminal-emulator", words.we_wordv); + } fprintf(stderr, "tint2: could not execute command in x-terminal-emulator: %s, executting in shell\n", command); } execlp("sh", "sh", "-c", command, NULL); @@ -1033,3 +1034,20 @@ void close_all_fds() close(fd); } } + +GString *tint2_g_string_replace(GString *s, const char *from, const char *to) +{ + GString *result = g_string_new(""); + for (char *p = s->str; *p;) { + if (strstr(p, from) == p) { + g_string_append(result, to); + p += strlen(from); + } else { + g_string_append_c(result, *p); + p += 1; + } + } + g_string_assign(s, result->str); + g_string_free(result, TRUE); + return s; +} diff --git a/src/util/common.h b/src/util/common.h index 1a88db2..8e47009 100644 --- a/src/util/common.h +++ b/src/util/common.h @@ -148,6 +148,8 @@ GSList *slist_remove_duplicates(GSList *list, GCompareFunc eq, GDestroyNotify fr // A trivial pointer comparator. gint cmp_ptr(gconstpointer a, gconstpointer b); +GString *tint2_g_string_replace(GString *s, const char *from, const char *to); + #define free_and_null(p) \ { \ free(p); \