Hi
On Sun, Aug 30, 2026 at 9:47 AM Chengyang Zhu <[email protected]> wrote:
>
> Currently, the SetUIInfo method cannot set a refresh rate.
> Simply adding a refresh_rate argument would break the method signature.
>
> This patch adds the UIInfo interface containing
> * property `Supported` indicating whether console UI info is supported.
> * the method `Apply` taking a dictionary as input.
> * the method `Get` returning the current UI info as a dictionary.
>
> Signed-off-by: Chengyang Zhu <[email protected]>
> ---
> ui/dbus-console.c | 106 +++++++++++++++++++++++++++++++++++++++++++
> ui/dbus-display1.xml | 50 ++++++++++++++++++++
> 2 files changed, 156 insertions(+)
>
> diff --git a/ui/dbus-console.c b/ui/dbus-console.c
> index e1ac06814b..947c3b3a54 100644
> --- a/ui/dbus-console.c
> +++ b/ui/dbus-console.c
> @@ -55,6 +55,8 @@ struct _DBusDisplayConsole {
> guint last_x;
> guint last_y;
> Notifier mouse_mode_notifier;
> +
> + QemuDBusDisplay1UIInfo *iface_ui_info;
> };
>
> G_DEFINE_TYPE(DBusDisplayConsole,
> @@ -155,6 +157,7 @@ dbus_display_console_dispose(GObject *object)
> qemu_input_led_notifier_remove(&ddc->led_notifier);
> qemu_console_unregister_listener(&ddc->dcl);
> qemu_remove_mouse_mode_change_notifier(&ddc->mouse_mode_notifier);
> + g_clear_object(&ddc->iface_ui_info);
> g_clear_object(&ddc->iface_touch);
> g_clear_object(&ddc->iface_mouse);
> g_clear_object(&ddc->iface_kbd);
> @@ -528,6 +531,98 @@ dbus_mouse_mode_change(Notifier *notify, void *data)
> dbus_mouse_update_is_absolute(ddc);
> }
>
> +static gboolean
> +dbus_ui_info_get(DBusDisplayConsole *ddc,
> + GDBusMethodInvocation *invocation)
> +{
> + QemuUIInfo ui_info;
> + GVariantDict dict;
> +
> + if (!qemu_console_ui_info_supported(ddc->dcl.con)) {
> + g_dbus_method_invocation_return_error(invocation,
> + DBUS_DISPLAY_ERROR,
> + DBUS_DISPLAY_ERROR_UNSUPPORTED,
> + "UIInfo is not supported");
> + return DBUS_METHOD_INVOCATION_HANDLED;
> + }
> +
> + ui_info = *qemu_console_get_ui_info(ddc->dcl.con);
> + g_variant_dict_init(&dict, NULL);
> +
> + g_variant_dict_insert(&dict, "width_mm", "q", ui_info.width_mm);
> + g_variant_dict_insert(&dict, "height_mm", "q", ui_info.height_mm);
> + g_variant_dict_insert(&dict, "xoff", "i", ui_info.xoff);
> + g_variant_dict_insert(&dict, "yoff", "i", ui_info.yoff);
> + g_variant_dict_insert(&dict, "width", "u", ui_info.width);
> + g_variant_dict_insert(&dict, "height", "u", ui_info.height);
> + g_variant_dict_insert(&dict, "refresh_rate", "u", ui_info.refresh_rate);
> +
> + qemu_dbus_display1_uiinfo_complete_get(ddc->iface_ui_info, invocation,
> + g_variant_dict_end(&dict));
> +
> + return DBUS_METHOD_INVOCATION_HANDLED;
> +}
> +
> +static bool
> +dbus_ui_info_apply_lookup(GDBusMethodInvocation *invocation,
> + GVariantDict *dict,
> + const gchar *key,
> + const gchar *fmt_str,
> + void *res)
> +{
> + if (g_variant_dict_contains(dict, key) &&
> + !g_variant_dict_lookup(dict, key, fmt_str, res)) {
> + g_dbus_method_invocation_return_error(invocation,
> + DBUS_DISPLAY_ERROR,
> + DBUS_DISPLAY_ERROR_INVALID,
> + "%s must have D-Bus signature
> %s",
> + key, fmt_str);
> + return false;
> + }
> + return true;
A bit surprising that the function returns true for unknown/invalid keys, but ok
> +}
> +
> +static gboolean
> +dbus_ui_info_apply(DBusDisplayConsole *ddc,
> + GDBusMethodInvocation *invocation,
> + GVariant *arg_ui_info)
> +{
> + QemuUIInfo ui_info;
> + g_auto(GVariantDict) dict = G_VARIANT_DICT_INIT(arg_ui_info);
> +
> + if (!qemu_console_ui_info_supported(ddc->dcl.con)) {
> + g_dbus_method_invocation_return_error(invocation,
> + DBUS_DISPLAY_ERROR,
> + DBUS_DISPLAY_ERROR_UNSUPPORTED,
> + "UIInfo is not supported");
> + return DBUS_METHOD_INVOCATION_HANDLED;
> + }
> +
> + ui_info = *qemu_console_get_ui_info(ddc->dcl.con);
> +
> + if (!dbus_ui_info_apply_lookup(invocation, &dict, "width_mm", "q",
> + &ui_info.width_mm) ||
> + !dbus_ui_info_apply_lookup(invocation, &dict, "height_mm", "q",
> + &ui_info.height_mm) ||
> + !dbus_ui_info_apply_lookup(invocation, &dict, "xoff", "i",
> + &ui_info.xoff) ||
> + !dbus_ui_info_apply_lookup(invocation, &dict, "yoff", "i",
> + &ui_info.yoff) ||
> + !dbus_ui_info_apply_lookup(invocation, &dict, "width", "u",
> + &ui_info.width) ||
> + !dbus_ui_info_apply_lookup(invocation, &dict, "height", "u",
> + &ui_info.height) ||
> + !dbus_ui_info_apply_lookup(invocation, &dict, "refresh_rate", "u",
> + &ui_info.refresh_rate)) {
> + return DBUS_METHOD_INVOCATION_HANDLED;
> + }
> +
> + qemu_console_set_ui_info(ddc->dcl.con, &ui_info, false);
> + qemu_dbus_display1_uiinfo_complete_apply(ddc->iface_ui_info, invocation);
> +
> + return DBUS_METHOD_INVOCATION_HANDLED;
> +}
> +
> int dbus_display_console_get_index(DBusDisplayConsole *ddc)
> {
> return qemu_console_get_index(ddc->dcl.con);
> @@ -550,6 +645,7 @@ dbus_display_console_new(DBusDisplay *display,
> QemuConsole *con)
> "org.qemu.Display1.Keyboard",
> "org.qemu.Display1.Mouse",
> "org.qemu.Display1.MultiTouch",
> + "org.qemu.Display1.UIInfo",
> NULL
> };
>
> @@ -626,5 +722,15 @@ dbus_display_console_new(DBusDisplay *display,
> QemuConsole *con)
> qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier);
> dbus_mouse_update_is_absolute(ddc);
>
> + ddc->iface_ui_info = qemu_dbus_display1_uiinfo_skeleton_new();
> + qemu_dbus_display1_uiinfo_set_supported(ddc->iface_ui_info,
> + qemu_console_ui_info_supported(ddc->dcl.con));
> + g_object_connect(ddc->iface_ui_info,
> + "swapped-signal::handle-get", dbus_ui_info_get, ddc,
> + "swapped-signal::handle-apply", dbus_ui_info_apply, ddc,
> + NULL);
> + g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
> + G_DBUS_INTERFACE_SKELETON(ddc->iface_ui_info));
> +
> return ddc;
> }
> diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
> index d96bae2ed6..26483edc37 100644
> --- a/ui/dbus-display1.xml
> +++ b/ui/dbus-display1.xml
> @@ -1159,4 +1159,54 @@
> -->
> <property name="Encoding" type="s" access="read"/>
> </interface>
> +
> + <!--
> + org.qemu.Display1.UIInfo:
> +
> + This interface is implemented on
> + ``/org/qemu/Display1/Console_$id`` (see
> + :dbus:iface:`~org.qemu.Display1.Console`).
> + -->
> + <interface name="org.qemu.Display1.UIInfo">
> + <!--
> + Supported:
> +
> + Whether console UI info is supported.
> + -->
> + <property name="Supported" type="b" access="read"/>
> +
> + <!--
> + Get:
> + @ui_info: a dictionary of current UI info properties.
> +
> + Return the properties of the current console display.
> +
> + - ``width_mm`` (q): the physical display width in millimeters.
> + - ``height_mm`` (q): the physical display height in millimeters.
> + - ``xoff`` (i): the horizontal offset in pixels.
> + - ``yoff`` (i): the vertical offset in pixels.
> + - ``width`` (u): the console width in pixels.
> + - ``height`` (u): the console height in pixels.
> + - ``refresh_rate`` (u): the display refresh rate in millihertz.
> + -->
> + <method name="Get">
> + <arg name="ui_info" type="a{sv}" direction="out"/>
> + </method>
> +
> + <!--
> + Apply:
> + @ui_info: a dictionary of new UI info properties.
> +
> + Apply the properties to the console display.
> + The dictionary schema of ``Apply`` is a subset of that of ``Get``.
> +
> + The properties will be merged with existing values.
> + Extra keys will be ignored.
> + The invocation will fail if any key has the wrong type,
> + leaving the UI info unchanged.
> + -->
> + <method name="Apply">
> + <arg name="ui_info" type="a{sv}" direction="in"/>
> + </method>
> + </interface>
> </node>
> --
> 2.55.0
>
>
lgtm, I can pick this patch unless you want to send a non-rfc version before