Skip to content

Commit

Permalink
rdp shell: add icon file search retry (#117)
Browse files Browse the repository at this point in the history
* rdp shell: add icon search retry

* misc fixes

* misc fixes

* misc fixes

Co-authored-by: Hideyuki Nagase <hideyukn@ntdev.microsoft.com>
  • Loading branch information
hideyukn88 and Hideyuki Nagase authored Oct 4, 2022
1 parent 32963ae commit 2270ceb
Showing 1 changed file with 121 additions and 57 deletions.
178 changes: 121 additions & 57 deletions rdprail-shell/app-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@

#define NUM_CONTROL_EVENT 5

#define EVENT_TIMEOUT_MS 2000 // 2 seconds
#define MAX_ICON_RETRY_COUNT 5

struct app_list_context {
wHashTable* table;
HANDLE thread;
Expand All @@ -81,6 +84,7 @@ struct app_list_context {
bool isAppListNamespaceAttached;
int app_list_pidfd;
int weston_pidfd;
uint32_t icon_retry_count;
pixman_image_t* default_icon;
pixman_image_t* default_overlay_icon;
struct {
Expand All @@ -106,8 +110,10 @@ struct app_entry {
char *exec;
char *try_exec;
char *working_dir;
char *icon;
char *icon_name;
char *icon_file;
pixman_image_t* icon_image;
uint32_t icon_retry_count;
};

/* TODO: obtain additional path from $XDG_DATA_DIRS, default path is defined here */
Expand Down Expand Up @@ -241,57 +247,84 @@ is_desktop_file(char *file)
return NULL;
}

static char *
find_icon_file(char *name)
static bool
find_icon_file(struct app_entry *entry)
{
struct desktop_shell *shell = entry->shell;
struct app_list_context *context = (struct app_list_context *)shell->app_list_context;
char buf[512];
int len;
char *icon_file = buf;

/* if name is absolute path and file presents, use as-is */
if (*name == '/') {
if (is_file_exist(name))
return strdup(name);
return NULL;
}
assert(entry->icon_name);
assert(entry->icon_file == NULL);
assert(entry->icon_retry_count < MAX_ICON_RETRY_COUNT);

/* TODO: follow icon search path desribed at "Icon Lookup" section at
/* if name is absolute path and file presents, use as-is */
if (*entry->icon_name == '/') {
if (is_file_exist(entry->icon_name)) {
icon_file = entry->icon_name;
goto Found;
}
} else {
/* TODO: follow icon search path desribed at "Icon Lookup" section at
https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html */
for (int i = 0; i < (int)ARRAY_LENGTH(icon_folder); i++) {
copy_string(buf, sizeof buf, icon_folder[i]);
append_string(buf, sizeof buf, name);
len = strlen(buf);

/* first, try given file name as is */
if (is_file_exist(buf))
return strdup(buf);

/* if not found, try again with .png extension appended */
append_string(buf, sizeof buf, ".png");
if (is_file_exist(buf))
return strdup(buf);

/* if not found, try again with .svg extension appended */
copy_string(&buf[len], sizeof buf - len, ".svg");
if (is_file_exist(buf))
return strdup(buf);
for (int i = 0; i < (int)ARRAY_LENGTH(icon_folder); i++) {
copy_string(buf, sizeof buf, icon_folder[i]);
append_string(buf, sizeof buf, entry->icon_name);
len = strlen(buf);

/* first, try given file name as is */
if (is_file_exist(buf))
goto Found;

/* if not found, try again with .png extension appended */
append_string(buf, sizeof buf, ".png");
if (is_file_exist(buf))
goto Found;

/* if not found, try again with .svg extension appended */
copy_string(&buf[len], sizeof buf - len, ".svg");
if (is_file_exist(buf))
goto Found;
}
}

return NULL;
if (entry->icon_retry_count++ == 0)
context->icon_retry_count++;
else if (entry->icon_retry_count == MAX_ICON_RETRY_COUNT)
context->icon_retry_count--;
shell_rdp_debug(entry->shell, "%s: icon (%s) search retry:(%d) global:(%d)\n",
__func__, entry->icon_name, entry->icon_retry_count, context->icon_retry_count);
return false;

Found:
if (entry->icon_retry_count)
context->icon_retry_count--;
entry->icon_file = strdup(icon_file);
return (entry->icon_file != NULL);
}

static void
free_app_entry(void *arg)
{
struct app_entry *e = (struct app_entry *)arg;
if (e) {
shell_rdp_debug(e->shell, "free_app_entry(): %s: %s\n", e->name, e->file);
struct desktop_shell *shell = e->shell;
struct app_list_context *context = (struct app_list_context *)shell->app_list_context;

shell_rdp_debug(shell, "free_app_entry(): %s: %s\n", e->name, e->file);

if (e->file) free(e->file);
if (e->name) free(e->name);
if (e->exec) free(e->exec);
if (e->try_exec) free(e->try_exec);
if (e->working_dir) free(e->working_dir);
if (e->icon) free(e->icon);
if (e->icon_name) free(e->icon_name);
if (e->icon_file) free(e->icon_file);
if (e->icon_image) pixman_image_unref(e->icon_image);
if (e->icon_retry_count) context->icon_retry_count--;

free(e);
}
}
Expand Down Expand Up @@ -340,19 +373,11 @@ send_app_entry(struct desktop_shell *shell, char *key, struct app_entry *entry,
app_list_data.appExecPath = entry->try_exec ? entry->try_exec : entry->exec;
app_list_data.appWorkingDir = entry->working_dir;
app_list_data.appDesc = entry->name;
if (entry->icon) {
attach_app_list_namespace(shell);
if (!entry->icon_file)
entry->icon_file = find_icon_file(entry->icon);
if (entry->icon_file)
app_list_data.appIcon = load_icon_image(shell, entry->icon_file);
detach_app_list_namespace(shell);
}
if (!app_list_data.appIcon) {
app_list_data.appIcon = entry->icon_image;
if (!app_list_data.appIcon)
app_list_data.appIcon = context->default_icon;
if (app_list_data.appIcon)
pixman_image_ref(app_list_data.appIcon);
}
if (app_list_data.appIcon)
pixman_image_ref(app_list_data.appIcon);
if (shell->is_blend_overlay_icon_app_list &&
app_list_data.appIcon &&
app_list_data.appIcon != context->default_icon &&
Expand All @@ -368,6 +393,42 @@ send_app_entry(struct desktop_shell *shell, char *key, struct app_entry *entry,
pixman_image_unref(app_list_data.appIcon);
}

static void
retry_find_icon_file(struct desktop_shell *shell)
{
struct app_list_context *context = (struct app_list_context *)shell->app_list_context;
struct app_entry *entry;
char **keys;
char **cur;
int num_keys;

keys = NULL;
num_keys = HashTable_GetKeys(context->table, (ULONG_PTR**)&keys);
if (num_keys < 0)
return;

cur = keys;
for (int i = 0; i < num_keys; i++, cur++) {
entry = (struct app_entry *)HashTable_GetItemValue(context->table, (void *)*cur);
if (entry &&
entry->icon_name &&
entry->icon_file == NULL &&
entry->icon_retry_count < MAX_ICON_RETRY_COUNT) {
shell_rdp_debug(entry->shell, "%s: icon (%s) retry count (%d)\n",
__func__, entry->icon_name, entry->icon_retry_count);
attach_app_list_namespace(shell);
if (find_icon_file(entry))
entry->icon_image = load_icon_image(shell, entry->icon_file);
detach_app_list_namespace(shell);
if (entry->icon_image)
send_app_entry(shell, *cur, entry, false, false, false, false, false, false);
}
}

if (keys)
free(keys);
}

static void
trim_command_exec(char *s)
{
Expand Down Expand Up @@ -480,10 +541,11 @@ update_app_entry(struct desktop_shell *shell, char *file, struct app_entry *entr
if (entry->try_exec)
trim_command_exec(entry->try_exec);
entry->working_dir = g_key_file_get_string(key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
entry->icon = g_key_file_get_locale_string(key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, lang_id, NULL);
if (entry->icon) {
entry->icon_name = g_key_file_get_locale_string(key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, lang_id, NULL);
if (entry->icon_name) {
attach_app_list_namespace(shell);
entry->icon_file = find_icon_file(entry->icon);
if (find_icon_file(entry))
entry->icon_image = load_icon_image(shell, entry->icon_file);
detach_app_list_namespace(shell);
}
g_key_file_free(key_file);
Expand All @@ -493,8 +555,9 @@ update_app_entry(struct desktop_shell *shell, char *file, struct app_entry *entr
shell_rdp_debug(shell, " Exec:%s\n", entry->exec);
shell_rdp_debug(shell, " TryExec:%s\n", entry->try_exec);
shell_rdp_debug(shell, " WorkingDir:%s\n", entry->working_dir);
shell_rdp_debug(shell, " Icon name:%s\n", entry->icon);
shell_rdp_debug(shell, " Icon name:%s\n", entry->icon_name);
shell_rdp_debug(shell, " Icon file:%s\n", entry->icon_file);
shell_rdp_debug(shell, " Icon image:%p\n", entry->icon_image);

return true;

Expand Down Expand Up @@ -900,7 +963,8 @@ app_list_monitor_thread(LPVOID arg)

/* now loop as changes are made or stop event is signaled */
while (TRUE) {
status = WaitForMultipleObjects(num_events, events, FALSE, INFINITE);
status = WaitForMultipleObjects(num_events, events, FALSE,
context->icon_retry_count ? EVENT_TIMEOUT_MS : INFINITE);
if (status == WAIT_FAILED) {
error = GetLastError();
break;
Expand All @@ -909,6 +973,12 @@ app_list_monitor_thread(LPVOID arg)
/* winpr doesn't support auto-reset event */
ResetEvent(events[status - WAIT_OBJECT_0]);

/* Timeout */
if (status == WAIT_TIMEOUT) {
retry_find_icon_file(shell);
continue;
}

/* Stop Event */
if (status == WAIT_OBJECT_0) {
shell_rdp_debug(shell, "app_list_monitor_thread: stopEvent is signalled\n");
Expand Down Expand Up @@ -942,13 +1012,9 @@ app_list_monitor_thread(LPVOID arg)
shell_rdp_debug(shell, "app_list_monitor_thread: loadIconEvent is signalled. %s\n", context->load_icon.key);
if (context->load_icon.key) {
entry = (struct app_entry *)HashTable_GetItemValue(context->table, (void*)context->load_icon.key);
if (entry && entry->icon) {
attach_app_list_namespace(shell);
if (!entry->icon_file)
entry->icon_file = find_icon_file(entry->icon);
if (entry->icon_file)
context->load_icon.image = load_icon_image(shell, entry->icon_file);
detach_app_list_namespace(shell);
if (entry && entry->icon_image) {
context->load_icon.image = entry->icon_image;
pixman_image_ref(context->load_icon.image);
}
shell_rdp_debug(shell, "app_list_monitor_thread: entry %p, image %p\n", entry, context->load_icon.image);
}
Expand Down Expand Up @@ -990,8 +1056,6 @@ app_list_monitor_thread(LPVOID arg)
if (shell->rdprail_api->notify_app_list && num_watch) {
len = read(fd[status - WAIT_OBJECT_0 - NUM_CONTROL_EVENT], buf, sizeof buf);
cur = 0;
if (len)
sleep(2); /* workaround to settle .desktop file and other resoures write */
while (cur < len) {
event = (struct inotify_event *)&buf[cur];
if (event->len &&
Expand Down

0 comments on commit 2270ceb

Please sign in to comment.