Add fullscreen support for QtWebEngine
This commit is contained in:
parent
1209724f83
commit
98e6ccf548
@ -27,6 +27,7 @@ Added
|
||||
- Proxy support for QtWebEngine with Qt >= 5.8
|
||||
- Support for the `content -> cookies-store` option with QtWebEngine
|
||||
- Support for the `storage -> cache-size` option with QtWebEngine
|
||||
- Support for the HTML5 fullscreen API (e.g. youtube videos) with QtWebEngine
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
@ -319,8 +319,13 @@ How many pages to go forward.
|
||||
|
||||
[[fullscreen]]
|
||||
=== fullscreen
|
||||
Syntax: +:fullscreen [*--leave*]+
|
||||
|
||||
Toggle fullscreen mode.
|
||||
|
||||
==== optional arguments
|
||||
* +*-l*+, +*--leave*+: Only leave fullscreen if it was entered by the page.
|
||||
|
||||
[[help]]
|
||||
=== help
|
||||
Syntax: +:help [*--tab*] [*--bg*] [*--window*] ['topic']+
|
||||
|
@ -94,6 +94,18 @@ class TabData:
|
||||
self.override_target = None
|
||||
|
||||
|
||||
class AbstractAction:
|
||||
|
||||
"""Attribute of AbstractTab for Qt WebActions."""
|
||||
|
||||
def __init__(self):
|
||||
self._widget = None
|
||||
|
||||
def exit_fullscreen(self):
|
||||
"""Exit the fullscreen mode."""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class AbstractPrinting:
|
||||
|
||||
"""Attribute of AbstractTab for printing the page."""
|
||||
@ -513,6 +525,9 @@ class AbstractTab(QWidget):
|
||||
new_tab_requested: Emitted when a new tab should be opened with the
|
||||
given URL.
|
||||
load_status_changed: The loading status changed
|
||||
fullscreen_requested: Fullscreen display was requested by the page.
|
||||
arg: True if fullscreen should be turned on,
|
||||
False if it should be turned off.
|
||||
"""
|
||||
|
||||
window_close_requested = pyqtSignal()
|
||||
@ -528,6 +543,7 @@ class AbstractTab(QWidget):
|
||||
shutting_down = pyqtSignal()
|
||||
contents_size_changed = pyqtSignal(QSizeF)
|
||||
add_history_item = pyqtSignal(QUrl, QUrl, str) # url, requested url, title
|
||||
fullscreen_requested = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, win_id, mode_manager, parent=None):
|
||||
self.win_id = win_id
|
||||
@ -548,6 +564,7 @@ class AbstractTab(QWidget):
|
||||
# self.search = AbstractSearch(parent=self)
|
||||
# self.printing = AbstractPrinting()
|
||||
# self.elements = AbstractElements(self)
|
||||
# self.action = AbstractAction()
|
||||
|
||||
self.data = TabData()
|
||||
self._layout = miscwidgets.WrapperLayout(self)
|
||||
@ -576,6 +593,7 @@ class AbstractTab(QWidget):
|
||||
self.zoom._widget = widget
|
||||
self.search._widget = widget
|
||||
self.printing._widget = widget
|
||||
self.action._widget = widget
|
||||
self.elements._widget = widget
|
||||
|
||||
self._install_event_filter()
|
||||
|
@ -2069,3 +2069,24 @@ class CommandDispatcher:
|
||||
"""
|
||||
if bg or tab or window or url != old_url:
|
||||
self.openurl(url=url, bg=bg, tab=tab, window=window)
|
||||
|
||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||
def fullscreen(self, leave=False):
|
||||
"""Toggle fullscreen mode.
|
||||
|
||||
Args:
|
||||
leave: Only leave fullscreen if it was entered by the page.
|
||||
"""
|
||||
if leave:
|
||||
tab = self._current_widget()
|
||||
try:
|
||||
tab.action.exit_fullscreen()
|
||||
except browsertab.UnsupportedOperationError:
|
||||
pass
|
||||
return
|
||||
|
||||
window = self._tabbed_browser.window()
|
||||
if window.isFullScreen():
|
||||
window.showNormal()
|
||||
else:
|
||||
window.showFullScreen()
|
||||
|
@ -164,6 +164,8 @@ def init(args):
|
||||
# https://bugreports.qt.io/browse/QTBUG-58650
|
||||
PersistentCookiePolicy().set(config.get('content', 'cookies-store'))
|
||||
|
||||
Attribute(QWebEngineSettings.FullScreenSupportEnabled).set(True)
|
||||
|
||||
websettings.init_mappings(MAPPINGS)
|
||||
objreg.get('config').changed.connect(update_settings)
|
||||
|
||||
|
@ -79,6 +79,17 @@ _JS_WORLD_MAP = {
|
||||
}
|
||||
|
||||
|
||||
class WebEngineAction(browsertab.AbstractAction):
|
||||
|
||||
"""QtWebKit implementations related to web actions."""
|
||||
|
||||
def _action(self, action):
|
||||
self._widget.triggerPageAction(action)
|
||||
|
||||
def exit_fullscreen(self):
|
||||
self._action(QWebEnginePage.ExitFullScreen)
|
||||
|
||||
|
||||
class WebEnginePrinting(browsertab.AbstractPrinting):
|
||||
|
||||
"""QtWebEngine implementations related to printing."""
|
||||
@ -473,6 +484,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||
self.search = WebEngineSearch(parent=self)
|
||||
self.printing = WebEnginePrinting()
|
||||
self.elements = WebEngineElements(self)
|
||||
self.action = WebEngineAction()
|
||||
self._set_widget(widget)
|
||||
self._connect_signals()
|
||||
self.backend = usertypes.Backend.QtWebEngine
|
||||
@ -640,6 +652,12 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||
url=url_string, error="Authentication required", icon='')
|
||||
self.set_html(error_page)
|
||||
|
||||
@pyqtSlot('QWebEngineFullScreenRequest')
|
||||
def _on_fullscreen_requested(self, request):
|
||||
# FIXME:qtwebengine do we want a setting to disallow this?
|
||||
request.accept()
|
||||
self.fullscreen_requested.emit(request.toggleOn())
|
||||
|
||||
def _connect_signals(self):
|
||||
view = self._widget
|
||||
page = view.page()
|
||||
@ -653,6 +671,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||
page.loadFinished.connect(self._on_load_finished)
|
||||
page.certificate_error.connect(self._on_ssl_errors)
|
||||
page.authenticationRequired.connect(self._on_authentication_required)
|
||||
page.fullScreenRequested.connect(self._on_fullscreen_requested)
|
||||
|
||||
view.titleChanged.connect(self.title_changed)
|
||||
view.urlChanged.connect(self._on_url_changed)
|
||||
|
@ -52,6 +52,14 @@ def init():
|
||||
objreg.register('js-bridge', js_bridge)
|
||||
|
||||
|
||||
class WebKitAction(browsertab.AbstractAction):
|
||||
|
||||
"""QtWebKit implementations related to web actions."""
|
||||
|
||||
def exit_fullscreen(self):
|
||||
raise browsertab.UnsupportedOperationError
|
||||
|
||||
|
||||
class WebKitPrinting(browsertab.AbstractPrinting):
|
||||
|
||||
"""QtWebKit implementations related to printing."""
|
||||
@ -610,6 +618,7 @@ class WebKitTab(browsertab.AbstractTab):
|
||||
self.search = WebKitSearch(parent=self)
|
||||
self.printing = WebKitPrinting()
|
||||
self.elements = WebKitElements(self)
|
||||
self.action = WebKitAction()
|
||||
self._set_widget(widget)
|
||||
self._connect_signals()
|
||||
self.backend = usertypes.Backend.QtWebKit
|
||||
|
@ -1549,7 +1549,8 @@ KEY_DATA = collections.OrderedDict([
|
||||
])),
|
||||
|
||||
('normal', collections.OrderedDict([
|
||||
('clear-keychain ;; search', ['<Escape>', '<Ctrl-[>']),
|
||||
('clear-keychain ;; search ;; fullscreen --leave',
|
||||
['<Escape>', '<Ctrl-[>']),
|
||||
('set-cmd-text -s :open', ['o']),
|
||||
('set-cmd-text :open {url:pretty}', ['go']),
|
||||
('set-cmd-text -s :open -t', ['O']),
|
||||
@ -1769,8 +1770,12 @@ CHANGED_KEY_COMMANDS = [
|
||||
(re.compile(r'^download-page$'), r'download'),
|
||||
(re.compile(r'^cancel-download$'), r'download-cancel'),
|
||||
|
||||
(re.compile(r"""^search (''|"")$"""), r'clear-keychain ;; search'),
|
||||
(re.compile(r'^search$'), r'clear-keychain ;; search'),
|
||||
(re.compile(r"""^search (''|"")$"""),
|
||||
r'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
(re.compile(r'^search$'),
|
||||
r'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
(re.compile(r'^clear-keychain ;; search$'),
|
||||
r'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
|
||||
(re.compile(r"""^set-cmd-text ['"](.*) ['"]$"""), r'set-cmd-text -s \1'),
|
||||
(re.compile(r"""^set-cmd-text ['"](.*)['"]$"""), r'set-cmd-text \1'),
|
||||
@ -1784,7 +1789,8 @@ CHANGED_KEY_COMMANDS = [
|
||||
(re.compile(r'^scroll 50 0$'), r'scroll right'),
|
||||
(re.compile(r'^scroll ([-\d]+ [-\d]+)$'), r'scroll-px \1'),
|
||||
|
||||
(re.compile(r'^search *;; *clear-keychain$'), r'clear-keychain ;; search'),
|
||||
(re.compile(r'^search *;; *clear-keychain$'),
|
||||
r'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
(re.compile(r'^clear-keychain *;; *leave-mode$'), r'leave-mode'),
|
||||
|
||||
(re.compile(r'^download-remove --all$'), r'download-clear'),
|
||||
|
@ -456,6 +456,10 @@ class MainWindow(QWidget):
|
||||
tabs.cur_url_changed.connect(status.url.set_url)
|
||||
tabs.cur_link_hovered.connect(status.url.set_hover_url)
|
||||
tabs.cur_load_status_changed.connect(status.url.on_load_status_changed)
|
||||
tabs.page_fullscreen_requested.connect(
|
||||
self._on_page_fullscreen_requested)
|
||||
tabs.page_fullscreen_requested.connect(
|
||||
status.on_page_fullscreen_requested)
|
||||
|
||||
# command input / completion
|
||||
mode_manager.left.connect(tabs.on_mode_left)
|
||||
@ -463,6 +467,13 @@ class MainWindow(QWidget):
|
||||
completion_obj.on_clear_completion_selection)
|
||||
cmd.hide_completion.connect(completion_obj.hide)
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _on_page_fullscreen_requested(self, on):
|
||||
if on:
|
||||
self.showFullScreen()
|
||||
else:
|
||||
self.showNormal()
|
||||
|
||||
@cmdutils.register(instance='main-window', scope='window')
|
||||
@pyqtSlot()
|
||||
def close(self):
|
||||
@ -474,14 +485,6 @@ class MainWindow(QWidget):
|
||||
"""
|
||||
super().close()
|
||||
|
||||
@cmdutils.register(instance='main-window', scope='window')
|
||||
def fullscreen(self):
|
||||
"""Toggle fullscreen mode."""
|
||||
if self.isFullScreen():
|
||||
self.showNormal()
|
||||
else:
|
||||
self.showFullScreen()
|
||||
|
||||
def resizeEvent(self, e):
|
||||
"""Extend resizewindow's resizeEvent to adjust completion.
|
||||
|
||||
|
@ -46,6 +46,8 @@ class StatusBar(QWidget):
|
||||
_hbox: The main QHBoxLayout.
|
||||
_stack: The QStackedLayout with cmd/txt widgets.
|
||||
_win_id: The window ID the statusbar is associated with.
|
||||
_page_fullscreen: Whether the webpage (e.g. a video) is shown
|
||||
fullscreen.
|
||||
|
||||
Class attributes:
|
||||
_prompt_active: If we're currently in prompt-mode.
|
||||
@ -143,6 +145,7 @@ class StatusBar(QWidget):
|
||||
|
||||
self._win_id = win_id
|
||||
self._option = None
|
||||
self._page_fullscreen = False
|
||||
|
||||
self._hbox = QHBoxLayout(self)
|
||||
self.set_hbox_padding()
|
||||
@ -193,7 +196,7 @@ class StatusBar(QWidget):
|
||||
def maybe_hide(self):
|
||||
"""Hide the statusbar if it's configured to do so."""
|
||||
hide = config.get('ui', 'hide-statusbar')
|
||||
if hide:
|
||||
if hide or self._page_fullscreen:
|
||||
self.hide()
|
||||
else:
|
||||
self.show()
|
||||
@ -306,6 +309,11 @@ class StatusBar(QWidget):
|
||||
usertypes.KeyMode.yesno]:
|
||||
self.set_mode_active(old_mode, False)
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def on_page_fullscreen_requested(self, on):
|
||||
self._page_fullscreen = on
|
||||
self.maybe_hide()
|
||||
|
||||
def resizeEvent(self, e):
|
||||
"""Extend resizeEvent of QWidget to emit a resized signal afterwards.
|
||||
|
||||
|
@ -98,6 +98,7 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
resized = pyqtSignal('QRect')
|
||||
current_tab_changed = pyqtSignal(browsertab.AbstractTab)
|
||||
new_tab = pyqtSignal(browsertab.AbstractTab, int)
|
||||
page_fullscreen_requested = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
super().__init__(win_id, parent)
|
||||
@ -199,6 +200,9 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
functools.partial(self.on_window_close_requested, tab))
|
||||
tab.new_tab_requested.connect(self.tabopen)
|
||||
tab.add_history_item.connect(objreg.get('web-history').add_from_tab)
|
||||
tab.fullscreen_requested.connect(self.page_fullscreen_requested)
|
||||
tab.fullscreen_requested.connect(
|
||||
self.tabBar().on_page_fullscreen_requested)
|
||||
|
||||
def current_url(self):
|
||||
"""Get the URL of the current tab.
|
||||
|
@ -259,6 +259,8 @@ class TabBar(QTabBar):
|
||||
Attributes:
|
||||
vertical: When the tab bar is currently vertical.
|
||||
win_id: The window ID this TabBar belongs to.
|
||||
_page_fullscreen: Whether the webpage (e.g. a video) is shown
|
||||
fullscreen.
|
||||
"""
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
@ -269,6 +271,7 @@ class TabBar(QTabBar):
|
||||
config_obj = objreg.get('config')
|
||||
config_obj.changed.connect(self.set_font)
|
||||
self.vertical = False
|
||||
self._page_fullscreen = False
|
||||
self._auto_hide_timer = QTimer()
|
||||
self._auto_hide_timer.setSingleShot(True)
|
||||
self._auto_hide_timer.setInterval(
|
||||
@ -296,20 +299,24 @@ class TabBar(QTabBar):
|
||||
self._auto_hide_timer.setInterval(
|
||||
config.get('tabs', 'show-switching-delay'))
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def on_page_fullscreen_requested(self, on):
|
||||
self._page_fullscreen = on
|
||||
self._tabhide()
|
||||
|
||||
def on_change(self):
|
||||
"""Show tab bar when current tab got changed."""
|
||||
show = config.get('tabs', 'show')
|
||||
if show == 'switching':
|
||||
if show == 'switching' or self._page_fullscreen:
|
||||
self.show()
|
||||
self._auto_hide_timer.start()
|
||||
|
||||
def _tabhide(self):
|
||||
"""Hide the tab bar if needed."""
|
||||
show = config.get('tabs', 'show')
|
||||
show_never = show == 'never'
|
||||
switching = show == 'switching'
|
||||
multiple = show == 'multiple'
|
||||
if show_never or (multiple and self.count() == 1) or switching:
|
||||
if (show in ['never', 'switching'] or
|
||||
(show == 'multiple' and self.count() == 1) or
|
||||
self._page_fullscreen):
|
||||
self.hide()
|
||||
else:
|
||||
self.show()
|
||||
|
@ -110,6 +110,7 @@ class Tab(browsertab.AbstractTab):
|
||||
self.search = browsertab.AbstractSearch(parent=self)
|
||||
self.printing = browsertab.AbstractPrinting()
|
||||
self.elements = browsertab.AbstractElements(self)
|
||||
self.action = browsertab.AbstractAction()
|
||||
|
||||
def _install_event_filter(self):
|
||||
pass
|
||||
|
@ -281,9 +281,9 @@ class TestKeyConfigParser:
|
||||
('download-page', 'download'),
|
||||
('cancel-download', 'download-cancel'),
|
||||
|
||||
('search ""', 'clear-keychain ;; search'),
|
||||
("search ''", 'clear-keychain ;; search'),
|
||||
("search", 'clear-keychain ;; search'),
|
||||
('search ""', 'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
("search ''", 'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
("search", 'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
("search ;; foobar", None),
|
||||
('search "foo"', None),
|
||||
|
||||
@ -305,11 +305,16 @@ class TestKeyConfigParser:
|
||||
('scroll 0 0', 'scroll-px 0 0'),
|
||||
('scroll 23 42', 'scroll-px 23 42'),
|
||||
|
||||
('search ;; clear-keychain', 'clear-keychain ;; search'),
|
||||
('search;;clear-keychain', 'clear-keychain ;; search'),
|
||||
('search ;; clear-keychain',
|
||||
'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
('search;;clear-keychain',
|
||||
'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
('search;;foo', None),
|
||||
('clear-keychain ;; leave-mode', 'leave-mode'),
|
||||
('clear-keychain ;; search',
|
||||
'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
('leave-mode ;; foo', None),
|
||||
('search ;; clear-keychain',
|
||||
'clear-keychain ;; search ;; fullscreen --leave'),
|
||||
|
||||
('download-remove --all', 'download-clear'),
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user