unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] Make browser windows pop up when browsing URLs on Wayland
@ 2024-12-23 19:23 Daniel Colascione
  2024-12-24  5:49 ` Tassilo Horn
  0 siblings, 1 reply; 3+ messages in thread
From: Daniel Colascione @ 2024-12-23 19:23 UTC (permalink / raw)
  To: emacs-devel; +Cc: Daniel Colascione

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




^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] Make browser windows pop up when browsing URLs on Wayland
  2024-12-23 19:23 [PATCH] Make browser windows pop up when browsing URLs on Wayland Daniel Colascione
@ 2024-12-24  5:49 ` Tassilo Horn
  2024-12-24  6:39   ` Daniel Colascione
  0 siblings, 1 reply; 3+ messages in thread
From: Tassilo Horn @ 2024-12-24  5:49 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: emacs-devel

Daniel Colascione <dancol@dancol.org> writes:

Hi Daniel,

> 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.

The reason there's browse-url-default-handlers and browse-url-handlers
is that the former is meant for Emacs itself and packages whereas the
latter is meant for the user to customize.  IIRC, Stefan Monnier
suggested that distinction back then when I added the handlers and I
still don't see a better way.  If there was only the defcustom
browse-url-handlers, either packages couldn't sensibly add to it or if
they did, users wouldn't be sensibly able to override what packages
added.  Or if a package added an entry which the user then saved, how
would that be removed when the package was removed?

That's different with display-buffer-alist which is nil by default and
it's not expected that packages add rules to it.  In contrast, if I'd
write a gemini client for emacs, it's quite obvious that I'd add an
entry matching gemini:// urls with my hander to
browse-url-default-handlers.

Bye,
Tassilo



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Make browser windows pop up when browsing URLs on Wayland
  2024-12-24  5:49 ` Tassilo Horn
@ 2024-12-24  6:39   ` Daniel Colascione
  0 siblings, 0 replies; 3+ messages in thread
From: Daniel Colascione @ 2024-12-24  6:39 UTC (permalink / raw)
  To: Tassilo Horn; +Cc: emacs-devel



On December 24, 2024 12:49:36 AM EST, Tassilo Horn <tsdh@gnu.org> wrote:
>Daniel Colascione <dancol@dancol.org> writes:
>
>Hi Daniel,
>
>> 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.
>
>The reason there's browse-url-default-handlers and browse-url-handlers
>is that the former is meant for Emacs itself and packages whereas the
>latter is meant for the user to customize.  IIRC, Stefan Monnier
>suggested that distinction back then when I added the handlers and I
>still don't see a better way.  If there was only the defcustom
>browse-url-handlers, either packages couldn't sensibly add to it or if
>they did, users wouldn't be sensibly able to override what packages
>added.  Or if a package added an entry which the user then saved, how
>would that be removed when the package was removed?
>
>That's different with display-buffer-alist which is nil by default and
>it's not expected that packages add rules to it.  In contrast, if I'd
>write a gemini client for emacs, it's quite obvious that I'd add an
>entry matching gemini:// urls with my hander to
>browse-url-default-handlers.
>
>Bye,
>Tassilo


You could say the same of hooks, yes? Or auto-mode-alist?

Customization could work by associating each entry with a priority --- 20, 50, 90, etc. --- and merging user-provided entries (and whiteouts to disable certain pre-existing entries) with package supplied entries. This way, we end up with a simple, single approach to finding the handler for a URL: go down the list in priority order (breaking ties arbitrarily) and use the first handler that says "yes, I handle this URL".




^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-12-24  6:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-23 19:23 [PATCH] Make browser windows pop up when browsing URLs on Wayland Daniel Colascione
2024-12-24  5:49 ` Tassilo Horn
2024-12-24  6:39   ` Daniel Colascione

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).