Launcher: Support %f and %F
This commit is contained in:
parent
498b665c8a
commit
d49adfdef3
6 changed files with 82 additions and 36 deletions
|
@ -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)
|
void handle_dnd_selection_notify(XSelectionEvent *e)
|
||||||
{
|
{
|
||||||
Atom target = e->target;
|
Atom target = e->target;
|
||||||
|
@ -326,11 +309,7 @@ void handle_dnd_selection_notify(XSelectionEvent *e)
|
||||||
__FILE__,
|
__FILE__,
|
||||||
__LINE__,
|
__LINE__,
|
||||||
GetAtomName(server.display, e->selection));
|
GetAtomName(server.display, e->selection));
|
||||||
fprintf(stderr,
|
fprintf(stderr, "tint2: DnD %s:%d: Target atom = %s\n", __FILE__, __LINE__, GetAtomName(server.display, target));
|
||||||
"tint2: DnD %s:%d: Target atom = %s\n",
|
|
||||||
__FILE__,
|
|
||||||
__LINE__,
|
|
||||||
GetAtomName(server.display, target));
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"DnD %s:%d: Property atom = %s\n",
|
"DnD %s:%d: Property atom = %s\n",
|
||||||
__FILE__,
|
__FILE__,
|
||||||
|
@ -371,25 +350,49 @@ void handle_dnd_selection_notify(XSelectionEvent *e)
|
||||||
fprintf(stderr, "tint2: --------\n");
|
fprintf(stderr, "tint2: --------\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: support %r nd %F
|
|
||||||
// https://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables
|
// https://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables
|
||||||
GString *cmd = g_string_new(dnd_launcher_icon->cmd);
|
GString *cmd = g_string_new(dnd_launcher_icon->cmd);
|
||||||
|
|
||||||
const char *atom_name = GetAtomName(server.display, prop.type);
|
const char *atom_name = GetAtomName(server.display, prop.type);
|
||||||
if (strcasecmp(atom_name, "STRING") == 0 ||
|
if (strcasecmp(atom_name, "STRING") == 0 || strcasecmp(atom_name, "text/uri-list") == 0) {
|
||||||
strcasecmp(atom_name, "text/uri-list") == 0) {
|
|
||||||
GString *url = g_string_new("");
|
GString *url = g_string_new("");
|
||||||
GString *prev_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++) {
|
for (int i = 0; i < prop.nitems * prop.format / 8; i++) {
|
||||||
char c = ((char *)prop.data)[i];
|
char c = ((char *)prop.data)[i];
|
||||||
if (c == '\n') {
|
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
|
// Many programs cannot handle this prefix
|
||||||
tint2_g_string_replace(url, "file://", "");
|
tint2_g_string_replace(url, "file://", "");
|
||||||
// Some programs put duplicates in the list, we remove them
|
// Some programs put duplicates in the list, we remove them
|
||||||
if (strcmp(url->str, prev_url->str) != 0) {
|
if (strcmp(url->str, prev_url->str) != 0) {
|
||||||
g_string_append(cmd, " \"");
|
if (strstr(cmd->str, "%F")) {
|
||||||
g_string_append(cmd, url->str);
|
GString *piece = g_string_new("");
|
||||||
g_string_append(cmd, "\"");
|
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(prev_url, url->str);
|
||||||
g_string_assign(url, "");
|
g_string_assign(url, "");
|
||||||
|
@ -405,6 +408,8 @@ void handle_dnd_selection_notify(XSelectionEvent *e)
|
||||||
g_string_free(url, TRUE);
|
g_string_free(url, TRUE);
|
||||||
g_string_free(prev_url, TRUE);
|
g_string_free(prev_url, TRUE);
|
||||||
}
|
}
|
||||||
|
tint2_g_string_replace(cmd, "%F", "");
|
||||||
|
tint2_g_string_replace(cmd, "%f", "");
|
||||||
if (debug_dnd)
|
if (debug_dnd)
|
||||||
fprintf(stderr, "tint2: DnD %s:%d: Running command: %s\n", __FILE__, __LINE__, cmd->str);
|
fprintf(stderr, "tint2: DnD %s:%d: Running command: %s\n", __FILE__, __LINE__, cmd->str);
|
||||||
tint_exec(cmd->str,
|
tint_exec(cmd->str,
|
||||||
|
|
|
@ -96,6 +96,10 @@ void expand_exec(DesktopEntry *entry, const char *path)
|
||||||
q += strlen("''");
|
q += strlen("''");
|
||||||
q += strlen(path);
|
q += strlen(path);
|
||||||
q--; // To balance the q++ in the for
|
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 {
|
} else {
|
||||||
// We don't care about other expansions
|
// We don't care about other expansions
|
||||||
q--; // Delete the last % from q
|
q--; // Delete the last % from q
|
||||||
|
|
|
@ -385,7 +385,12 @@ void draw_launcher_icon(void *obj, cairo_t *c)
|
||||||
void launcher_icon_dump_geometry(void *obj, int indent)
|
void launcher_icon_dump_geometry(void *obj, int indent)
|
||||||
{
|
{
|
||||||
LauncherIcon *launcherIcon = (LauncherIcon *)obj;
|
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)
|
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_icon((Launcher *)icon->area.parent, icon);
|
||||||
launcher_reload_hidden_icons((Launcher *)icon->area.parent);
|
launcher_reload_hidden_icons((Launcher *)icon->area.parent);
|
||||||
|
|
||||||
if (evt->type == ButtonPress || evt->type == ButtonRelease)
|
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);
|
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
|
// Populates the list_icons list from the list_apps list
|
||||||
|
|
|
@ -536,7 +536,6 @@ void handle_x_event(XEvent *e)
|
||||||
emit_self_restart("compositor changed");
|
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 &&
|
if (systray_enabled && e->xclient.message_type == server.atom._NET_SYSTEM_TRAY_OPCODE &&
|
||||||
e->xclient.format == 32 && e->xclient.window == net_sel_win) {
|
e->xclient.format == 32 && e->xclient.window == net_sel_win) {
|
||||||
handle_systray_event(&e->xclient);
|
handle_systray_event(&e->xclient);
|
||||||
|
|
|
@ -400,10 +400,11 @@ pid_t tint_exec(const char *command,
|
||||||
fprintf(stderr, "tint2: executing in x-terminal-emulator: %s\n", command);
|
fprintf(stderr, "tint2: executing in x-terminal-emulator: %s\n", command);
|
||||||
wordexp_t words;
|
wordexp_t words;
|
||||||
words.we_offs = 2;
|
words.we_offs = 2;
|
||||||
wordexp(command, &words, WRDE_DOOFFS | WRDE_SHOWERR);
|
if (wordexp(command, &words, WRDE_DOOFFS | WRDE_SHOWERR) == 0) {
|
||||||
words.we_wordv[0] = (char*)"x-terminal-emulator";
|
words.we_wordv[0] = (char*)"x-terminal-emulator";
|
||||||
words.we_wordv[1] = (char*)"-e";
|
words.we_wordv[1] = (char*)"-e";
|
||||||
execvp("x-terminal-emulator", words.we_wordv);
|
execvp("x-terminal-emulator", words.we_wordv);
|
||||||
|
}
|
||||||
fprintf(stderr, "tint2: could not execute command in x-terminal-emulator: %s, executting in shell\n", command);
|
fprintf(stderr, "tint2: could not execute command in x-terminal-emulator: %s, executting in shell\n", command);
|
||||||
}
|
}
|
||||||
execlp("sh", "sh", "-c", command, NULL);
|
execlp("sh", "sh", "-c", command, NULL);
|
||||||
|
@ -1033,3 +1034,20 @@ void close_all_fds()
|
||||||
close(fd);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -148,6 +148,8 @@ GSList *slist_remove_duplicates(GSList *list, GCompareFunc eq, GDestroyNotify fr
|
||||||
// A trivial pointer comparator.
|
// A trivial pointer comparator.
|
||||||
gint cmp_ptr(gconstpointer a, gconstpointer b);
|
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) \
|
#define free_and_null(p) \
|
||||||
{ \
|
{ \
|
||||||
free(p); \
|
free(p); \
|
||||||
|
|
Loading…
Reference in a new issue