From nobody Mon May 25 20:31:53 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1778311965; cv=none; d=zohomail.com; s=zohoarc; b=dlN7ljKNNRkIhrRXgi379szXQlcHv7UIqKGFp12ys1Irf3ocTokjan0fm99bJ8ctt4tXKBPqBTWYAbqo/7B0GjlnF8IFeFnNn6OOCd0+8/Kny/b+MEl0YIVONoNyq8x8oPfq6TiizbYK5j3L3PevShyaMr+KotBUzzIQnNC8eDI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778311965; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:Sender:Subject:Subject:To:To:Message-Id; bh=8Bg2CJHy10HiG46AKL6I1j3u1VDHtACZpqO97S06QhU=; b=G1NvePfXjTLcH17bltuxz2X0gk03zoF/Z9jofdXD64A+PXOQA6kg9CObyzljYLVdP650tSgh06EzdxjH14bNVr6luuNXRxGWW9XG/p2SmF4IS3sd/aVz8YfamUU0tN9duKsdF2RhKMmhYU8ptkTKqkm5bJ0qDBrr1eoR3asuws0= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 177831196582898.1241515381073; Sat, 9 May 2026 00:32:45 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wLcAO-0003Di-1C; Sat, 09 May 2026 03:32:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wLXoJ-00010q-53 for qemu-devel@nongnu.org; Fri, 08 May 2026 22:52:59 -0400 Received: from outboundhk.mxmail.xiaomi.com ([118.143.206.90]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wLXoF-0004yF-P9 for qemu-devel@nongnu.org; Fri, 08 May 2026 22:52:58 -0400 X-CSE-ConnectionGUID: /5UvtCYhSMyHQ71IUhhalQ== X-CSE-MsgGUID: sKRhidHvQvyM4s85ObKsIQ== X-IronPort-AV: E=Sophos;i="6.23,224,1770566400"; d="scan'208";a="149009391" To: "qemu-devel@nongnu.org" CC: "marcandre.lureau@redhat.com" Subject: [RFC PATCH] ui/sdl2: replace SDL relative mouse mode with manual warp-to-center Thread-Topic: [RFC PATCH] ui/sdl2: replace SDL relative mouse mode with manual warp-to-center Thread-Index: AQHc312vI6jO0+xB3EWc01YoWuwmCQ== Date: Sat, 9 May 2026 02:52:44 +0000 Message-ID: <3d86e8cfc12040eca14364739b0a35db@xiaomi.com> Accept-Language: zh-CN, en-US Content-Language: zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.237.88.13] Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=118.143.206.90; envelope-from=liuhongchao@xiaomi.com; helo=outboundhk.mxmail.xiaomi.com X-Spam_score_int: 38 X-Spam_score: 3.8 X-Spam_bar: +++ X-Spam_report: (3.8 / 5.0 requ) BAYES_00=-1.9, CHARSET_FARAWAY_HEADER=3.2, MIME_CHARSET_FARAWAY=2.45, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Sat, 09 May 2026 03:32:03 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: =?gb2312?B?wfW66bOs?= From: =?gb2312?B?wfW66bOs?= via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1778311969628158500 Content-Type: text/plain; charset="utf-8" Hi all, This is an RFC because the change touches the defaults for relative pointer handling in the SDL2 UI backend; I would like feedback on the overall direction before posting a non-RFC version. Motivation ---------- SDL_SetRelativeMouseMode(SDL_TRUE), which ui/sdl2.c currently enables on the grab paths via sdl_hide_cursor(), switches SDL on X11/XInput2 to consume only XI_RawMotion events. X servers that can only inject MotionNotify (VNC via XTestFakeMotionEvent, nested X sessions, some remote desktop setups) therefore never deliver input to the guest once it enters a relative-pointer grab. We hit this in practice when running qemu-system-arm with the SDL display forwarded through VNC for remote development. The environments can't be distinguished at runtime: both local X11 and a VNC-forwarded X session report "x11" from SDL_GetCurrentVideoDriver(). Upstream SDL issues about this (libsdl-org/SDL#1116, #4206) have been open for years with no fix in sight. The GTK backend in QEMU already side-steps the problem by doing manual warp-to-center in gd_motion_event (ui/gtk.c); this patch applies the same pattern to the SDL2 backend. What the patch does ------------------- 1. Stop calling sdl_hide_cursor() from sdl_grab_start() and sdl_mouse_warp(): both paths now open-code the cursor hide so we never enter SDL_SetRelativeMouseMode(SDL_TRUE). sdl_hide_cursor() is retained as the counterpart of sdl_show_cursor() and marked G_GNUC_UNUSED. 2. handle_mousemotion(): for relative pointing devices in grab mode, detect the host pointer at the window edge and SDL_WarpMouseInWindow() it back to the window center, mirroring ui/gtk.c:gd_motion_event. Edge detection uses window coordinates (ev->motion.x/y vs scr_w/h) independently of the window-to-surface scaling introduced for the sent event. 3. Absolute pointing devices and absolute_enabled paths are untouched. Why one commit -------------- Splitting "open-code the cursor hide" from "add edge-warp" is possible but (1) alone would immediately regress to "host pointer stuck at window edge" under relative grab, because SDL_SetWindowGrab by itself has no wraparound. They are semantically one change, so it is posted as a single patch. Points I would especially like feedback on ------------------------------------------ 1. Keeping sdl_hide_cursor() around with G_GNUC_UNUSED vs just deleting it. I kept it for symmetry with sdl_show_cursor() and so the XI2 rationale has an obvious place to live; I have no strong preference. 2. Whether the edge-detection threshold (<=3D 0, >=3D size - 1) is agreeable given SDL_SetWindowGrab clamping semantics. 3. Any concerns about the default-behavior change for local-X11 users. In my testing, local-X11 behavior is equivalent: the host pointer just gets warped by a different code path, while xrel/yrel delivered to the guest are unchanged. Tested on --------- - Linux/X11 (local Xorg), SDL2 2.30.x, qemu-system-arm with a relative virtio-mouse: pointer is no longer stuck at the window edge in grab mode; release after quick drag delivers correctly; absolute (virtio-tablet) path unchanged. - Same host reached via VNC: no regression; mouse input stays functional inside grab (this is the scenario that motivated the change). Not tested: macOS Cocoa, Windows, Wayland-only setups. The change does not rely on XI2 specifics so behavior there should at most match the previous SDL_SetRelativeMouseMode path, but feedback from anyone with those hosts would be very welcome. Thanks, liuhongchao --- ui/sdl2.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/ui/sdl2.c b/ui/sdl2.c index 5dd612d9a6..faf610281c 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -212,7 +212,19 @@ static void sdl_update_caption(struct sdl2_console *sc= on) } } -static void sdl_hide_cursor(struct sdl2_console *scon) +/* + * sdl_hide_cursor - hide cursor and optionally enable SDL relative mouse = mode. + * + * NOTE: This function is intentionally NOT called from sdl_grab_start() or + * sdl_mouse_warp() because SDL_SetRelativeMouseMode(SDL_TRUE) switches SD= L2 + * on XI2-based X servers to consume only XI_RawMotion events. Pointer- + * injection servers (VNC via XTestFakeMotionEvent, nested X, some remote + * desktop setups) never produce XI_RawMotion, so mouse input would break + * under those servers. Those call sites set the cursor state inline + * instead. This function is retained as the counterpart of + * sdl_show_cursor() and for potential future use. + */ +static void G_GNUC_UNUSED sdl_hide_cursor(struct sdl2_console *scon) { if (scon->opts->has_show_cursor && scon->opts->show_cursor) { return; @@ -267,7 +279,16 @@ static void sdl_grab_start(struct sdl2_console *scon) SDL_WarpMouseInWindow(scon->real_window, guest_x, guest_y); } } else { - sdl_hide_cursor(scon); + /* + * Directly set cursor state, avoid calling sdl_hide_cursor + * which would enable SDL_SetRelativeMouseMode(SDL_TRUE) and + * break mouse input under XI2-based pointer-injection X servers + * (see the note on sdl_hide_cursor). + */ + if (!(scon->opts->has_show_cursor && scon->opts->show_cursor)) { + SDL_ShowCursor(SDL_DISABLE); + SDL_SetCursor(sdl_cursor_hidden); + } } SDL_SetWindowGrab(scon->real_window, SDL_TRUE); gui_grab =3D 1; @@ -526,6 +547,34 @@ static void handle_mousemotion(SDL_Event *ev) dy =3D (int64_t)ev->motion.yrel * surf_h / scr_h; if (gui_grab || qemu_input_is_absolute(scon->dcl.con) || absolute_enab= led) { sdl_send_mouse_event(scon, dx, dy, x, y, ev->motion.state); + + /* + * For relative pointing devices in grab mode we do not enable + * SDL_SetRelativeMouseMode, because under XI2-based X servers + * that switches SDL to consume only XI_RawMotion events, which + * some pointer-injection servers (VNC via XTestFakeMotionEvent, + * nested X, ...) never produce. + * + * Without relative mode, SDL_SetWindowGrab clamps the host + * pointer at the window edge without wrapping, so xrel/yrel + * become zero once the pointer hits a side and the guest + * cursor gets stuck in that direction. + * + * Mirror the approach used by the GTK backend (ui/gtk.c): + * when the pointer reaches any window edge, warp it back to + * the window center so subsequent motion can generate deltas + * in every direction again. Edge detection uses window + * coordinates (ev->motion.x/y, scr_w/h) regardless of the + * window-to-surface scaling applied above. + */ + if (!qemu_input_is_absolute(scon->dcl.con) && !absolute_enabled + && gui_grab) { + if (ev->motion.x <=3D 0 || ev->motion.x >=3D scr_w - 1 || + ev->motion.y <=3D 0 || ev->motion.y >=3D scr_h - 1) { + SDL_WarpMouseInWindow(scon->real_window, + scr_w / 2, scr_h / 2); + } + } } } @@ -748,7 +797,16 @@ static void sdl_mouse_warp(DisplayChangeListener *dcl, } } } else if (gui_grab) { - sdl_hide_cursor(scon); + /* + * Directly set cursor state, avoid calling sdl_hide_cursor + * which would enable SDL_SetRelativeMouseMode(SDL_TRUE) and + * break mouse input under XI2-based pointer-injection X servers + * (see the note on sdl_hide_cursor). + */ + if (!(scon->opts->has_show_cursor && scon->opts->show_cursor)) { + SDL_ShowCursor(SDL_DISABLE); + SDL_SetCursor(sdl_cursor_hidden); + } } guest_cursor =3D on; guest_x =3D x, guest_y =3D y; -- 2.34.1 #/******=E6=9C=AC=E9=82=AE=E4=BB=B6=E5=8F=8A=E5=85=B6=E9=99=84=E4=BB=B6=E5= =90=AB=E6=9C=89=E5=B0=8F=E7=B1=B3=E5=85=AC=E5=8F=B8=E7=9A=84=E4=BF=9D=E5=AF= =86=E4=BF=A1=E6=81=AF=EF=BC=8C=E4=BB=85=E9=99=90=E4=BA=8E=E5=8F=91=E9=80=81= =E7=BB=99=E4=B8=8A=E9=9D=A2=E5=9C=B0=E5=9D=80=E4=B8=AD=E5=88=97=E5=87=BA=E7= =9A=84=E4=B8=AA=E4=BA=BA=E6=88=96=E7=BE=A4=E7=BB=84=E3=80=82=E7=A6=81=E6=AD= =A2=E4=BB=BB=E4=BD=95=E5=85=B6=E4=BB=96=E4=BA=BA=E4=BB=A5=E4=BB=BB=E4=BD=95= =E5=BD=A2=E5=BC=8F=E4=BD=BF=E7=94=A8=EF=BC=88=E5=8C=85=E6=8B=AC=E4=BD=86=E4= =B8=8D=E9=99=90=E4=BA=8E=E5=85=A8=E9=83=A8=E6=88=96=E9=83=A8=E5=88=86=E5=9C= =B0=E6=B3=84=E9=9C=B2=E3=80=81=E5=A4=8D=E5=88=B6=E3=80=81=E6=88=96=E6=95=A3= =E5=8F=91=EF=BC=89=E6=9C=AC=E9=82=AE=E4=BB=B6=E4=B8=AD=E7=9A=84=E4=BF=A1=E6= =81=AF=E3=80=82=E5=A6=82=E6=9E=9C=E6=82=A8=E9=94=99=E6=94=B6=E4=BA=86=E6=9C= =AC=E9=82=AE=E4=BB=B6=EF=BC=8C=E8=AF=B7=E6=82=A8=E7=AB=8B=E5=8D=B3=E7=94=B5= =E8=AF=9D=E6=88=96=E9=82=AE=E4=BB=B6=E9=80=9A=E7=9F=A5=E5=8F=91=E4=BB=B6=E4= =BA=BA=E5=B9=B6=E5=88=A0=E9=99=A4=E6=9C=AC=E9=82=AE=E4=BB=B6=EF=BC=81 This = e-mail and its attachments contain confidential information from XIAOMI, wh= ich is intended only for the person or entity whose address is listed above= . Any use of the information contained herein in any way (including, but no= t limited to, total or partial disclosure, reproduction, or dissemination) = by persons other than the intended recipient(s) is prohibited. If you recei= ve this e-mail in error, please notify the sender by phone or email immedia= tely and delete it!******/#