Skip to content

Commit

Permalink
rdp shell/rdp backend: support associate window id (#140)
Browse files Browse the repository at this point in the history
Co-authored-by: Hideyuki Nagase <hideyukn@HIDEYUKN-SB3>
  • Loading branch information
hideyukn88 and Hideyuki Nagase authored Mar 9, 2023
1 parent 28553ce commit f09791f
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 36 deletions.
2 changes: 2 additions & 0 deletions include/libweston/backend-rdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,15 @@ struct weston_rdprail_app_list_data {
bool newAppId;
bool deleteAppId;
bool deleteAppProvider;
bool associateWindowId;
char *appId;
char *appGroup;
char *appExecPath;
char *appWorkingDir;
char *appDesc;
char *appProvider;
pixman_image_t *appIcon;
uint32_t appWindowId;
};

struct weston_rdp_rail_window_pos {
Expand Down
2 changes: 1 addition & 1 deletion libweston/backend-rdp/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ if not dep_wpr.found()
endif
endif

dep_rdpapplist = dependency('rdpapplist', version: '>= 1.0.0', required: false)
dep_rdpapplist = dependency('rdpapplist', version: '>= 2.0.0', required: false)
if dep_rdpapplist.found()
config_h.set('HAVE_FREERDP_RDPAPPLIST_H', '1')
endif
Expand Down
45 changes: 42 additions & 3 deletions libweston/backend-rdp/rdprail.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,8 +770,8 @@ rail_client_ClientGetAppidReq_callback(bool freeOnly, void *arg)
goto Exit;
}

rdp_debug(b, "Client: ClientGetAppidReq: pid:%d appId:%s\n",
(uint32_t)pid, appId);
rdp_debug(b, "Client: ClientGetAppidReq: pid:%d appId:%s WindowId:0x%x\n",
(uint32_t)pid, appId, getAppidReq->windowId);
rdp_debug_verbose(b,
"Client: ClientGetAppidReq: pid:%d imageName:%s\n",
(uint32_t)pid, imageName);
Expand Down Expand Up @@ -3460,9 +3460,20 @@ rdp_rail_peer_activate(freerdp_peer* client)

rdp_debug(b, "Server AppList caps version:%d\n", RDPAPPLIST_CHANNEL_VERSION);
app_list_caps.version = RDPAPPLIST_CHANNEL_VERSION;
rdp_debug(b, " appListProviderName:%s\n", b->rdprail_shell_name);
if (!utf8_string_to_rail_string(b->rdprail_shell_name,
&app_list_caps.appListProviderName))
goto error_exit;
#if RDPAPPLIST_CHANNEL_VERSION >= 4
/* assign unique id */
char *s = getenv("WSLG_SERVICE_ID");
if (!s)
s = b->rdprail_shell_name;
rdp_debug(b, " appListProviderUniqueId:%s\n", s);
if (!utf8_string_to_rail_string(s,
&app_list_caps.appListProviderUniqueId))
goto error_exit;
#endif /* RDPAPPLIST_CHANNEL_VERSION >= 4 */
if (applist_ctx->ApplicationListCaps(applist_ctx, &app_list_caps) != CHANNEL_RC_OK)
goto error_exit;
free(app_list_caps.appListProviderName.string);
Expand Down Expand Up @@ -4624,15 +4635,43 @@ rdp_rail_notify_app_list(void *rdp_backend,
rdp_debug(b, " newAppId: %d\n", app_list_data->newAppId);
rdp_debug(b, " deleteAppId: %d\n", app_list_data->deleteAppId);
rdp_debug(b, " deleteAppProvider: %d\n", app_list_data->deleteAppProvider);
rdp_debug(b, " associateWindowId: %d\n", app_list_data->associateWindowId);
rdp_debug(b, " appId: %s\n", app_list_data->appId);
rdp_debug(b, " appGroup: %s\n", app_list_data->appGroup);
rdp_debug(b, " appExecPath: %s\n", app_list_data->appExecPath);
rdp_debug(b, " appWorkingDir: %s\n", app_list_data->appWorkingDir);
rdp_debug(b, " appDesc: %s\n", app_list_data->appDesc);
rdp_debug(b, " appIcon: %p\n", app_list_data->appIcon);
rdp_debug(b, " appProvider: %s\n", app_list_data->appProvider);
rdp_debug(b, " appWindowId: 0x%x\n", app_list_data->appWindowId);

if (app_list_data->associateWindowId) {
RDPAPPLIST_ASSOCIATE_WINDOW_ID_PDU associate_window_id = {};

assert(app_list_data->appProvider == NULL);
associate_window_id.flags = RDPAPPLIST_FIELD_ID | RDPAPPLIST_FIELD_WINDOW_ID;
associate_window_id.appWindowId = app_list_data->appWindowId;
if (app_list_data->appId == NULL ||
!utf8_string_to_rail_string(app_list_data->appId, &associate_window_id.appId))
goto Exit_associateWindowId;

if (app_list_data->deleteAppId) {
if (app_list_data->appGroup &&
utf8_string_to_rail_string(app_list_data->appGroup, &associate_window_id.appGroup)) {
associate_window_id.flags |= RDPAPPLIST_FIELD_GROUP;
}
if (app_list_data->appExecPath &&
utf8_string_to_rail_string(app_list_data->appExecPath, &associate_window_id.appExecPath)) {
associate_window_id.flags |= RDPAPPLIST_FIELD_EXECPATH;
}
if (app_list_data->appDesc &&
utf8_string_to_rail_string(app_list_data->appDesc, &associate_window_id.appDesc)) {
associate_window_id.flags |= RDPAPPLIST_FIELD_DESC;
}
applist_ctx->AssociateWindowId(applist_ctx, &associate_window_id);
Exit_associateWindowId:
free(associate_window_id.appId.string);
free(associate_window_id.appGroup.string);
} else if (app_list_data->deleteAppId) {
RDPAPPLIST_DELETE_APPLIST_PDU delete_app_list = {};

assert(app_list_data->appProvider == NULL);
Expand Down
102 changes: 101 additions & 1 deletion rdprail-shell/app-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@

#if HAVE_GLIB && HAVE_WINPR

#define NUM_CONTROL_EVENT 5
#define NUM_CONTROL_EVENT 6

#define EVENT_TIMEOUT_MS 2000 // 2 seconds
#define MAX_ICON_RETRY_COUNT 5
Expand All @@ -79,6 +79,7 @@ struct app_list_context {
HANDLE stopRdpNotifyEvent; // control event: wait index 2
HANDLE loadIconEvent; // control event: wait index 3
HANDLE findImageNameEvent; // control event: wait index 4
HANDLE associateWindowAppIdEvent;// control event: wait index 5
HANDLE replyEvent;
bool isRdpNotifyStarted;
bool isAppListNamespaceAttached;
Expand All @@ -97,6 +98,11 @@ struct app_list_context {
char *image_name;
size_t image_name_size;
} find_image_name;
struct {
pid_t pid;
char *app_id;
uint32_t window_id;
} associate_window_app_id;
struct {
char requestedClientLanguageId[32]; // 32 = RDPAPPLIST_LANG_SIZE.
char currentClientLanguageId[32];
Expand Down Expand Up @@ -389,6 +395,41 @@ send_app_entry(struct desktop_shell *shell, char *key, struct app_entry *entry,
pixman_image_unref(app_list_data.appIcon);
}

static void
send_associate_window_app_id(struct desktop_shell *shell, pid_t pid, char *app_id, uint32_t window_id)
{
struct app_list_context *context = (struct app_list_context *)shell->app_list_context;
struct weston_rdprail_app_list_data app_list_data = {};
struct app_entry *entry;
char *app_exec = NULL;
char *app_desc = NULL;

if (!shell->rdprail_api->notify_app_list)
return;

entry = (struct app_entry *)HashTable_GetItemValue(context->table, app_id);
if (entry) {
app_exec = entry->try_exec ? entry->try_exec : entry->exec;
app_desc = entry->name;
}

if (!app_exec) {
/*TODO: obtain from /proc/[pid]/cmdline */
}

if (!app_desc)
app_desc = app_id;

app_list_data.associateWindowId = true;
app_list_data.appId = app_id;
app_list_data.appGroup = NULL;
app_list_data.appExecPath = app_exec;
app_list_data.appDesc = app_desc;
app_list_data.appWindowId = window_id;

shell->rdprail_api->notify_app_list(shell->rdp_backend, &app_list_data);
}

static void
retry_find_icon_file(struct desktop_shell *shell)
{
Expand Down Expand Up @@ -909,6 +950,7 @@ app_list_monitor_thread(LPVOID arg)
events[num_events++] = context->stopRdpNotifyEvent;
events[num_events++] = context->loadIconEvent;
events[num_events++] = context->findImageNameEvent;
events[num_events++] = context->associateWindowAppIdEvent;
assert(num_events == NUM_CONTROL_EVENT);

/* append optional folders */
Expand Down Expand Up @@ -1084,6 +1126,22 @@ app_list_monitor_thread(LPVOID arg)
continue;
}

/* Associate Window/AppId event */
if (status == WAIT_OBJECT_0 + 5) {
shell_rdp_debug_verbose(shell, "app_list_monitor_thread: associateWindowAppIdEvent is signalled. pid:%d, app_id:%s, window_id:0x%x\n",
context->associate_window_app_id.pid,
context->associate_window_app_id.app_id,
context->associate_window_app_id.window_id);

send_associate_window_app_id(shell,
context->associate_window_app_id.pid,
context->associate_window_app_id.app_id,
context->associate_window_app_id.window_id);

SetEvent(context->replyEvent);
continue;
}

/* Somethings are changed in watch folders */
if (shell->rdprail_api->notify_app_list && num_watch) {
len = read(fd[status - WAIT_OBJECT_0 - NUM_CONTROL_EVENT], buf, sizeof buf);
Expand Down Expand Up @@ -1172,6 +1230,11 @@ start_app_list_monitor(struct desktop_shell *shell)
if (!context->findImageNameEvent)
goto Error_Exit;

/* bManualReset = TRUE, ideally here needs FALSE, but winpr doesn't support it */
context->associateWindowAppIdEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!context->associateWindowAppIdEvent)
goto Error_Exit;

/* bManualReset = TRUE, ideally here needs FALSE, but winpr doesn't support it */
context->replyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!context->replyEvent)
Expand All @@ -1190,6 +1253,11 @@ start_app_list_monitor(struct desktop_shell *shell)
context->replyEvent = NULL;
}

if (context->associateWindowAppIdEvent) {
CloseHandle(context->associateWindowAppIdEvent);
context->associateWindowAppIdEvent = NULL;
}

if (context->findImageNameEvent) {
CloseHandle(context->findImageNameEvent);
context->findImageNameEvent = NULL;
Expand Down Expand Up @@ -1246,6 +1314,11 @@ stop_app_list_monitor(struct desktop_shell *shell)
context->replyEvent = NULL;
}

if (context->associateWindowAppIdEvent) {
CloseHandle(context->associateWindowAppIdEvent);
context->associateWindowAppIdEvent = NULL;
}

if (context->findImageNameEvent) {
CloseHandle(context->findImageNameEvent);
context->findImageNameEvent = NULL;
Expand Down Expand Up @@ -1330,6 +1403,33 @@ void app_list_find_image_name(struct desktop_shell *shell, pid_t pid, char *imag
return;
}

void app_list_associate_window_app_id(struct desktop_shell *shell, pid_t pid, char *app_id, uint32_t window_id)
{
#if HAVE_WINPR && HAVE_GLIB
struct app_list_context *context = (struct app_list_context *)shell->app_list_context;

if (context) {
assert(context->associate_window_app_id.pid == (pid_t) 0);
assert(context->associate_window_app_id.app_id == NULL);
assert(context->associate_window_app_id.window_id == 0);
context->associate_window_app_id.pid = pid;
context->associate_window_app_id.app_id = app_id;
context->associate_window_app_id.window_id = window_id;

/* signal worker thread to load icon at worker thread */
SetEvent(context->associateWindowAppIdEvent);
WaitForSingleObject(context->replyEvent, INFINITE);
/* here must reset since winpr doesn't support auto reset event */
ResetEvent(context->replyEvent);

context->associate_window_app_id.pid = (pid_t) 0;
context->associate_window_app_id.app_id = NULL;
context->associate_window_app_id.window_id = 0;
}
#endif
return;
}

bool app_list_start_backend_update(struct desktop_shell *shell, char *clientLanguageId)
{
#if HAVE_WINPR && HAVE_GLIB
Expand Down
78 changes: 47 additions & 31 deletions rdprail-shell/shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ struct shell_surface {
bool is_icon_set;
} icon;

struct {
bool is_window_app_id_associated;
} app_id;

struct wl_listener metadata_listener;
};

Expand Down Expand Up @@ -2612,12 +2616,6 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
wl_list_for_each(view, &surface->views, surface_link)
weston_view_update_transform(view);
}

if (!shsurf->icon.is_icon_set) {
/* TODO hook to meta data change notification */
shell_surface_set_window_icon(desktop_surface, 0, 0, 0, NULL, NULL);
shsurf->icon.is_icon_set = true;
}
}

static void
Expand Down Expand Up @@ -4635,6 +4633,7 @@ shell_backend_get_app_id(void *shell_context, struct weston_surface *surface, ch
{
struct desktop_shell *shell = (struct desktop_shell *)shell_context;
struct weston_desktop_surface *desktop_surface;
struct weston_surface_rail_state *rail_state;
struct shell_surface *shsurf;
const struct weston_xwayland_surface_api *api;
pid_t pid;
Expand All @@ -4655,31 +4654,35 @@ shell_backend_get_app_id(void *shell_context, struct weston_surface *surface, ch
if (!desktop_surface)
return -1;

/* obtain application id specified via wayland interface */
id = weston_desktop_surface_get_app_id(desktop_surface);
if (id) {
strncpy(app_id, id, app_id_size);
} else {
/* if app_id is not specified via wayland interface,
obtain class name from X server for X app, and use as app_id */
shsurf = weston_desktop_surface_get_user_data(desktop_surface);
if (shsurf) {
api = shsurf->shell->xwayland_surface_api;
if (!api) {
api = weston_xwayland_surface_get_api(shsurf->shell->compositor);
shsurf->shell->xwayland_surface_api = api;
}
if (api && api->is_xwayland_surface(surface)) {
class_name = api->get_class_name(surface);
if (class_name) {
strncpy(app_id, class_name, app_id_size);
free(class_name);
/* app_id is from Xwayland */
is_wayland = false;
}
}
shsurf = weston_desktop_surface_get_user_data(desktop_surface);
if (!shsurf)
return -1;

rail_state = (struct weston_surface_rail_state *)surface->backend_state;
if (!rail_state)
return -1;

/* first obtain class name from X server for X app, and use as app_id */
api = shsurf->shell->xwayland_surface_api;
if (!api) {
api = weston_xwayland_surface_get_api(shsurf->shell->compositor);
shsurf->shell->xwayland_surface_api = api;
}
if (api && api->is_xwayland_surface(surface)) {
class_name = api->get_class_name(surface);
if (class_name) {
strncpy(app_id, class_name, app_id_size);
free(class_name);
/* app_id is from Xwayland */
is_wayland = false;
}
}
/* if not, obtain application id specified via wayland interface */
if (app_id[0] == '\0') {
id = weston_desktop_surface_get_app_id(desktop_surface);
if (id)
strncpy(app_id, id, app_id_size);
}

/* obtain pid for execuable path */
pid = weston_desktop_surface_get_pid(desktop_surface);
Expand All @@ -4700,8 +4703,21 @@ shell_backend_get_app_id(void *shell_context, struct weston_surface *surface, ch
strncpy(image_name, app_id, image_name_size);
}

shell_rdp_debug_verbose(shell, "shell_backend_get_app_id: 0x%p: pid:%d, app_id:%s, image_name:%s\n",
surface, pid, app_id, image_name);
shell_rdp_debug_verbose(shell, "shell_backend_get_app_id: 0x%p: pid:%d, app_id:%s, windowId:0x%x, image_name:%s\n",
surface, pid, app_id, rail_state->window_id, image_name);

/* obtain window icon for app */
if (!shsurf->icon.is_icon_set) {
/* TODO hook to meta data change notification */
shell_surface_set_window_icon(desktop_surface, 0, 0, 0, NULL, NULL);
shsurf->icon.is_icon_set = true;
}

/* associate window and app_id at client side */
if (!shsurf->app_id.is_window_app_id_associated && app_id[0] != '\0') {
app_list_associate_window_app_id(shsurf->shell, pid, app_id, rail_state->window_id);
shsurf->app_id.is_window_app_id_associated = true;
}

return pid;
}
Expand Down
1 change: 1 addition & 0 deletions rdprail-shell/shell.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,5 +204,6 @@ pixman_image_t *app_list_load_icon_file(struct desktop_shell *shell, const char
bool app_list_start_backend_update(struct desktop_shell *shell, char *clientLanguageId);
void app_list_stop_backend_update(struct desktop_shell *shell);
void app_list_find_image_name(struct desktop_shell *shell, pid_t pid, char *image_name, size_t image_name_size, bool is_wayland);
void app_list_associate_window_app_id(struct desktop_shell *shell, pid_t pid, char *app_id, uint32_t window_id);
// img-load.c
pixman_image_t *load_icon_image(struct desktop_shell *shell, const char *filename);

0 comments on commit f09791f

Please sign in to comment.