From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Daniel Colascione Newsgroups: gmane.emacs.devel Subject: [PATCH] Make browser windows pop up when browsing URLs on Wayland Date: Mon, 23 Dec 2024 14:23:14 -0500 Message-ID: <20241223192320.39021-1-dancol@dancol.org> Mime-Version: 1.0 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="7660"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Daniel Colascione To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Dec 23 20:24:34 2024 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1tPo2b-0001oP-51 for ged-emacs-devel@m.gmane-mx.org; Mon, 23 Dec 2024 20:24:33 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tPo1m-0005Ka-Kg; Mon, 23 Dec 2024 14:23:43 -0500 Original-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 1tPo1k-0005KG-C4 for emacs-devel@gnu.org; Mon, 23 Dec 2024 14:23:41 -0500 Original-Received: from dancol.org ([2600:3c01:e000:3d8::1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tPo1h-0002E1-Cp for emacs-devel@gnu.org; Mon, 23 Dec 2024 14:23:39 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=dancol.org; s=x; h=Content-Transfer-Encoding:MIME-Version:Message-ID:Date:Subject:Cc:To: From:Sender:Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post: List-Owner:List-Archive; bh=8TnF6aZz01mFdFX69VmLVMmX5rbpOJg977XDvx0SAiw=; b=C HquE0kaJ0n0SDlsCT+eRHAPsAQiCHUDItWHVPl8CAfP83gmBf6pgCZlt1I/H5ejv2Er9YJuHij6KR 974bvjIIwoEieQfox4DYEn7hlXEVumPj2OqLzIGOYbyjKwhJLivfEk58Z0kKE8dD0iqm/Lbk58Q9u r2c9+pUfD1wZ0qMLWqy0UG+Hp/VkjRq7d+x6ERlOqQAOp1/QaYI8F5YO+ykxyMEyawCpvwPGWB+FW nbRopdEHUdvG0VxaMNbzlycT7zhEWP7QqkpD5phD9xI5mcvsoFH9URyfDFr+grP/2hy9QsLK7ATiH c552vlxUN6bmATviPytylslG4LI6BuLpw==; Original-Received: from [2600:1006:b16d:bc2d:b104:97a9:aea2:dfb4] (port=49342 helo=localhost) by dancol.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1tPo1d-00051N-0z; Mon, 23 Dec 2024 14:23:33 -0500 X-Mailer: git-send-email 2.45.2 Received-SPF: pass client-ip=2600:3c01:e000:3d8::1; envelope-from=dancol@dancol.org; helo=dancol.org 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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:326931 Archived-At: When a user invokes browse-url, the browser window viewing the URL should be raised in the user's desktop environment. On X11, running xdg-open as a subprocess does the job. However, on Wayland, this approach doesn't work: xdg-open makes the web browser browse a URL all right, but doesn't raise the browser window in the GUI. Therefore, if the browser window is behind Emacs, browse-url appears to do nothing. Repeated invocations of browse-url cause the browser to load multiple tabs in the background, surprising the user when he gives up in frustration and manually switches to the browser window. There's no subprocess we can run to make the right thing happen. Wayland requires that we pass along event activation information to the browser using the xdg_activation_v1 protocol. This change adds x-gtk-launch-uri to invoke GTK-native URL-dispatch machinery. This machinery DTRT on both X11 and Wayland. We fall back to the default browser machinery if we're not on a GTK frame. The logic is more complicated than it has to be because the GTK URI launch mechanism requires that we launch with respect to a specific GTK window, and in some environments (e.g., running emacs -nw in a PGTK Emacs) we don't have a GTK window. We also want to preserve the effect of customizing browse-url-browser-function, so adding an entry to browse-url-default-handlers that preempts URI open when we happen to be on a GTK frame is the wrong thing to do. We really should consider simplifying the whole browse-url mechanism by eliminating browse-url-default-browser and the distinction between browse-url-handlers and browse-url-default-handlers. Instead, browse-url-handlers should have a simple list of predicated handlers just like display-buffer-alist. * lisp/net/browse-url.el (browse-url--browser-defcustom-type): (browse-url--inhibit-pgtk): avoid infinite recursion (browse-url-default-browser): use pgtk launch (x-gtk-launch-uri): new function (browse-url-default-gtk-browser): ues it * src/pgtkfns.c (unwind_gerror_ptr): new function (Fx_gtk_launch_uri): new function (syms_of_pgtkfns): register it --- lisp/net/browse-url.el | 25 +++++++++++++++++++++++++ src/pgtkfns.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index 9dd990108df..e5b7fc7ba6d 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el @@ -179,6 +179,9 @@ browse-url--browser-defcustom-type ,@(when (eq system-type 'android) (list '(function-item :tag "Default Android browser" :value browse-url-default-android-browser))) + ,@(when (eq window-system 'pgtk) + (list '(function-item :tag "Default GTK browser" + :value browse-url-default-gtk-browser))) (function-item :tag "Default browser" :value browse-url-default-browser) (function :tag "Your own function") @@ -1097,6 +1100,8 @@ browse-url-emacs-display (and (not (equal display (getenv "DISPLAY"))) display))) +(defvar browse-url--inhibit-pgtk nil) + (defun browse-url-default-browser (url &rest args) "Find a suitable browser and ask it to load URL. Default to the URL around or before point. @@ -1118,6 +1123,9 @@ browse-url-default-browser 'browse-url-default-haiku-browser) ((eq system-type 'android) 'browse-url-default-android-browser) + ((and (eq (frame-parameter nil 'window-system) 'pgtk) + (not browse-url--inhibit-pgtk)) + 'browse-url-default-gtk-browser) ((browse-url-can-use-xdg-open) 'browse-url-xdg-open) ;;; ((executable-find browse-url-gnome-moz-program) 'browse-url-gnome-moz) ((executable-find browse-url-firefox-program) 'browse-url-firefox) @@ -1438,6 +1446,23 @@ browse-url-default-android-browser (function-put 'browse-url-default-android-browser 'browse-url-browser-kind 'external) +(declare-function x-gtk-launch-uri "pgtkfns.c") + +;;;###autoload +(defun browse-url-default-gtk-browser (url &optional new-window) + "Browse URL with GTK's idea of the default browser. +If the selected frame isn't a GTK frame, fall back to +`browse-url-default-browser'." + (interactive (browse-url-interactive-arg "URL: ")) + (let ((frame (selected-frame))) + (if (eq (frame-parameter frame 'window-system) 'pgtk) + (x-gtk-launch-uri frame url) + (let ((browse-url--inhibit-pgtk t)) + (browse-url-default-browser url new-window))))) + +(function-put 'browse-url-default-gtk-browser + 'browse-url-browser-kind 'external) + ;;;###autoload (defun browse-url-emacs (url &optional same-window) "Ask Emacs to load URL into a buffer and show it in another window. diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 0ff3262cd11..1c2b8985ee8 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -3819,6 +3819,44 @@ DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0, return NILP (enable) ? Qnil : Qt; } +static void +unwind_gerror_ptr (void* data) +{ + GError* error = *(GError**)data; + if (error) + g_error_free (error); +} + +DEFUN ("x-gtk-launch-uri", Fx_gtk_launch_uri, Sx_gtk_launch_uri, 2, 2, 0, + doc: /* launch URI */) + (Lisp_Object frame, Lisp_Object uri) +{ + CHECK_FRAME (frame); + + if (!FRAME_LIVE_P (XFRAME (frame)) || + !FRAME_PGTK_P (XFRAME (frame)) || + !FRAME_GTK_OUTER_WIDGET (XFRAME (frame))) + error ("GTK URI launch not available for this frame"); + + CHECK_STRING (uri); + guint32 timestamp = gtk_get_current_event_time (); + + GError *err = NULL; + specpdl_ref count = SPECPDL_INDEX (); + + record_unwind_protect_ptr (unwind_gerror_ptr, &err); + + gtk_show_uri_on_window (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (XFRAME (frame))), + SSDATA (uri), + timestamp, + &err); + + if (err) + error ("Failed to launch URI via GTK: %s", err->message); + + return unbind_to (count, Qnil); +} + void syms_of_pgtkfns (void) { @@ -3890,6 +3928,7 @@ syms_of_pgtkfns (void) defsubr (&Sx_close_connection); defsubr (&Sx_display_list); defsubr (&Sx_gtk_debug); + defsubr (&Sx_gtk_launch_uri); defsubr (&Sx_show_tip); defsubr (&Sx_hide_tip); -- 2.45.2