]> git.eshelyaron.com Git - emacs.git/commitdiff
Make browser windows pop up when browsing URLs on Wayland
authorDaniel Colascione <dancol@dancol.org>
Mon, 23 Dec 2024 18:34:11 +0000 (13:34 -0500)
committerEshel Yaron <me@eshelyaron.com>
Sat, 4 Jan 2025 20:22:39 +0000 (21:22 +0100)
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.

* 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

* etc/NEWS: mention the new feature

(cherry picked from commit 72eb5f8bedbe441f6a3952557b9aa3ef6fd6235d)

etc/NEWS
lisp/net/browse-url.el
src/pgtkfns.c

index 7d9575d4de6936a0a1ac5c2dd8eadf895762a65f..d37a7254b613939e4a77d4a4c3067a16748c5fb1 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -236,6 +236,13 @@ It has been obsolete since Emacs 28.1.
 *** Support for gnome-moz-remote has been removed.
 It has been obsolete since Emacs 25.1.
 
+*** New GTK-native launch mode
+For better Wayland support, the pgtk toolkit exposes a new
+'x-gtk-launch-uri' browse-url handler and uses it by default when URLs
+are browsed from a PGTK frame.  For other frames, we fall back to the
+default URL launch function.  This change allows us to properly raise
+browser windows under Wayland using the xdg_activation_v1 protocol.
+
 ** CL-Lib
 +++
 *** 'cl-labels' now also accepts (FUNC EXP) bindings, like 'cl-flet'.
index 252d247a9a9044e42b6e51922ad949472dd34d45..b272ae6c348d9033244fa9a4e4729f87aab8caf3 100644 (file)
     ,@(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")
@@ -1084,6 +1087,8 @@ one showing the selected frame."
     (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.
@@ -1105,6 +1110,9 @@ instead of `browse-url-new-window-flag'."
      '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-firefox-program) 'browse-url-firefox)
     ((executable-find browse-url-chromium-program) 'browse-url-chromium)
@@ -1424,6 +1432,23 @@ point."
 (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.
index 0ff3262cd11514796c6516702a0ec1a4e07f3f0c..1c2b8985ee8d7720332114626473209765224cb0 100644 (file)
@@ -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);