GUACAMOLE-2123: Fix remote app render issues. Use per-window guac_dis…#673
GUACAMOLE-2123: Fix remote app render issues. Use per-window guac_dis…#673jjheinon wants to merge 1 commit into
Conversation
|
great work |
necouchman
left a comment
There was a problem hiding this comment.
Thanks @jjheinon, this is great - I had started to work on this some time back but hit a couple of walls that I couldn't get past, and it looks like you've figured out the issues I couldn't!
The code looks pretty good to me, though I need to take time to more thoroughly review it - most of the things that need to be changed so far deal with style, particularly the comment blocks of the functions you've implemented.
necouchman
left a comment
There was a problem hiding this comment.
@jjheinon:
A few more changes and a couple of questions. Also, one of your commits lacks the required GUACAMOLE-2123: tag.
Overall looking pretty good and just about ready for merge.
b062650 to
735cd68
Compare
necouchman
left a comment
There was a problem hiding this comment.
Looking pretty good to me. Just one other change for an explicit type-cast at the moment.
061ba6f to
b8aa4f4
Compare
b8aa4f4 to
cdd4ade
Compare
necouchman
left a comment
There was a problem hiding this comment.
One more change, and I think it'll be ready to merge.
10d806b to
50b8f58
Compare
necouchman
left a comment
There was a problem hiding this comment.
This code is looking really good - a handful of changes, mostly to comments, but overall I'm liking it.
@jjheinon Are you good with it? I see a lot of comments and pushes coming in - do we need to convert it to a draft at this point, or are you good with it?
a308e7a to
534b89a
Compare
|
@jjheinon I've marked this as a draft for now as it looks like you're still pretty actively working through things and making changes. When you're happy that it's ready for a final review and merge, just hit that Ready for review button. |
3fedd19 to
40556be
Compare
…ng by tracking RAIL windows as independent Guacamole layers. Synchronize RDPGFX surface updates with RAIL window metadata. Track surface-to-window mappings, window ownership, visibility, geometry, activation, and z-order to render RemoteApp windows independently of the hidden desktop. Add support for both FreeRDP 2.x UpdateSurfaceArea and FreeRDP 3.x UpdateWindowFromSurface, including HiDPI scaling. Improved input responsiveness. Preserve the hidden desktop framebuffer and black background during RemoteApp sessions.
40556be to
f860d9e
Compare
|
Quite happy with it now, not aware of any major issues or bugs (tested on FreeRDP 3.26.0). Also, the GfxProgressive codec is enabled for both non-RAIL and RAIL paths, but making additional codecs user configurable would be a nice improvement. Will probably create a separate ticket about these in the future. |
|
Thanks @jjheinon, I'll try to get it reviewed here today or tomorrow. |
necouchman
left a comment
There was a problem hiding this comment.
A few more items:
- Overall, there are some large blocks of code, particularly in
rail.c, where some inline comments to document the code flow, particularly the "why", would be useful. - In data structures, each variable should be documented independently - I understand the desire to document, e.g.
xandywith a single comment block as they necessarily go together, but 1) it doesn't follow established style in the code, and 2) I think there are actually some reasons why we don't do things that way related to automatic generation of documentation.
| int rdp_x = x; | ||
| int rdp_y = y; |
There was a problem hiding this comment.
I'm looking through the code, here, and I'm not seeing a reason why we need to make copies of the x and y variables in this function? Does one of the other functions where they are passed as an argument through here potentially update them? Or is there some other need to duplicate them?
| * The server-side ID of the RAIL window that was unmapped. | ||
| * | ||
| * @return | ||
| * CHANNEL_RC_OK is always returned. Surface unmapping failures are ignored as the window might not be tracked. |
There was a problem hiding this comment.
If you could wrap this line at 80 columns that'd be nice :-).
| guac_display_layer_raw_context* current_context = NULL; | ||
|
|
||
| /* Full desktop sessions share the resized GDI buffer with the default | ||
| * layer, and must hold an open raw context while the external buffer | ||
| * details change. */ | ||
| if (rdp_client->settings->remote_app == NULL | ||
| || !rdp_client->settings->enable_gfx | ||
| || !rdp_client->rail_background_painted) | ||
| current_context = guac_display_layer_open_raw(default_layer); |
There was a problem hiding this comment.
This there some reason why this particular operation - opening the raw display layer - needs to happen prior to the gdi_resize() call just below this? It looks like there are two identical if statements, here, and I'm just wondering if this guac_display_layer_open_raw() call could be moved inside the if statement down on line 224, or if it needs to happen prior to the FreeRDP GDI buffer resize?
|
|
||
| /* Send client status */ | ||
| guac_client_log(client, GUAC_LOG_TRACE, "Sending RAIL client status."); | ||
| guac_client_log(client, GUAC_LOG_DEBUG, |
There was a problem hiding this comment.
Is there a reason why this should be DEBUG level and not remain TRACE? This seems like pretty low-level log messages, particularly including the actual flags, so I'm thinking TRACE is more appropriate?
| status = rail->ClientExecute(rail, &exec); | ||
| pthread_mutex_unlock(&(rdp_client->message_lock)); | ||
|
|
||
| guac_client_log(client, GUAC_LOG_DEBUG, |
There was a problem hiding this comment.
Since the log message above for the Executing remote application... log is TRACE, this should probably also be TRACE rather than DEBUG.
| int x; | ||
| int y; |
There was a problem hiding this comment.
This is a bit of a nit, but, in keeping with style used throughout the rest of the code, I think these variables need to be documented individually. I also think there's a technical reason behind it - I believe there are some automated processes that use the documentation to generate things like API documentation (e.g. https://guacamole.apache.org/doc/libguac/), and that documenting multiple variables with a single comment may cause some problems with that.
There are several places throughout the code, here, where this needs to be tweaked.
| for (guac_common_list_element* current = rdp_client->rail_windows->head; | ||
| current != NULL; current = current->next) { | ||
|
|
||
| guac_rdp_rail_window* rail_window = current->data; | ||
| if (rail_window == NULL) | ||
| continue; | ||
|
|
||
| if (rail_window->visible && rail_window->has_rail_order | ||
| && !rail_window->has_surface) { | ||
|
|
||
| if (!has_no_surface_window | ||
| || rail_window->z_order > highest_no_surface_z) { | ||
| highest_no_surface_z = rail_window->z_order; | ||
| has_no_surface_window = 1; | ||
| } | ||
|
|
||
| continue; | ||
| } | ||
|
|
||
| if (!rail_window->visible || !rail_window->has_surface | ||
| || !rail_window->has_rail_order) | ||
| continue; | ||
|
|
||
| if (x < rail_window->x || y < rail_window->y | ||
| || x >= rail_window->x + rail_window->layer_width | ||
| || y >= rail_window->y + rail_window->layer_height) | ||
| continue; | ||
|
|
||
| if (clicked_window == NULL || rail_window->z_order > clicked_z) { | ||
| clicked_window = rail_window; | ||
| clicked_z = rail_window->z_order; | ||
| } | ||
|
|
||
| } |
There was a problem hiding this comment.
Might be nice to have a few comments in here to document the code flow in-line.
| if (rdp_client->mouse_button_mask != 0 | ||
| && rdp_client->rail_mouse_window_id != 0) | ||
| target_window = guac_rdp_rail_get_window(rdp_client, | ||
| rdp_client->rail_mouse_window_id); | ||
|
|
||
| if (target_window == NULL) { | ||
|
|
||
| int target_z = 0; | ||
|
|
||
| for (guac_common_list_element* current = rdp_client->rail_windows->head; | ||
| current != NULL; current = current->next) { | ||
|
|
||
| guac_rdp_rail_window* rail_window = current->data; | ||
| if (rail_window == NULL) | ||
| continue; | ||
|
|
||
| if (!rail_window->visible || !rail_window->has_surface | ||
| || !rail_window->has_rail_order) | ||
| continue; | ||
|
|
||
| if (x < rail_window->x || y < rail_window->y | ||
| || x >= rail_window->x + rail_window->layer_width | ||
| || y >= rail_window->y + rail_window->layer_height) | ||
| continue; | ||
|
|
||
| if (target_window == NULL || rail_window->z_order > target_z) { | ||
| target_window = rail_window; | ||
| target_z = rail_window->z_order; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| } | ||
|
|
||
| if (target_window != NULL | ||
| && rdp_client->mouse_button_mask == 0 && mask != 0) | ||
| rdp_client->rail_mouse_window_id = target_window->window_id; | ||
|
|
||
| if (mask == 0) | ||
| rdp_client->rail_mouse_window_id = 0; | ||
|
|
||
| guac_common_list_unlock(rdp_client->rail_windows); |
There was a problem hiding this comment.
Similar to above, a handful of comments in here would be helpful.
|
Note that the build currently fails when using FreeRDP on Rocky9 (2.11.7-7.el9_8.3): |
Fixing remote app render issues with this patch, using per-window guac_display_layer for remote apps. Also introducing a fix for stale desktop background on RDPGFX.
Using per-window guac_display_layer for remote apps and also prevent dirty-region propagation to desktop background. Added support for UpdateSurfaceArea (FreeRDP 2.x) and UpdateWindowFromSurface (FreeRDP 3.x)
When Guacamole's RDP plugin is configured with both RemoteApp and the RDPGFX pipeline enabled, remote application windows fail to render.
With GFX active, FreeRDP does not update RAIL window contents via BeginPaint/Endpaint, but via RDPGFX surfaces using windowId and callbacks.
For FreeRDP 3.x: UpdateWindowFromSurface is called per window-mapped surface with its accumulated invalid region.
For FreeRDP 2.x: UpdateSurfaceArea is called per surface with a rect list.
This patch has a dedicated guac_display_layer for each remote app and derives visibility via showState. Surface content painted with RDPGFX callbacks and scaled to correct size.
Layer is kept hidden until both window position is known and at least one surface paint request has arrived, avoiding flashes and race conditions.
Tested remote apps with FreeRDP 3.26.0 with the latest staging/1.6.1 branch.