TODO This patch does not use a capability to send the old version of the monitors config message (the VDAgentMonitorsConfig one) in case of an old server. Sends the SpiceMsgcMainMonitorsConfig as the monitors_config message, which contains the unique (channel_id, monitor_id) identification pair to identify the monitors_configs with. The message is meant for the server only, which needs to translate the ID pair to a guest_output_id in case it needs to send the monitors_config to the vd_agent. Signed-off-by: Lukáš Hrázký <lhrazky@xxxxxxxxxx> --- src/channel-main.c | 183 +++++++++++++++++++++++++++++---------- subprojects/spice-common | 2 +- 2 files changed, 137 insertions(+), 48 deletions(-) diff --git a/src/channel-main.c b/src/channel-main.c index 44137b9..cff9595 100644 --- a/src/channel-main.c +++ b/src/channel-main.c @@ -1054,6 +1054,53 @@ static void monitors_align(VDAgentMonConfig *monitors, int nmonitors) g_free(sorted_monitors); } +static int monitors_cmp_smh(const void *p1, const void *p2, gpointer user_data) +{ + const SpiceMainHead *m1 = p1; + const SpiceMainHead *m2 = p2; + double d1 = sqrt(m1->x * m1->x + m1->y * m1->y); + double d2 = sqrt(m2->x * m2->x + m2->y * m2->y); + int diff = d1 - d2; + + return diff == 0 ? (char*)p1 - (char*)p2 : diff; +} + +static void monitors_align_smh(SpiceMainHead *monitors, int nmonitors) +{ + gint i, j, x = 0; + guint32 used = 0; + SpiceMainHead *sorted_monitors; + + if (nmonitors == 0) + return; + + /* sort by distance from origin */ + sorted_monitors = g_memdup(monitors, nmonitors * sizeof(SpiceMainHead)); + g_qsort_with_data(sorted_monitors, nmonitors, sizeof(SpiceMainHead), monitors_cmp_smh, NULL); + + /* super-KISS ltr alignment, feel free to improve */ + for (i = 0; i < nmonitors; i++) { + /* Find where this monitor is in the sorted order */ + for (j = 0; j < nmonitors; j++) { + /* Avoid using the same entry twice, this happens with older + virt-viewer versions which always set x and y to 0 */ + if (used & (1 << j)) + continue; + if (memcmp(&monitors[j], &sorted_monitors[i], + sizeof(SpiceMainHead)) == 0) + break; + } + used |= 1 << j; + monitors[j].x = x; + monitors[j].y = 0; + x += monitors[j].width; + if (monitors[j].width || monitors[j].height) + SPICE_DEBUG("#%d +%u+%u-%ux%u", j, monitors[j].x, monitors[j].y, + monitors[j].width, monitors[j].height); + } + g_free(sorted_monitors); +} + #define agent_msg_queue(Channel, Type, Size, Data) \ agent_msg_queue_many((Channel), (Type), (Data), (Size), NULL) @@ -1087,69 +1134,111 @@ gboolean spice_main_send_monitor_config(SpiceMainChannel *channel) **/ gboolean spice_main_channel_send_monitor_config(SpiceMainChannel *channel) { - SpiceMainChannelPrivate *c; - VDAgentMonitorsConfig *mon; - int i, j, monitors; - size_t size; - g_return_val_if_fail(SPICE_IS_MAIN_CHANNEL(channel), FALSE); - c = channel->priv; + + SpiceMainChannelPrivate *c = channel->priv; g_return_val_if_fail(c->agent_connected, FALSE); GArray *monitor_configs = spice_session_get_monitor_configs( spice_channel_get_session(SPICE_CHANNEL(channel))); - if (spice_main_channel_agent_test_capability(channel, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG)) { - monitors = monitor_configs->len; - } else { - monitors = 0; + if (false /* TODO add capability for the old version of the message in this if branch */) { + VDAgentMonitorsConfig *mon; + int i, j, monitors; + size_t size; + + if (spice_main_channel_agent_test_capability(channel, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG)) { + monitors = monitor_configs->len; + } else { + monitors = 0; + for (i = 0; i < monitor_configs->len; i++) { + if (g_array_index(monitor_configs, SpiceMonitorConfig, i).enabled) { + monitors += 1; + } + } + } + + size = sizeof(VDAgentMonitorsConfig) + sizeof(VDAgentMonConfig) * monitors; + mon = g_malloc0(size); + + mon->num_of_monitors = monitors; + if (c->disable_display_position == FALSE || + c->disable_display_align == FALSE) + mon->flags |= VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS; + + CHANNEL_DEBUG(channel, "Sending new monitors config to the vd_agent:"); + j = 0; for (i = 0; i < monitor_configs->len; i++) { - if (g_array_index(monitor_configs, SpiceMonitorConfig, i).enabled) { - monitors += 1; + SpiceMonitorConfig *mc = &g_array_index(monitor_configs, SpiceMonitorConfig, i); + if (!mc->enabled) { + if (spice_main_channel_agent_test_capability(channel, + VD_AGENT_CAP_SPARSE_MONITORS_CONFIG)) + j++; + continue; } + mon->monitors[j].depth = c->display_color_depth ? c->display_color_depth : 32; + mon->monitors[j].width = mc->width; + mon->monitors[j].height = mc->height; + mon->monitors[j].x = mc->x; + mon->monitors[j].y = mc->y; + CHANNEL_DEBUG(channel, " monitor #%d: %ux%u+%d+%d @ %u bpp", j, + mon->monitors[j].width, mon->monitors[j].height, + mon->monitors[j].x, mon->monitors[j].y, + mon->monitors[j].depth); + j++; } - } - size = sizeof(VDAgentMonitorsConfig) + sizeof(VDAgentMonConfig) * monitors; - mon = g_malloc0(size); + if (c->disable_display_align == FALSE) + monitors_align(mon->monitors, mon->num_of_monitors); - mon->num_of_monitors = monitors; - if (c->disable_display_position == FALSE || - c->disable_display_align == FALSE) - mon->flags |= VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS; + agent_msg_queue(channel, VD_AGENT_MONITORS_CONFIG, size, mon); + g_free(mon); - CHANNEL_DEBUG(channel, "sending new monitors config to guest"); - j = 0; - for (i = 0; i < monitor_configs->len; i++) { - SpiceMonitorConfig *mc = &g_array_index(monitor_configs, SpiceMonitorConfig, i); - if (!mc->enabled) { - if (spice_main_channel_agent_test_capability(channel, - VD_AGENT_CAP_SPARSE_MONITORS_CONFIG)) - j++; - continue; + spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE); + if (c->timer_id != 0) { + g_source_remove(c->timer_id); + c->timer_id = 0; } - mon->monitors[j].depth = c->display_color_depth ? c->display_color_depth : 32; - mon->monitors[j].width = mc->width; - mon->monitors[j].height = mc->height; - mon->monitors[j].x = mc->x; - mon->monitors[j].y = mc->y; - CHANNEL_DEBUG(channel, "monitor #%d: %ux%u+%d+%d @ %u bpp", j, - mon->monitors[j].width, mon->monitors[j].height, - mon->monitors[j].x, mon->monitors[j].y, - mon->monitors[j].depth); - j++; - } + } else { + size_t size = sizeof(SpiceMsgcMainMonitorsConfig) + sizeof(SpiceMainHead) * monitor_configs->len; + SpiceMsgcMainMonitorsConfig *msg = g_malloc0(size); - if (c->disable_display_align == FALSE) - monitors_align(mon->monitors, mon->num_of_monitors); + msg->count = monitor_configs->len; - agent_msg_queue(channel, VD_AGENT_MONITORS_CONFIG, size, mon); - g_free(mon); + if (c->disable_display_position == FALSE || + c->disable_display_align == FALSE) { + msg->flags |= VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS; + } - spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE); - if (c->timer_id != 0) { - g_source_remove(c->timer_id); - c->timer_id = 0; + CHANNEL_DEBUG(channel, "Sending new monitors config to the server:"); + + for (size_t i = 0; i < monitor_configs->len; i++) { + SpiceMonitorConfig *mc = &g_array_index(monitor_configs, SpiceMonitorConfig, i); + + msg->heads[i].channel_id = mc->channel_id; + msg->heads[i].monitor_id = mc->monitor_id; + msg->heads[i].depth = c->display_color_depth ? c->display_color_depth : 32; + msg->heads[i].width = mc->width; + msg->heads[i].height = mc->height; + msg->heads[i].x = mc->x; + msg->heads[i].y = mc->y; + + CHANNEL_DEBUG(channel, " monitor channel_id %u, monitor_id %u: %ux%u+%u+%u @ %u bpp", + msg->heads[i].channel_id, msg->heads[i].monitor_id, + msg->heads[i].width, msg->heads[i].height, + msg->heads[i].x, msg->heads[i].y, + msg->heads[i].depth); + } + + if (c->disable_display_align == FALSE) { + monitors_align_smh(msg->heads, msg->count); + } + + SpiceMsgOut *out = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_MAIN_MONITORS_CONFIG); + out->marshallers->msgc_main_monitors_config(out->marshaller, msg); + spice_msg_out_send(out); + + g_free(msg); } return TRUE; diff --git a/subprojects/spice-common b/subprojects/spice-common index f82a6c5..0af835f 160000 --- a/subprojects/spice-common +++ b/subprojects/spice-common @@ -1 +1 @@ -Subproject commit f82a6c5349a9a71485910bd3a57fe588c49d74f8 +Subproject commit 0af835f10e4dd51773dbeeb784fda4364b745874 -- 2.18.0 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel