From 14c3824632f6e654e60a8510a9aa3a0cec9c6c72 Mon Sep 17 00:00:00 2001 From: o9000 Date: Sat, 2 Sep 2017 10:53:20 +0200 Subject: [PATCH] Launcher: Add support for Terminal=true --- src/battery/battery.c | 2 +- src/button/button.c | 2 +- src/clock/clock.c | 2 +- src/drag_and_drop.c | 62 +++++++++++++++++++++++++++---------- src/execplugin/execplugin.c | 2 +- src/launcher/apps-common.c | 6 ++++ src/launcher/apps-common.h | 2 ++ src/launcher/launcher.c | 4 ++- src/launcher/launcher.h | 2 ++ src/main.c | 1 + src/util/common.c | 40 +++++++++++++++++++----- src/util/common.h | 10 +++++- 12 files changed, 105 insertions(+), 30 deletions(-) diff --git a/src/battery/battery.c b/src/battery/battery.c index 433bff4..c8dc907 100644 --- a/src/battery/battery.c +++ b/src/battery/battery.c @@ -464,5 +464,5 @@ void battery_action(void *obj, int button, int x, int y, Time time) command = battery_dwheel_command; break; } - tint_exec(command, NULL, NULL, time, obj, x, y); + tint_exec(command, NULL, NULL, time, obj, x, y, FALSE, TRUE); } diff --git a/src/button/button.c b/src/button/button.c index 7a36dda..3b8a58a 100644 --- a/src/button/button.c +++ b/src/button/button.c @@ -530,7 +530,7 @@ void button_action(void *obj, int mouse_button, int x, int y, Time time) command = button->backend->dwheel_command; break; } - tint_exec(command, NULL, NULL, time, obj, x, y); + tint_exec(command, NULL, NULL, time, obj, x, y, FALSE, TRUE); } char *button_get_tooltip(void *obj) diff --git a/src/clock/clock.c b/src/clock/clock.c index d26520f..2b10484 100644 --- a/src/clock/clock.c +++ b/src/clock/clock.c @@ -353,5 +353,5 @@ void clock_action(void *obj, int button, int x, int y, Time time) command = clock_dwheel_command; break; } - tint_exec(command, NULL, NULL, time, obj, x, y); + tint_exec(command, NULL, NULL, time, obj, x, y, FALSE, TRUE); } diff --git a/src/drag_and_drop.c b/src/drag_and_drop.c index 01277b3..d2d7294 100644 --- a/src/drag_and_drop.c +++ b/src/drag_and_drop.c @@ -30,7 +30,7 @@ static int dnd_version; static Atom dnd_selection; static Atom dnd_atom; static int dnd_sent_request; -static char *dnd_launcher_exec; +static LauncherIcon *dnd_launcher_icon; static gboolean dnd_debug = FALSE; gboolean hidden_panel_shown_for_dnd; @@ -43,7 +43,7 @@ void dnd_init() dnd_selection = XInternAtom(server.display, "PRIMARY", 0); dnd_atom = None; dnd_sent_request = 0; - dnd_launcher_exec = 0; + dnd_launcher_icon = NULL; hidden_panel_shown_for_dnd = FALSE; } @@ -62,9 +62,21 @@ void handle_dnd_enter(XClientMessageEvent *e) __LINE__, more_than_3 ? "yes" : "no"); fprintf(stderr, "tint2: DnD %s:%d: Protocol version = %d\n", __FILE__, __LINE__, dnd_version); - fprintf(stderr, "tint2: DnD %s:%d: Type 1 = %s\n", __FILE__, __LINE__, GetAtomName(server.display, e->data.l[2])); - fprintf(stderr, "tint2: DnD %s:%d: Type 2 = %s\n", __FILE__, __LINE__, GetAtomName(server.display, e->data.l[3])); - fprintf(stderr, "tint2: DnD %s:%d: Type 3 = %s\n", __FILE__, __LINE__, GetAtomName(server.display, e->data.l[4])); + fprintf(stderr, + "tint2: DnD %s:%d: Type 1 = %s\n", + __FILE__, + __LINE__, + GetAtomName(server.display, e->data.l[2])); + fprintf(stderr, + "tint2: DnD %s:%d: Type 2 = %s\n", + __FILE__, + __LINE__, + GetAtomName(server.display, e->data.l[3])); + fprintf(stderr, + "tint2: DnD %s:%d: Type 3 = %s\n", + __FILE__, + __LINE__, + GetAtomName(server.display, e->data.l[4])); } // Query which conversions are available and pick the best @@ -80,7 +92,11 @@ void handle_dnd_enter(XClientMessageEvent *e) } if (dnd_debug) - fprintf(stderr, "tint2: DnD %s:%d: Requested type = %s\n", __FILE__, __LINE__, GetAtomName(server.display, dnd_atom)); + fprintf(stderr, + "tint2: DnD %s:%d: Requested type = %s\n", + __FILE__, + __LINE__, + GetAtomName(server.display, dnd_atom)); } void handle_dnd_position(XClientMessageEvent *e) @@ -102,9 +118,9 @@ void handle_dnd_position(XClientMessageEvent *e) LauncherIcon *icon = click_launcher_icon(panel, mapX, mapY); if (icon) { accept = 1; - dnd_launcher_exec = icon->cmd; + dnd_launcher_icon = icon; } else { - dnd_launcher_exec = 0; + dnd_launcher_icon = NULL; } } @@ -129,7 +145,7 @@ void handle_dnd_position(XClientMessageEvent *e) void handle_dnd_drop(XClientMessageEvent *e) { - if (dnd_target_window && dnd_launcher_exec) { + if (dnd_target_window && dnd_launcher_icon) { if (dnd_version >= 1) { XConvertSelection(server.display, server.atom.XdndSelection, @@ -173,7 +189,11 @@ 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__, @@ -181,7 +201,7 @@ void handle_dnd_selection_notify(XSelectionEvent *e) GetAtomName(server.display, e->property)); } - if (e->property != None && dnd_launcher_exec) { + if (e->property != None && dnd_launcher_icon) { Property prop = read_property(server.display, dnd_target_window, dnd_selection); // If we're being given a list of targets (possible conversions) @@ -213,10 +233,12 @@ void handle_dnd_selection_notify(XSelectionEvent *e) fprintf(stderr, "tint2: --------\n"); } + // TODO replace this with exec*(...) + int cmd_length = 0; - cmd_length += 1; // ( - cmd_length += strlen(dnd_launcher_exec) + 1; // exec + space - cmd_length += 1; // open double quotes + cmd_length += 1; // ( + cmd_length += strlen(dnd_launcher_icon->cmd) + 1; // exec + space + cmd_length += 1; // open double quotes for (int i = 0; i < prop.nitems * prop.format / 8; i++) { char c = ((char *)prop.data)[i]; if (c == '\n') { @@ -239,7 +261,7 @@ void handle_dnd_selection_notify(XSelectionEvent *e) char *cmd = (char *)calloc(cmd_length, 1); cmd[0] = '\0'; strcat(cmd, "("); - strcat(cmd, dnd_launcher_exec); + strcat(cmd, dnd_launcher_icon->cmd); strcat(cmd, " \""); for (int i = 0; i < prop.nitems * prop.format / 8; i++) { char c = ((char *)prop.data)[i]; @@ -263,7 +285,15 @@ void handle_dnd_selection_notify(XSelectionEvent *e) strcat(cmd, "&)"); if (dnd_debug) fprintf(stderr, "tint2: DnD %s:%d: Running command: %s\n", __FILE__, __LINE__, cmd); - tint_exec(cmd, NULL, NULL, e->time, NULL, 0, 0); + tint_exec(cmd, + NULL, + NULL, + e->time, + NULL, + 0, + 0, + dnd_launcher_icon->start_in_terminal, + dnd_launcher_icon->startup_notification); free(cmd); // Reply OK. diff --git a/src/execplugin/execplugin.c b/src/execplugin/execplugin.c index 87a4ca2..69234a6 100644 --- a/src/execplugin/execplugin.c +++ b/src/execplugin/execplugin.c @@ -577,7 +577,7 @@ void execp_action(void *obj, int button, int x, int y, Time time) setenvd("EXECP_Y", y); setenvd("EXECP_W", execp->area.width); setenvd("EXECP_H", execp->area.height); - pid_t pid = tint_exec(command, NULL, NULL, time, obj, x, y); + pid_t pid = tint_exec(command, NULL, NULL, time, obj, x, y, FALSE, TRUE); unsetenv("EXECP_X"); unsetenv("EXECP_Y"); unsetenv("EXECP_W"); diff --git a/src/launcher/apps-common.c b/src/launcher/apps-common.c index a6d2b5b..e8de09e 100644 --- a/src/launcher/apps-common.c +++ b/src/launcher/apps-common.c @@ -113,6 +113,8 @@ gboolean read_desktop_file_full_path(const char *path, DesktopEntry *entry) { entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL; entry->hidden_from_menus = FALSE; + entry->start_in_terminal = FALSE; + entry->startup_notification = TRUE; FILE *fp = fopen(path, "rt"); if (fp == NULL) { @@ -192,6 +194,10 @@ gboolean read_desktop_file_full_path(const char *path, DesktopEntry *entry) entry->icon = strdup(value); } else if (strcmp(key, "NoDisplay") == 0) { entry->hidden_from_menus = strcasecmp(value, "true") == 0; + } else if (strcmp(key, "Terminal") == 0) { + entry->start_in_terminal = strcasecmp(value, "true") == 0; + } else if (strcmp(key, "StartupNotify") == 0) { + entry->startup_notification = strcasecmp(value, "true") == 0; } } } diff --git a/src/launcher/apps-common.h b/src/launcher/apps-common.h index 6c41a6a..e27ce0d 100644 --- a/src/launcher/apps-common.h +++ b/src/launcher/apps-common.h @@ -17,6 +17,8 @@ typedef struct DesktopEntry { char *path; char *cwd; gboolean hidden_from_menus; + gboolean start_in_terminal; + gboolean startup_notification; } DesktopEntry; // Parses a line of the form "key = value". Modifies the line. diff --git a/src/launcher/launcher.c b/src/launcher/launcher.c index cbef1ad..994837f 100644 --- a/src/launcher/launcher.c +++ b/src/launcher/launcher.c @@ -435,7 +435,7 @@ void launcher_action(LauncherIcon *icon, XEvent *evt, int x, int y) 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); + tint_exec(icon->cmd, icon->cwd, icon->icon_tooltip, evt->xbutton.time, &icon->area, x, y, icon->start_in_terminal, icon->startup_notification); } // Populates the list_icons list from the list_apps list @@ -490,6 +490,8 @@ void launcher_reload_icon(Launcher *launcher, LauncherIcon *launcherIcon) launcherIcon->cwd = strdup(entry.cwd); else launcherIcon->cwd = NULL; + launcherIcon->start_in_terminal = entry.start_in_terminal; + launcherIcon->startup_notification = entry.startup_notification; if (launcherIcon->icon_name) free(launcherIcon->icon_name); launcherIcon->icon_name = entry.icon ? strdup(entry.icon) : strdup(DEFAULT_ICON); diff --git a/src/launcher/launcher.h b/src/launcher/launcher.h index db22e6f..3a311a1 100644 --- a/src/launcher/launcher.h +++ b/src/launcher/launcher.h @@ -33,6 +33,8 @@ typedef struct LauncherIcon { Imlib_Image image_pressed; char *cmd; char *cwd; + gboolean start_in_terminal; + gboolean startup_notification; char *icon_name; char *icon_path; char *icon_tooltip; diff --git a/src/main.c b/src/main.c index 8af7602..f24af2c 100644 --- a/src/main.c +++ b/src/main.c @@ -536,6 +536,7 @@ 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 da2091b..9c4faea 100644 --- a/src/util/common.c +++ b/src/util/common.c @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef HAVE_RSVG #include @@ -267,7 +268,15 @@ int setenvd(const char *name, const int value) } #ifndef TINT2CONF -pid_t tint_exec(const char *command, const char *dir, const char *tooltip, Time time, Area *area, int x, int y) +pid_t tint_exec(const char *command, + const char *dir, + const char *tooltip, + Time time, + Area *area, + int x, + int y, + gboolean terminal, + gboolean startup_notification) { if (!command || strlen(command) == 0) return -1; @@ -362,7 +371,7 @@ pid_t tint_exec(const char *command, const char *dir, const char *tooltip, Time #if HAVE_SN SnLauncherContext *ctx = 0; - if (startup_notifications && time) { + if (startup_notifications && startup_notification && time) { ctx = sn_launcher_context_new(server.sn_display, server.screen); sn_launcher_context_set_name(ctx, tooltip); sn_launcher_context_set_description(ctx, "Application launched from tint2"); @@ -377,7 +386,7 @@ pid_t tint_exec(const char *command, const char *dir, const char *tooltip, Time } else if (pid == 0) { // Child process #if HAVE_SN - if (startup_notifications && time) { + if (startup_notifications && startup_notification && time) { sn_launcher_context_setup_child_process(ctx); } #endif // HAVE_SN @@ -387,10 +396,25 @@ pid_t tint_exec(const char *command, const char *dir, const char *tooltip, Time if (dir) chdir(dir); close_all_fds(); - execl("/bin/sh", "/bin/sh", "-c", command, NULL); - fprintf(stderr, "tint2: Failed to execlp %s\n", command); + if (terminal) { + 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); + } + fprintf(stderr, "tint2: could not execute command in x-terminal-emulator: %s, executting in shell\n", command); + wordexp_t words; + words.we_offs = 2; + wordexp(command, &words, WRDE_DOOFFS | WRDE_SHOWERR); + words.we_wordv[0] = (char*)"sh"; + words.we_wordv[1] = (char*)"-c"; + execvp("sh", words.we_wordv); + fprintf(stderr, "tint2: Failed to execute %s\n", command); #if HAVE_SN - if (startup_notifications && time) { + if (startup_notifications && startup_notification && time) { sn_launcher_context_unref(ctx); } #endif // HAVE_SN @@ -398,7 +422,7 @@ pid_t tint_exec(const char *command, const char *dir, const char *tooltip, Time } else { // Parent process #if HAVE_SN - if (startup_notifications && time) { + if (startup_notifications && startup_notification && time) { g_tree_insert(server.pids, GINT_TO_POINTER(pid), ctx); } #endif // HAVE_SN @@ -425,7 +449,7 @@ pid_t tint_exec(const char *command, const char *dir, const char *tooltip, Time void tint_exec_no_sn(const char *command) { - tint_exec(command, NULL, NULL, 0, NULL, 0, 0); + tint_exec(command, NULL, NULL, 0, NULL, 0, 0, FALSE, FALSE); } #endif diff --git a/src/util/common.h b/src/util/common.h index 803fa24..1a88db2 100644 --- a/src/util/common.h +++ b/src/util/common.h @@ -66,7 +66,15 @@ void extract_values(const char *value, char **value1, char **value2, char **valu void extract_values_4(const char *value, char **value1, char **value2, char **value3, char **value4); // Executes a command in a shell. -pid_t tint_exec(const char *command, const char *dir, const char *tooltip, Time time, Area *area, int x, int y); +pid_t tint_exec(const char *command, + const char *dir, + const char *tooltip, + Time time, + Area *area, + int x, + int y, + gboolean terminal, + gboolean startup_notification); void tint_exec_no_sn(const char *command); int setenvd(const char *name, const int value);