From patchwork Fri Nov 18 01:44:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kasireddy, Vivek" X-Patchwork-Id: 13047643 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1E487C433FE for ; Fri, 18 Nov 2022 02:05:57 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ovqkk-0007qm-SH; Thu, 17 Nov 2022 21:05:14 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkj-0007qI-G6 for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:13 -0500 Received: from mga18.intel.com ([134.134.136.126]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkh-0008SK-S7 for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:13 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1668737111; x=1700273111; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=vNYLIrODk15ws5FA3V6uw9asG9+QoPhfEsPw/HPUUcI=; b=ff+gW3oQ4JE6pUZdRAlBtOTXQnD8Q+3lJjfYXJbBaIpvPgjYHySdA2NS 1wsbLPx2YdZqJk5XYuwhoU7GRJfNJb3xcp03h9EybhEsVIBdEaaB7ztzz n9cIal60xFtoE/iRJpr13WdWJVhP0PXemN74pil9/LMuLkWhx7Li3Zh0H 2YrZS5qAl2CiEHE+ksP1gnHx6rYRuDBMGG5V0yK/Ix5vWT6GuqAm0OP+1 LPYyddPRjsHt7ThV1cVPEPU7zEUwiWBI2q9GTFBkQYERKOdER2k9zgenE q7Z2Eo9lD5RFvA8x2t6z/mH6K5+Yzdg0/v07sTfkbB2+M1JiYvp5NZ6Us w==; X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="296393525" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="296393525" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="634270854" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="634270854" Received: from vkasired-desk2.fm.intel.com ([10.105.128.127]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 From: Vivek Kasireddy To: qemu-devel@nongnu.org Cc: Vivek Kasireddy , Gerd Hoffmann , Dongwon Kim Subject: [PATCH v2 1/6] ui/gtk: Consider the scaling factor when getting the root coordinates Date: Thu, 17 Nov 2022 17:44:21 -0800 Message-Id: <20221118014426.182599-2-vivek.kasireddy@intel.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221118014426.182599-1-vivek.kasireddy@intel.com> References: <20221118014426.182599-1-vivek.kasireddy@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.126; envelope-from=vivek.kasireddy@intel.com; helo=mga18.intel.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Since gdk_window_get_root_coords() expects a position within the window, we need to translate Guest's cooridinates to window local coordinates by multiplying them with the scaling factor. Cc: Gerd Hoffmann Cc: Dongwon Kim Signed-off-by: Vivek Kasireddy --- ui/gtk.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/gtk.c b/ui/gtk.c index 92daaa6a6e..6c23903173 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -456,7 +456,8 @@ static void gd_mouse_set(DisplayChangeListener *dcl, dpy = gtk_widget_get_display(vc->gfx.drawing_area); gdk_window_get_root_coords(gtk_widget_get_window(vc->gfx.drawing_area), - x, y, &x_root, &y_root); + x * vc->gfx.scale_x, y * vc->gfx.scale_y, + &x_root, &y_root); gdk_device_warp(gd_get_pointer(dpy), gtk_widget_get_screen(vc->gfx.drawing_area), x_root, y_root); From patchwork Fri Nov 18 01:44:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kasireddy, Vivek" X-Patchwork-Id: 13047645 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 55AE8C433FE for ; Fri, 18 Nov 2022 02:06:35 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ovqkm-0007rB-J4; Thu, 17 Nov 2022 21:05:16 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkk-0007qR-9f for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:14 -0500 Received: from mga18.intel.com ([134.134.136.126]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqki-0008UF-Kt for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:13 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1668737112; x=1700273112; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=hxKMkVLMF/xiKJRXg+0U8EDrk2c9wtBqfqOnXNGnP1A=; b=JPWIiXkamVigLoB4VE8cR8JOKqxJyC89PoSeY51FeGFXk4zPrWMAR/76 CuFv/dQTyGFDdj/RGUtLDQ2gjpnI7UnvDu4CoOvF3QdCb2ybKG8GgWruY wqRhYZZakchYuEztL8aU1kJHC5A6JFLbM1VfuXLVG3SxxRY4xhUpmXLIQ woShY59FQ4GvUQjCRGbdpoxuP5zRICmBPmRLU+lgM26BhAH7Q18/kOx4D EafVPJQEirt3Gsmu2i11W75tv0bsnN4Ctb+auW2ax1TOaIGnpNGC2QYMJ lIAoRcmhgCsRe9U1/jKo/wpcrR4wFO71qTImLXhM1iEvhaQq6SettBfRX Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="296393527" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="296393527" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="634270858" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="634270858" Received: from vkasired-desk2.fm.intel.com ([10.105.128.127]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 From: Vivek Kasireddy To: qemu-devel@nongnu.org Cc: Vivek Kasireddy , Gerd Hoffmann , Dongwon Kim Subject: [PATCH v2 2/6] ui/gtk-gl-area: Don't forget to calculate the scaling factors in draw Date: Thu, 17 Nov 2022 17:44:22 -0800 Message-Id: <20221118014426.182599-3-vivek.kasireddy@intel.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221118014426.182599-1-vivek.kasireddy@intel.com> References: <20221118014426.182599-1-vivek.kasireddy@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.126; envelope-from=vivek.kasireddy@intel.com; helo=mga18.intel.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Just like it is done in gtk-egl.c, we need to ensure that the scaling factors are correctly calculated in draw callback. Otherwise, they would just be set to 1.0. And, use gtk_widget_get_allocated_width/height variants to determine width and height in the Wayland case similar to how it is done in draw. Cc: Gerd Hoffmann Cc: Dongwon Kim Signed-off-by: Vivek Kasireddy --- ui/gtk-gl-area.c | 5 +++++ ui/gtk.c | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 682638a197..6799805f8e 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -81,6 +81,9 @@ void gd_gl_area_draw(VirtualConsole *vc) egl_dmabuf_create_sync(dmabuf); } #endif + vc->gfx.scale_x = (double)ww / vc->gfx.w; + vc->gfx.scale_y = (double)wh / vc->gfx.h; + glFlush(); #ifdef CONFIG_GBM if (dmabuf) { @@ -100,6 +103,8 @@ void gd_gl_area_draw(VirtualConsole *vc) surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); + vc->gfx.scale_x = (double)ww / vc->gfx.w; + vc->gfx.scale_y = (double)wh / vc->gfx.h; } } diff --git a/ui/gtk.c b/ui/gtk.c index 6c23903173..9d0c27c9e7 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -883,9 +883,14 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y; window = gtk_widget_get_window(vc->gfx.drawing_area); - ww = gdk_window_get_width(window); - wh = gdk_window_get_height(window); ws = gdk_window_get_scale_factor(window); + if (GDK_IS_WAYLAND_DISPLAY(dpy)) { + ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area); + wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area); + } else { + ww = gdk_window_get_width(window); + wh = gdk_window_get_height(window); + } mx = my = 0; if (ww > fbw) { From patchwork Fri Nov 18 01:44:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kasireddy, Vivek" X-Patchwork-Id: 13047647 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A67DEC43219 for ; Fri, 18 Nov 2022 02:06:36 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ovqkp-0007sF-OI; Thu, 17 Nov 2022 21:05:19 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkn-0007rF-4U for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:17 -0500 Received: from mga18.intel.com ([134.134.136.126]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkk-0008SK-H1 for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:16 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1668737114; x=1700273114; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bNBtkT8BrPXRhVh5qBorPneLzYO3BEyvd/5ZN2v2bOw=; b=Q3F8p414kKGJSZPf7rDZPcyFLCgMXWlNiAvtKG0ws4fU6PTN/hcmJBds 1z9kXnH78qgOqR1LikgjbQcskHF/Ghww4b+SdT8s57M+lTq9b0aP49J6i PvKiiGWyzSUZ3fGml9ygRGBaQFOQrjCoK064f8p6+Yr3gBwGQVmMiRn2I iuJZYSo76ZK7UCjk5w11ThkWOhVkmS06BQj7U14E++NtciWiye8HPEPKf 69w3T2maTSNQlWg2pjX3zcURNXmouwvf/j3loj9iUZaQzcHWN1yuB7a99 YWNsPi2pY/eSqNkeBhoX8NGDPFNIMxdxG2VIvshX5BjJX8CyNcM21Kqdw A==; X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="296393528" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="296393528" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="634270861" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="634270861" Received: from vkasired-desk2.fm.intel.com ([10.105.128.127]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 From: Vivek Kasireddy To: qemu-devel@nongnu.org Cc: Vivek Kasireddy , Gerd Hoffmann , Dongwon Kim Subject: [PATCH v2 3/6] ui/gtk: Handle relative mode events correctly with Wayland compositors Date: Thu, 17 Nov 2022 17:44:23 -0800 Message-Id: <20221118014426.182599-4-vivek.kasireddy@intel.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221118014426.182599-1-vivek.kasireddy@intel.com> References: <20221118014426.182599-1-vivek.kasireddy@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.126; envelope-from=vivek.kasireddy@intel.com; helo=mga18.intel.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org gdk_device_warp() is a no-op when running in a Host environment that is Wayland based as the Wayland protocol does not allow clients to move the cursor to a specific location. This presents a problem when Qemu is running with GTK UI + relative mouse mode, as we would no longer be able to warp the cursor to the Guest's location like it is done when running in Xorg-based environments. To solve this problem, we just store the Guest's cursor location and add/subtract the difference compared to the Host's cursor location when injecting the next motion event. Cc: Gerd Hoffmann Cc: Dongwon Kim Signed-off-by: Vivek Kasireddy --- include/ui/gtk.h | 2 ++ ui/gtk.c | 71 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/include/ui/gtk.h b/include/ui/gtk.h index ae0f53740d..f8df042f95 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -130,6 +130,8 @@ struct GtkDisplayState { gboolean last_set; int last_x; int last_y; + int guest_x; + int guest_y; int grab_x_root; int grab_y_root; VirtualConsole *kbd_owner; diff --git a/ui/gtk.c b/ui/gtk.c index 9d0c27c9e7..8ccc948813 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -447,22 +447,44 @@ static void gd_mouse_set(DisplayChangeListener *dcl, int x, int y, int visible) { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - GdkDisplay *dpy; + GtkDisplayState *s = vc->s; + GdkDisplay *dpy = gtk_widget_get_display(vc->gfx.drawing_area); gint x_root, y_root; if (qemu_input_is_absolute()) { return; } + /* + * When the mouse cursor moves from one vc (or connector in guest + * terminology) to another, some guest compositors (e.g. Weston) + * set x and y to 0 on the old vc. We check for this condition + * and return right away as we do not want to move the cursor + * back to the old vc (at 0, 0). + */ + if (GDK_IS_WAYLAND_DISPLAY(dpy)) { + if (s->ptr_owner != vc || (x == 0 && y == 0)) { + return; + } + } + /* + * Since Wayland compositors do not support clients warping/moving + * the cursor, we just store the Guest's cursor location here and + * add or subtract the difference when injecting the next motion event. + */ + if (GDK_IS_WAYLAND_DISPLAY(dpy)) { + s->guest_x = x; + s->guest_y = y; + return; + } - dpy = gtk_widget_get_display(vc->gfx.drawing_area); gdk_window_get_root_coords(gtk_widget_get_window(vc->gfx.drawing_area), x * vc->gfx.scale_x, y * vc->gfx.scale_y, &x_root, &y_root); gdk_device_warp(gd_get_pointer(dpy), gtk_widget_get_screen(vc->gfx.drawing_area), x_root, y_root); - vc->s->last_x = x; - vc->s->last_y = y; + s->last_x = x; + s->last_y = y; } static void gd_cursor_define(DisplayChangeListener *dcl, @@ -869,6 +891,7 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, { VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; + GdkDisplay *dpy = gtk_widget_get_display(vc->gfx.drawing_area); GdkWindow *window; int x, y; int mx, my; @@ -915,14 +938,41 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, 0, surface_height(vc->gfx.ds)); qemu_input_event_sync(); } else if (s->last_set && s->ptr_owner == vc) { - qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, x - s->last_x); - qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, y - s->last_y); + int dx = x - s->last_x; + int dy = y - s->last_y; + + /* + * To converge/sync the Guest's and Host's cursor locations more + * accurately, we can avoid doing the / 2 below but it appears + * some Guest compositors (e.g. Weston) do not like large jumps; + * so we just do / 2 which seems to work reasonably well. + */ + if (GDK_IS_WAYLAND_DISPLAY(dpy)) { + dx += s->guest_x ? (x - s->guest_x) / 2 : 0; + dy += s->guest_y ? (y - s->guest_y) / 2 : 0; + s->guest_x = 0; + s->guest_y = 0; + } + qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, dx); + qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, dy); qemu_input_event_sync(); } s->last_x = x; s->last_y = y; s->last_set = TRUE; + /* + * When running in Wayland environment, we don't grab the cursor; so, + * we want to return right away as it would not make sense to warp it + * (below). + */ + if (GDK_IS_WAYLAND_DISPLAY(dpy)) { + if (s->ptr_owner != vc) { + s->ptr_owner = vc; + } + return TRUE; + } + if (!qemu_input_is_absolute() && s->ptr_owner == vc) { GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area); GdkDisplay *dpy = gtk_widget_get_display(widget); @@ -961,11 +1011,16 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, { VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; + GdkDisplay *dpy = gtk_widget_get_display(vc->gfx.drawing_area); InputButton btn; - /* implicitly grab the input at the first click in the relative mode */ + /* Implicitly grab the input at the first click in the relative mode. + * However, when running in Wayland environment, some limited testing + * indicates that grabs are not very reliable. + */ if (button->button == 1 && button->type == GDK_BUTTON_PRESS && - !qemu_input_is_absolute() && s->ptr_owner != vc) { + !qemu_input_is_absolute() && s->ptr_owner != vc && + !GDK_IS_WAYLAND_DISPLAY(dpy)) { if (!vc->window) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE); From patchwork Fri Nov 18 01:44:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kasireddy, Vivek" X-Patchwork-Id: 13047642 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A371DC433FE for ; Fri, 18 Nov 2022 02:05:51 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ovqko-0007rz-08; Thu, 17 Nov 2022 21:05:18 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkn-0007rD-23 for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:17 -0500 Received: from mga18.intel.com ([134.134.136.126]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkk-0008UX-P5 for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:16 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1668737114; x=1700273114; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0CDU+QcjUNRnuQu6lFdJk8fyZBNFp/cGaLFC8nvqalI=; b=nXHQAeKLfkyyM5iTJhWyN+U9IHggU/jnWqVIa1Bx5fke4wryHEL3UFpB m3NhFmjLLfhb4uH9EwKWKFGgngygfBAGe97D+6IW+2d+BgoNBMiUX/fu6 Ex6dnl3dlYpAairtpVh5/74b0Ml8GLx1+rCcCxfCILcb3JHqS863MZ9eZ H+4z4WyhghsaeS6btvHyGwWPjA3f1A0IJ4ZLQdWJ+PCMMNkhDl/MMbcq1 jJr4vssYSClc7pdDkqWxppyHuqS3vYgodHpz3CYhSoinm1QKvIPHBs8y5 XaoZZxkMZaj7xC3453GAtSWUk4a0CXH1KD32vAh0AzRKVmHGURMdsUSsg A==; X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="296393529" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="296393529" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="634270865" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="634270865" Received: from vkasired-desk2.fm.intel.com ([10.105.128.127]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 From: Vivek Kasireddy To: qemu-devel@nongnu.org Cc: Vivek Kasireddy , Gerd Hoffmann , Dongwon Kim Subject: [PATCH v2 4/6] ui/gtk: Disable the scanout when a detached tab is closed Date: Thu, 17 Nov 2022 17:44:24 -0800 Message-Id: <20221118014426.182599-5-vivek.kasireddy@intel.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221118014426.182599-1-vivek.kasireddy@intel.com> References: <20221118014426.182599-1-vivek.kasireddy@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.126; envelope-from=vivek.kasireddy@intel.com; helo=mga18.intel.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org When a detached tab window is closed, the underlying (EGL) context is destroyed; therefore, disable the scanout which also destroys the underlying framebuffer (id) and other objects. Also add calls to make the context current in disable scanout and other missing places. Cc: Gerd Hoffmann Cc: Dongwon Kim Signed-off-by: Vivek Kasireddy --- ui/gtk-egl.c | 2 ++ ui/gtk-gl-area.c | 2 ++ ui/gtk.c | 1 + 3 files changed, 5 insertions(+) diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 35f917ceb1..396cb6590a 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -214,6 +214,8 @@ void gd_egl_scanout_disable(DisplayChangeListener *dcl) { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, + vc->gfx.esurface, vc->gfx.ectx); vc->gfx.w = 0; vc->gfx.h = 0; gtk_egl_set_scanout_mode(vc, false); diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 6799805f8e..816f213158 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -275,6 +275,7 @@ void gd_gl_area_scanout_disable(DisplayChangeListener *dcl) { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); gtk_gl_area_set_scanout_mode(vc, false); } @@ -283,6 +284,7 @@ void gd_gl_area_scanout_flush(DisplayChangeListener *dcl, { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); if (vc->gfx.guest_fb.dmabuf) { graphic_hw_gl_block(vc->gfx.dcl.con, true); vc->gfx.guest_fb.dmabuf->draw_submitted = true; diff --git a/ui/gtk.c b/ui/gtk.c index 8ccc948813..4ac3655694 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1367,6 +1367,7 @@ static gboolean gd_tab_window_close(GtkWidget *widget, GdkEvent *event, VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; + dpy_gl_scanout_disable(vc->gfx.dcl.con); gtk_widget_set_sensitive(vc->menu_item, true); gd_widget_reparent(vc->window, s->notebook, vc->tab_item); gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(s->notebook), From patchwork Fri Nov 18 01:44:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kasireddy, Vivek" X-Patchwork-Id: 13047646 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 196DCC4332F for ; Fri, 18 Nov 2022 02:06:36 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ovqkq-0007sE-Ej; Thu, 17 Nov 2022 21:05:20 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkn-0007rI-4t for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:17 -0500 Received: from mga18.intel.com ([134.134.136.126]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkk-0008UF-K3 for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:16 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1668737114; x=1700273114; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zZ8y1d1FbFTlcvDvNWsNgEr/73NLZ1JW9us3UExtaEI=; b=M31wLLlzaaSrwVqyUxMwLlJnmmE5p9B9WErrCboygoPLup/xiWFBcdNb 47wuvAQcMIUXhFaBNGX9u/OvaYNAPpLcTtiQuMUDYKjMi378e7csRWuZi avcXc8C8H7zeGu0kQFG2Q3G+zDsC32R2Va1AfNZsiHIQpp4TUseLQ0Wxe 59HJIUt4en9vfAO+H58CMal31mg8FFU5e5xNMFrvA0C6z04QIDNvrKN6W ZNNhYUgLg7XLS6ApiBkg0aedforv2J7KBGDm3gguV0RyVMraN8Bh5li/S OeSNhM+KrlJkLo4uD3TtkRiOG1K112Evu8gzS2oO90rFJUQDiQgKHfVhr g==; X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="296393530" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="296393530" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="634270868" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="634270868" Received: from vkasired-desk2.fm.intel.com ([10.105.128.127]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 From: Vivek Kasireddy To: qemu-devel@nongnu.org Cc: Vivek Kasireddy , Gerd Hoffmann , Dongwon Kim Subject: [PATCH v2 5/6] ui/gtk: Factor out tab window creation into a separate function Date: Thu, 17 Nov 2022 17:44:25 -0800 Message-Id: <20221118014426.182599-6-vivek.kasireddy@intel.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221118014426.182599-1-vivek.kasireddy@intel.com> References: <20221118014426.182599-1-vivek.kasireddy@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.126; envelope-from=vivek.kasireddy@intel.com; helo=mga18.intel.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Pull the code that creates a new window associated with a notebook tab into a separate function. This new function can be useful not just when user wants to detach a tab but also in the future when a new window creation is needed in other scenarios. Cc: Gerd Hoffmann Cc: Dongwon Kim Signed-off-by: Vivek Kasireddy --- ui/gtk.c | 65 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 4ac3655694..6b0369e3ed 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1400,6 +1400,41 @@ static gboolean gd_win_grab(void *opaque) return TRUE; } +static void gd_tab_window_create(VirtualConsole *vc) +{ + GtkDisplayState *s = vc->s; + + gtk_widget_set_sensitive(vc->menu_item, false); + vc->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); +#if defined(CONFIG_OPENGL) + if (vc->gfx.esurface) { + eglDestroySurface(qemu_egl_display, vc->gfx.esurface); + vc->gfx.esurface = NULL; + } + if (vc->gfx.esurface) { + eglDestroyContext(qemu_egl_display, vc->gfx.ectx); + vc->gfx.ectx = NULL; + } +#endif + gd_widget_reparent(s->notebook, vc->window, vc->tab_item); + + g_signal_connect(vc->window, "delete-event", + G_CALLBACK(gd_tab_window_close), vc); + gtk_widget_show_all(vc->window); + + if (qemu_console_is_graphic(vc->gfx.dcl.con)) { + GtkAccelGroup *ag = gtk_accel_group_new(); + gtk_window_add_accel_group(GTK_WINDOW(vc->window), ag); + + GClosure *cb = g_cclosure_new_swap(G_CALLBACK(gd_win_grab), + vc, NULL); + gtk_accel_group_connect(ag, GDK_KEY_g, HOTKEY_MODIFIERS, 0, cb); + } + + gd_update_geometry_hints(vc); + gd_update_caption(s); +} + static void gd_menu_untabify(GtkMenuItem *item, void *opaque) { GtkDisplayState *s = opaque; @@ -1411,35 +1446,7 @@ static void gd_menu_untabify(GtkMenuItem *item, void *opaque) FALSE); } if (!vc->window) { - gtk_widget_set_sensitive(vc->menu_item, false); - vc->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); -#if defined(CONFIG_OPENGL) - if (vc->gfx.esurface) { - eglDestroySurface(qemu_egl_display, vc->gfx.esurface); - vc->gfx.esurface = NULL; - } - if (vc->gfx.esurface) { - eglDestroyContext(qemu_egl_display, vc->gfx.ectx); - vc->gfx.ectx = NULL; - } -#endif - gd_widget_reparent(s->notebook, vc->window, vc->tab_item); - - g_signal_connect(vc->window, "delete-event", - G_CALLBACK(gd_tab_window_close), vc); - gtk_widget_show_all(vc->window); - - if (qemu_console_is_graphic(vc->gfx.dcl.con)) { - GtkAccelGroup *ag = gtk_accel_group_new(); - gtk_window_add_accel_group(GTK_WINDOW(vc->window), ag); - - GClosure *cb = g_cclosure_new_swap(G_CALLBACK(gd_win_grab), - vc, NULL); - gtk_accel_group_connect(ag, GDK_KEY_g, HOTKEY_MODIFIERS, 0, cb); - } - - gd_update_geometry_hints(vc); - gd_update_caption(s); + gd_tab_window_create(vc); } } From patchwork Fri Nov 18 01:44:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Kasireddy, Vivek" X-Patchwork-Id: 13047644 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9AD2FC433FE for ; Fri, 18 Nov 2022 02:06:25 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ovqkr-0007t9-D0; Thu, 17 Nov 2022 21:05:21 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkp-0007sG-Ru for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:19 -0500 Received: from mga18.intel.com ([134.134.136.126]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ovqkn-0008UX-Bv for qemu-devel@nongnu.org; Thu, 17 Nov 2022 21:05:19 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1668737117; x=1700273117; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=5V55llVN3tmjBUlqhrT2ZTUetXSq55cgYaFxBSP/MvQ=; b=e/GUDN/oqluXjwg2sPuxOscn7KijhboPXKJ3Y5n3hre6xHzWRSG6nCq0 RWAzfvOPaNZbKYrsaBCCnhXQhhT8nWY2NJlhr2vUA6VM17hal4KRsWiP/ few3tBUalbSQpOw93kN67OR1nTlXig++T/MaTyzIH+OimsXRG2ZdD62kK lceHBgv9loUYJf5kkrf+H6dNZWY03dsckq5UgMGtM1QQdPRRPdACG5PJD uTFRIBEDKLMKWvgYeyEvvmlBt2VcQp5X14aFyXpBk3w1kN4XWZa4Teenv xA8/gyW7vguMdwVHVqGG7qz/JGjcJYZqq0xy5NwMRgex/71c8wIzPMqKp w==; X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="296393531" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="296393531" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:06 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10534"; a="634270872" X-IronPort-AV: E=Sophos;i="5.96,172,1665471600"; d="scan'208";a="634270872" Received: from vkasired-desk2.fm.intel.com ([10.105.128.127]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Nov 2022 18:05:05 -0800 From: Vivek Kasireddy To: qemu-devel@nongnu.org Cc: Vivek Kasireddy , Dongwon Kim , Gerd Hoffmann , Markus Armbruster , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= Subject: [PATCH v2 6/6] ui/gtk: Add a new parameter to assign connectors/monitors to GFX VCs (v2) Date: Thu, 17 Nov 2022 17:44:26 -0800 Message-Id: <20221118014426.182599-7-vivek.kasireddy@intel.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221118014426.182599-1-vivek.kasireddy@intel.com> References: <20221118014426.182599-1-vivek.kasireddy@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.126; envelope-from=vivek.kasireddy@intel.com; helo=mga18.intel.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The new parameter named "connector" can be used to assign physical monitors/connectors to individual GFX VCs such that when the monitor is connected or hotplugged, the associated GTK window would be moved to it. If the monitor is disconnected or unplugged, the associated GTK window would be destroyed and a relevant disconnect event would be sent to the Guest. Usage: -device virtio-gpu-pci,max_outputs=2,blob=true,... -display gtk,gl=on,connectors.0=eDP-1,connectors.1=DP-1..... v2: - Make various style improvements suggested by Markus. - Fullscreen the window only if the fullscreen option is enabled. Cc: Dongwon Kim Cc: Gerd Hoffmann Cc: Markus Armbruster Cc: Marc-André Lureau Acked-by: Markus Armbruster (QAPI schema) Signed-off-by: Vivek Kasireddy --- include/ui/gtk.h | 1 + qapi/ui.json | 10 +- qemu-options.hx | 5 +- ui/gtk.c | 260 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 268 insertions(+), 8 deletions(-) diff --git a/include/ui/gtk.h b/include/ui/gtk.h index f8df042f95..bbea0316fb 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -83,6 +83,7 @@ typedef struct VirtualConsole { GtkWidget *menu_item; GtkWidget *tab_item; GtkWidget *focus; + GdkMonitor *monitor; VirtualConsoleType type; union { VirtualGfxConsole gfx; diff --git a/qapi/ui.json b/qapi/ui.json index 0abba3e930..a4d1616445 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1201,6 +1201,13 @@ # Since 7.1 # @show-menubar: Display the main window menubar. Defaults to "on". # Since 8.0 +# @connectors: List of physical monitor/connector names where the GTK +# windows containing the respective graphics virtual consoles +# (VCs) are to be placed. If a mapping exists for a VC, it +# will be moved to that specific monitor or else it would +# not be displayed anywhere and would appear disconnected +# to the guest. +# Since 8.0 # # Since: 2.12 ## @@ -1208,7 +1215,8 @@ 'data' : { '*grab-on-hover' : 'bool', '*zoom-to-fit' : 'bool', '*show-tabs' : 'bool', - '*show-menubar' : 'bool' } } + '*show-menubar' : 'bool', + '*connectors' : ['str'] } } ## # @DisplayEGLHeadless: diff --git a/qemu-options.hx b/qemu-options.hx index eb38e5dc40..ae6289e4f3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1980,7 +1980,7 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, #if defined(CONFIG_GTK) "-display gtk[,full-screen=on|off][,gl=on|off][,grab-on-hover=on|off]\n" " [,show-tabs=on|off][,show-cursor=on|off][,window-close=on|off]\n" - " [,show-menubar=on|off]\n" + " [,show-menubar=on|off][,connectors.=]\n" #endif #if defined(CONFIG_VNC) "-display vnc=[,]\n" @@ -2075,6 +2075,9 @@ SRST ``show-menubar=on|off`` : Display the main window menubar, defaults to "on" + ``connectors=`` : VC to connector mappings to display the VC + window on a specific monitor + ``curses[,charset=]`` Display video output via curses. For graphics device models which support a text mode, QEMU can display this output using a diff --git a/ui/gtk.c b/ui/gtk.c index 6b0369e3ed..03fc454a1f 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -37,6 +37,7 @@ #include "qapi/qapi-commands-misc.h" #include "qemu/cutils.h" #include "qemu/main-loop.h" +#include "qemu/option.h" #include "ui/console.h" #include "ui/gtk.h" @@ -116,6 +117,11 @@ #define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK) +/* Upper limit on number of times to check for a valid monitor name */ +#define MAX_NUM_RETRIES 5 +/* Max num of milliseconds to wait before checking for a valid monitor name */ +#define WAIT_MS 50 + static const guint16 *keycode_map; static size_t keycode_maplen; @@ -126,6 +132,14 @@ struct VCChardev { }; typedef struct VCChardev VCChardev; +typedef struct gd_monitor_data { + GtkDisplayState *s; + GdkDisplay *dpy; + GdkMonitor *monitor; + QEMUTimer *hp_timer; + int num_retries; +} gd_monitor_data; + #define TYPE_CHARDEV_VC "chardev-vc" DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV, TYPE_CHARDEV_VC) @@ -461,7 +475,7 @@ static void gd_mouse_set(DisplayChangeListener *dcl, * and return right away as we do not want to move the cursor * back to the old vc (at 0, 0). */ - if (GDK_IS_WAYLAND_DISPLAY(dpy)) { + if (GDK_IS_WAYLAND_DISPLAY(dpy) || s->opts->u.gtk.has_connectors) { if (s->ptr_owner != vc || (x == 0 && y == 0)) { return; } @@ -962,11 +976,11 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, s->last_set = TRUE; /* - * When running in Wayland environment, we don't grab the cursor; so, - * we want to return right away as it would not make sense to warp it - * (below). + * When running in Wayland environment or when has_connectors is set, + * we don't grab the cursor; so, we want to return right away as it + * would not make sense to warp it (below). */ - if (GDK_IS_WAYLAND_DISPLAY(dpy)) { + if (GDK_IS_WAYLAND_DISPLAY(dpy) || s->opts->u.gtk.has_connectors) { if (s->ptr_owner != vc) { s->ptr_owner = vc; } @@ -1017,10 +1031,13 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, /* Implicitly grab the input at the first click in the relative mode. * However, when running in Wayland environment, some limited testing * indicates that grabs are not very reliable. + * And, when has_connectors is set, we also do not want to grab the cursor + * as it would be tedious to grab/ungrab when drag-and-dropping or moving + * apps from one vc to another -- which may be on a different monitor. */ if (button->button == 1 && button->type == GDK_BUTTON_PRESS && !qemu_input_is_absolute() && s->ptr_owner != vc && - !GDK_IS_WAYLAND_DISPLAY(dpy)) { + !GDK_IS_WAYLAND_DISPLAY(dpy) && !s->opts->u.gtk.has_connectors) { if (!vc->window) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE); @@ -1450,6 +1467,228 @@ static void gd_menu_untabify(GtkMenuItem *item, void *opaque) } } +static void gd_window_show_on_monitor(GdkDisplay *dpy, VirtualConsole *vc, + gint monitor_num) +{ + GtkDisplayState *s = vc->s; + GdkMonitor *monitor = gdk_display_get_monitor(dpy, monitor_num); + GdkWindow *window; + GdkRectangle geometry; + + if (!vc->window) { + gd_tab_window_create(vc); + } + if (s->opts->has_full_screen && s->opts->full_screen) { + s->full_screen = TRUE; + gtk_widget_set_size_request(vc->gfx.drawing_area, -1, -1); + gtk_window_fullscreen_on_monitor(GTK_WINDOW(vc->window), + gdk_display_get_default_screen(dpy), + monitor_num); + } else { + gd_update_windowsize(vc); + gdk_monitor_get_geometry(monitor, &geometry); + /* + * Note: some compositors (mainly Wayland ones) may not honor a + * request to move to a particular location. The user is expected + * to drag the window to the preferred location in this case. + */ + gtk_window_move(GTK_WINDOW(vc->window), geometry.x, geometry.y); + } + + vc->monitor = monitor; + window = gtk_widget_get_window(vc->gfx.drawing_area); + gd_set_ui_size(vc, gdk_window_get_width(window), + gdk_window_get_height(window)); + gd_update_cursor(vc); +} + +static int gd_monitor_lookup(GdkDisplay *dpy, char *label) +{ + GdkMonitor *monitor; + int total_monitors = gdk_display_get_n_monitors(dpy); + int i; + + for (i = 0; i < total_monitors; i++) { + monitor = gdk_display_get_monitor(dpy, i); + if (monitor && !g_strcmp0(gdk_monitor_get_model(monitor), label)) { + return i; + } + } + return -1; +} + +static gboolean gd_vc_is_misplaced(GdkDisplay *dpy, GdkMonitor *monitor, + VirtualConsole *vc) +{ + GdkWindow *window = gtk_widget_get_window(vc->gfx.drawing_area); + GdkMonitor *mon = gdk_display_get_monitor_at_window(dpy, window); + const char *monitor_name = gdk_monitor_get_model(monitor); + + if (!vc->monitor) { + if (!g_strcmp0(monitor_name, vc->label)) { + return TRUE; + } + } else { + if (vc->monitor != mon) { + return TRUE; + } + } + return FALSE; +} + +static void gd_monitor_check_vcs(GdkDisplay *dpy, GdkMonitor *monitor, + GtkDisplayState *s) +{ + VirtualConsole *vc; + gint monitor_num; + int i; + + /* + * We need to call gd_vc_is_misplaced() after a monitor is added to + * ensure that the Host compositor has not moved our windows around. + */ + for (i = 0; i < s->nb_vcs; i++) { + vc = &s->vc[i]; + monitor_num = vc->label ? gd_monitor_lookup(dpy, vc->label) : -1; + if (monitor_num >= 0 && gd_vc_is_misplaced(dpy, monitor, vc)) { + gd_window_show_on_monitor(dpy, vc, monitor_num); + } + } +} + +static void gd_monitor_hotplug_timer(void *opaque) +{ + gd_monitor_data *data = opaque; + const char *monitor_name; + + monitor_name = GDK_IS_MONITOR(data->monitor) ? + gdk_monitor_get_model(data->monitor) : NULL; + if (monitor_name) { + gd_monitor_check_vcs(data->dpy, data->monitor, data->s); + } + if (monitor_name || data->num_retries == MAX_NUM_RETRIES) { + timer_del(data->hp_timer); + g_free(data); + } else { + data->num_retries++; + timer_mod(data->hp_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + WAIT_MS); + } +} + +static void gd_monitor_add(GdkDisplay *dpy, GdkMonitor *monitor, + void *opaque) +{ + GtkDisplayState *s = opaque; + gd_monitor_data *data; + + /* + * It is possible that the Host Compositor or GTK would not have + * had a chance to fully process the hotplug event and as a result + * gdk_monitor_get_model() could return NULL. Therefore, check for + * this case and try again later. + */ + if (GDK_IS_MONITOR(monitor) && gdk_monitor_get_model(monitor)) { + gd_monitor_check_vcs(dpy, monitor, s); + } else { + data = g_new0(gd_monitor_data, 1); + data->s = s; + data->dpy = dpy; + data->monitor = monitor; + data->hp_timer = timer_new_ms(QEMU_CLOCK_REALTIME, + gd_monitor_hotplug_timer, data); + timer_mod(data->hp_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + WAIT_MS); + } +} + +static void gd_monitor_remove(GdkDisplay *dpy, GdkMonitor *monitor, + void *opaque) +{ + GtkDisplayState *s = opaque; + VirtualConsole *vc; + int i; + + for (i = 0; i < s->nb_vcs; i++) { + vc = &s->vc[i]; + if (vc->monitor == monitor) { + vc->monitor = NULL; + if (vc->window == s->window) { + gdk_window_hide(gtk_widget_get_window(vc->window)); + } else { + gd_tab_window_close(NULL, NULL, vc); + } + gd_set_ui_size(vc, 0, 0); + break; + } + } +} + +static VirtualConsole *gd_next_gfx_vc(GtkDisplayState *s) +{ + VirtualConsole *vc; + int i; + + for (i = 0; i < s->nb_vcs; i++) { + vc = &s->vc[i]; + if (vc->type == GD_VC_GFX && + qemu_console_is_graphic(vc->gfx.dcl.con) && + !vc->label) { + return vc; + } + } + return NULL; +} + +static void gd_vc_free_labels(GtkDisplayState *s) +{ + VirtualConsole *vc; + int i; + + for (i = 0; i < s->nb_vcs; i++) { + vc = &s->vc[i]; + if (vc->type == GD_VC_GFX && + qemu_console_is_graphic(vc->gfx.dcl.con)) { + g_free(vc->label); + vc->label = NULL; + } + } +} + +static void gd_connectors_init(GdkDisplay *dpy, GtkDisplayState *s) +{ + VirtualConsole *vc; + strList *conn; + gint monitor_num; + gboolean first_vc = TRUE; + + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), + FALSE); + gd_vc_free_labels(s); + for (conn = s->opts->u.gtk.connectors; conn; conn = conn->next) { + vc = gd_next_gfx_vc(s); + if (!vc) { + break; + } + if (first_vc) { + vc->window = s->window; + first_vc = FALSE; + } + + vc->label = g_strdup(conn->value); + monitor_num = gd_monitor_lookup(dpy, vc->label); + if (monitor_num >= 0) { + gd_window_show_on_monitor(dpy, vc, monitor_num); + } else { + if (vc->window) { + gdk_window_hide(gtk_widget_get_window(vc->window)); + } + gd_set_ui_size(vc, 0, 0); + } + } +} + static void gd_menu_show_menubar(GtkMenuItem *item, void *opaque) { GtkDisplayState *s = opaque; @@ -2103,6 +2342,12 @@ static void gd_connect_signals(GtkDisplayState *s) G_CALLBACK(gd_menu_grab_input), s); g_signal_connect(s->notebook, "switch-page", G_CALLBACK(gd_change_page), s); + if (s->opts->u.gtk.has_connectors) { + g_signal_connect(gtk_widget_get_display(s->window), "monitor-added", + G_CALLBACK(gd_monitor_add), s); + g_signal_connect(gtk_widget_get_display(s->window), "monitor-removed", + G_CALLBACK(gd_monitor_remove), s); + } } static GtkWidget *gd_create_menu_machine(GtkDisplayState *s) @@ -2472,6 +2717,9 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) opts->u.gtk.show_tabs) { gtk_menu_item_activate(GTK_MENU_ITEM(s->show_tabs_item)); } + if (s->opts->u.gtk.has_connectors) { + gd_connectors_init(window_display, s); + } gd_clipboard_init(s); }