From 341c2bcfb0ab9d57d22c1ee723f19b3dba8e3ce1 Mon Sep 17 00:00:00 2001 From: "Andre A. Gomes" Date: Tue, 23 Jul 2024 21:51:18 +0300 Subject: [PATCH 1/2] Refactor fullscreen and maximized window logic. The new foreign interface architecture handles the state of the relevant window slots (fullscreen-p, maximized-p) instead of setf-ing them on the renderer packages. This replaces the need for the :skip-renderer-resize keyword. Fixed bug in toggle-message-buffer, where the height of the buffer was being probed incorrectly. Refactor the handling of the window-state-event in GTK. It didn't account for events where the window is no longer fullscreen or maximized. Simplify implementation of toggle-fullscreen, toggle-maximize, toggle-status-buffer and toggle-message-buffer. As for the fullscreen rationale regarding the UI: when a fullscreen event is emitted by JS's Fullscreen API, the status and message buffers are hidden. For all other fullscreen events, the status and message buffers are kept. Note that we can't hide the message buffer on fullscreen since then there would be no way to get that important piece of information. On typical browsers, the equivalent of the message buffer is a dynamically visible toolbar at the bottom left (and it is still displayed on fullscreen). --- source/foreign-interface.lisp | 35 ++++++++++++---- source/renderer/electron.lisp | 8 ++-- source/renderer/gtk.lisp | 38 ++++++++++------- source/window.lisp | 79 +++++++++++++---------------------- 4 files changed, 84 insertions(+), 76 deletions(-) diff --git a/source/foreign-interface.lisp b/source/foreign-interface.lisp index 7ee020b7a6f..79eef818e7a 100644 --- a/source/foreign-interface.lisp +++ b/source/foreign-interface.lisp @@ -26,15 +26,32 @@ If the `:setter-p' option is non-nil, then a dummy setf method is defined." (define-ffi-generic ffi-window-delete (window) (:documentation "Delete WINDOW.")) -(define-ffi-generic ffi-window-fullscreen (window) - (:documentation "Set fullscreen WINDOW state on.")) -(define-ffi-generic ffi-window-unfullscreen (window) - (:documentation "Set fullscreen WINDOW state off.")) - -(define-ffi-generic ffi-window-maximize (window) - (:documentation "Set WINDOW to a maximized state.")) -(define-ffi-generic ffi-window-unmaximize (window) - (:documentation "Set WINDOW to an unmaximized state.")) +(define-ffi-generic ffi-window-fullscreen (window &key &allow-other-keys) + (:method :around ((window window) &key (user-event-p t) &allow-other-keys) + (setf (slot-value window 'fullscreen-p) t) + (when user-event-p (call-next-method))) + (:documentation "Set fullscreen WINDOW state on. +USER-EVENT-P helps to distinguish events requested by the user or +renderer (e.g. fullscreen a video stream).")) +(define-ffi-generic ffi-window-unfullscreen (window &key &allow-other-keys) + (:method :around ((window window) &key (user-event-p t) &allow-other-keys) + (setf (slot-value window 'fullscreen-p) nil) + (when user-event-p (call-next-method))) + (:documentation "Set fullscreen WINDOW state off. +See `ffi-window-fullscreen'.")) + +(define-ffi-generic ffi-window-maximize (window &key &allow-other-keys) + (:method :around ((window window) &key (user-event-p t) &allow-other-keys) + (setf (slot-value window 'maximized-p) t) + (when user-event-p (call-next-method))) + (:documentation "Set WINDOW to a maximized state. +USER-EVENT-P helps to distinguish events requested by the user or renderer.")) +(define-ffi-generic ffi-window-unmaximize (window &key &allow-other-keys) + (:method :around ((window window) &key (user-event-p t) &allow-other-keys) + (setf (slot-value window 'maximized-p) nil) + (when user-event-p (call-next-method))) + (:documentation "Set WINDOW to an unmaximized state. +See `ffi-window-maximize'.")) (define-ffi-generic ffi-buffer-url (buffer) (:documentation "Return the URL associated with BUFFER as a `quri:uri'. diff --git a/source/renderer/electron.lisp b/source/renderer/electron.lisp index 35cac853227..69424a3a2ad 100644 --- a/source/renderer/electron.lisp +++ b/source/renderer/electron.lisp @@ -403,16 +403,16 @@ (defmethod ffi-width ((window electron-window)) (electron:get-bounds window 'width)) -(defmethod ffi-window-fullscreen ((window electron-window)) +(defmethod ffi-window-fullscreen ((window electron-window) &key &allow-other-keys) (electron:fullscreen window)) -(defmethod ffi-window-unfullscreen ((window electron-window)) +(defmethod ffi-window-unfullscreen ((window electron-window) &key &allow-other-keys) (electron:unfullscreen window)) -(defmethod ffi-window-maximize ((window electron-window)) +(defmethod ffi-window-maximize ((window electron-window) &key &allow-other-keys) (electron:maximize window)) -(defmethod ffi-window-unmaximize ((window electron-window)) +(defmethod ffi-window-unmaximize ((window electron-window) &key &allow-other-keys) (electron:unmaximize window)) ;; Input handling diff --git a/source/renderer/gtk.lisp b/source/renderer/gtk.lisp index 379fd29f390..3b1e5c2b20c 100644 --- a/source/renderer/gtk.lisp +++ b/source/renderer/gtk.lisp @@ -500,12 +500,18 @@ response. The BODY is wrapped with `with-protect'." (on-signal-destroy window)) (connect-signal window "window-state-event" nil (widget event) (declare (ignore widget)) - (setf (nyxt::fullscreen-p window) - (find :fullscreen - (gdk:gdk-event-window-state-new-window-state event))) - (setf (nyxt::maximized-p window) - (find :maximized - (gdk:gdk-event-window-state-new-window-state event))) + (let ((fullscreen-p) + (maximized-p)) + (dolist (state (gdk:gdk-event-window-state-new-window-state event)) + (case state + (:fullscreen + (setq fullscreen-p t) + (ffi-window-fullscreen window :user-event-p nil)) + (:maximized + (setq maximized-p t) + (ffi-window-maximize window :user-event-p nil)))) + (unless fullscreen-p (ffi-window-unfullscreen window :user-event-p nil)) + (unless maximized-p (ffi-window-unmaximize window :user-event-p nil))) nil)) (unless nyxt::*headless-p* @@ -523,16 +529,16 @@ response. The BODY is wrapped with `with-protect'." (define-ffi-method ffi-window-delete ((window gtk-window)) (gtk:gtk-widget-destroy (gtk-object window))) -(define-ffi-method ffi-window-fullscreen ((window gtk-window)) +(define-ffi-method ffi-window-fullscreen ((window gtk-window) &key &allow-other-keys) (gtk:gtk-window-fullscreen (gtk-object window))) -(define-ffi-method ffi-window-unfullscreen ((window gtk-window)) +(define-ffi-method ffi-window-unfullscreen ((window gtk-window) &key &allow-other-keys) (gtk:gtk-window-unfullscreen (gtk-object window))) -(define-ffi-method ffi-window-maximize ((window gtk-window)) +(define-ffi-method ffi-window-maximize ((window gtk-window) &key &allow-other-keys) (gtk:gtk-window-maximize (gtk-object window))) -(define-ffi-method ffi-window-unmaximize ((window gtk-window)) +(define-ffi-method ffi-window-unmaximize ((window gtk-window) &key &allow-other-keys) (gtk:gtk-window-unmaximize (gtk-object window))) (defun derive-key-string (keyval character) @@ -1610,13 +1616,17 @@ the `active-buffer'." nil) (connect-signal buffer "enter-fullscreen" nil (web-view) (declare (ignore web-view)) - (setf (nyxt::fullscreen-p (current-window)) t) - (toggle-fullscreen :skip-renderer-resize t) + (ffi-window-fullscreen (current-window) :user-event-p nil) + ;; As to account for JS's Fullscreen API. + (disable-message-buffer (current-window)) + (disable-status-buffer (current-window)) nil) (connect-signal buffer "leave-fullscreen" nil (web-view) (declare (ignore web-view)) - (setf (nyxt::fullscreen-p (current-window)) nil) - (toggle-fullscreen :skip-renderer-resize t) + (ffi-window-unfullscreen (current-window) :user-event-p nil) + ;; Ideally, the UI state prior to fullscreen must be recovered. + (enable-message-buffer (current-window)) + (enable-status-buffer (current-window)) nil) buffer) diff --git a/source/window.lisp b/source/window.lisp index 82c47e2ce78..b089ca5e5a3 100644 --- a/source/window.lisp +++ b/source/window.lisp @@ -178,66 +178,47 @@ not try to quit the browser." (window-set-buffer window buffer) (values window buffer))) -(define-command toggle-fullscreen (&key (window (current-window)) - skip-renderer-resize) - "Fullscreen WINDOW, or the current window, when omitted. -When `skip-renderer-resize' is non-nil, don't ask the renderer to fullscreen the window." - (let ((fullscreen (fullscreen-p window))) - (unless skip-renderer-resize - (if fullscreen - (ffi-window-unfullscreen window) - (ffi-window-fullscreen window))) - (toggle-status-buffer :show-p (not fullscreen)) - (toggle-message-buffer :show-p (not fullscreen)))) - -(define-command toggle-maximize (&key (window (current-window))) - "Maximize WINDOW, or the current window, when omitted." - (let ((maximized (maximized-p window))) - (if maximized - (ffi-window-unmaximize window) - (ffi-window-maximize window)))) - +(define-command toggle-fullscreen (&optional (window (current-window))) + "Toggle fullscreen state of window." + (if (fullscreen-p window) + (ffi-window-unfullscreen window) + (ffi-window-fullscreen window))) + +(define-command toggle-maximize (&optional (window (current-window))) + "Toggle maximized state of window." + (if (maximized-p window) + (ffi-window-unmaximize window) + (ffi-window-maximize window))) + +(export-always 'enable-status-buffer) (defun enable-status-buffer (&optional (window (current-window))) (setf (ffi-height (status-buffer window)) (height (status-buffer window)))) +(export-always 'disable-status-buffer) (defun disable-status-buffer (&optional (window (current-window))) (setf (ffi-height (status-buffer window)) 0)) +(export-always 'enable-message-buffer) (defun enable-message-buffer (&optional (window (current-window))) (setf (ffi-height (message-buffer window)) (height (message-buffer window)))) +(export-always 'disable-message-buffer) (defun disable-message-buffer (&optional (window (current-window))) (setf (ffi-height (message-buffer window)) 0)) (define-command toggle-toolbars (&optional (window (current-window))) "Toggle the visibility of the message and status buffers." - (toggle-status-buffer :window window) - (toggle-message-buffer :window window)) - -(define-command toggle-status-buffer (&key (window (current-window)) - (show-p nil show-provided-p)) - "Toggle the visibility of the status buffer. - -If SHOW-P is provided: -- If SHOW-P is T, then `status-buffer' is always enabled; -- Otherwise, it is always disabled." - (cond ((and show-provided-p show-p) - (enable-status-buffer window)) - ((and (not show-provided-p) - (zerop (ffi-height (status-buffer window)))) - (enable-status-buffer window)) - (t (disable-status-buffer window)))) - -(define-command toggle-message-buffer (&key (window (current-window)) - (show-p nil show-provided-p)) - "Toggle the visibility of the message buffer. - -If SHOW-P is provided: -- If SHOW-P is T, then `message-buffer' is always enabled; -- Otherwise, it is always disabled." - (cond ((and show-provided-p show-p) - (enable-message-buffer window)) - ((and (not show-provided-p) - (zerop (height (message-buffer window)))) - (enable-message-buffer window)) - (t (disable-message-buffer window)))) + (toggle-status-buffer window) + (toggle-message-buffer window)) + +(define-command toggle-status-buffer (&optional (window (current-window))) + "Toggle the visibility of the status buffer." + (if (zerop (ffi-height (status-buffer window))) + (enable-status-buffer window) + (disable-status-buffer window))) + +(define-command toggle-message-buffer (&optional (window (current-window))) + "Toggle the visibility of the message buffer." + (if (zerop (ffi-height (message-buffer window))) + (enable-message-buffer window) + (disable-message-buffer window))) From ed26e875bf6bf13f382f87120807ec92118035bf Mon Sep 17 00:00:00 2001 From: "Andre A. Gomes" Date: Wed, 24 Jul 2024 12:34:07 +0300 Subject: [PATCH 2/2] changelog: Mention fullscreen logic fix. --- source/changelog.lisp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/changelog.lisp b/source/changelog.lisp index dcda371278a..97c45c827a1 100644 --- a/source/changelog.lisp +++ b/source/changelog.lisp @@ -27,6 +27,7 @@ (define-version "4.0.0" (:ul + (:li "Fix fullscreen and maximized window logic.") (:li "Refactor input to be handled on the buffer level rather than the window level.") (:li "Deprecate " (:code "input-skip-dispatcher") ".")