1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 10:46:35 +01:00

Use native scrollbars for main scrollbars

Use native widgets to render main scrollbars (scrollbars of the
main webview widget, not iframes etc).

It makes the scrollbars on body element invisible and instead draws
native widgets on the space for scrollbars.

Comes with possibility to disable it, enabled by default.
This commit is contained in:
David Rosca 2016-12-26 12:38:51 +01:00
parent 83444d8851
commit 64b48f6899
11 changed files with 417 additions and 4 deletions

View File

@ -215,6 +215,8 @@ SOURCES += \
webengine/webinspector.cpp \
webengine/webpage.cpp \
webengine/webview.cpp \
webengine/webscrollbar.cpp \
webengine/webscrollbarmanager.cpp \
webtab/searchtoolbar.cpp \
webtab/tabbedwebview.cpp \
webtab/webtab.cpp \
@ -397,6 +399,8 @@ HEADERS += \
webengine/webinspector.h \
webengine/webpage.h \
webengine/webview.h \
webengine/webscrollbar.h \
webengine/webscrollbarmanager.h \
webtab/searchtoolbar.h \
webtab/tabbedwebview.h \
webtab/webtab.h \

View File

@ -48,6 +48,7 @@
#include "profilemanager.h"
#include "html5permissions/html5permissionsdialog.h"
#include "searchenginesdialog.h"
#include "webscrollbarmanager.h"
#include <QSettings>
#include <QInputDialog>
@ -277,6 +278,7 @@ Preferences::Preferences(BrowserWindow* window)
ui->animateScrolling->setChecked(settings.value("AnimateScrolling", true).toBool());
ui->wheelScroll->setValue(settings.value("wheelScrollLines", qApp->wheelScrollLines()).toInt());
ui->xssAuditing->setChecked(settings.value("XSSAuditing", false).toBool());
ui->useNativeScrollbars->setChecked(settings.value("UseNativeScrollbars", true).toBool());
foreach (int level, WebView::zoomLevels()) {
ui->defaultZoomLevel->addItem(QString("%1%").arg(level));
@ -973,6 +975,7 @@ void Preferences::saveSettings()
settings.setValue("DefaultZoomLevel", ui->defaultZoomLevel->currentIndex());
settings.setValue("XSSAuditing", ui->xssAuditing->isChecked());
settings.setValue("closeAppWithCtrlQ", ui->closeAppWithCtrlQ->isChecked());
settings.setValue("UseNativeScrollbars", ui->useNativeScrollbars->isChecked());
#ifdef Q_OS_WIN
settings.setValue("CheckDefaultBrowser", ui->checkDefaultBrowser->isChecked());
#endif
@ -1070,6 +1073,8 @@ void Preferences::saveSettings()
mApp->desktopNotifications()->loadSettings();
mApp->autoFill()->loadSettings();
mApp->networkManager()->loadSettings();
WebScrollBarManager::instance()->loadSettings();
}
Preferences::~Preferences()

View File

@ -1117,6 +1117,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="useNativeScrollbars">
<property name="text">
<string>Use native scrollbars</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
@ -2374,8 +2381,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>560</width>
<height>70</height>
<width>96</width>
<height>28</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_14">

View File

@ -161,6 +161,11 @@ void WebPage::scroll(int x, int y)
runJavaScript(QSL("window.scrollTo(window.scrollX + %1, window.scrollY + %2)").arg(x).arg(y), WebPage::SafeJsWorld);
}
void WebPage::setScrollPosition(const QPointF &pos)
{
runJavaScript(QSL("window.scrollTo(%1, %2)").arg(pos.x()).arg(pos.y()), WebPage::SafeJsWorld);
}
void WebPage::scheduleAdjustPage()
{
if (view()->isLoading()) {

View File

@ -59,6 +59,7 @@ public:
WebHitTestResult hitTestContent(const QPoint &pos) const;
void scroll(int x, int y);
void setScrollPosition(const QPointF &pos);
bool javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString* result) Q_DECL_OVERRIDE;
bool javaScriptConfirm(const QUrl &securityOrigin, const QString &msg) Q_DECL_OVERRIDE;

View File

@ -0,0 +1,89 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2016 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "webscrollbar.h"
#include "webview.h"
#include "webpage.h"
#include <QPaintEvent>
WebScrollBar::WebScrollBar(Qt::Orientation orientation, WebView *view)
: QScrollBar(orientation)
, m_view(view)
{
setFocusProxy(m_view);
resize(sizeHint());
connect(this, &QScrollBar::valueChanged, this, &WebScrollBar::performScroll);
connect(view, &WebView::focusChanged, this, [this]() { update(); });
}
int WebScrollBar::thickness() const
{
return orientation() == Qt::Vertical ? width() : height();
}
void WebScrollBar::updateValues(const QSize &viewport)
{
setMinimum(0);
setParent(m_view->overlayWidget());
m_blockScrolling = true;
if (orientation() == Qt::Vertical) {
setFixedHeight(viewport.height());
move(m_view->width() - width(), 0);
setPageStep(viewport.height());
setMaximum(std::max(0, m_view->page()->contentsSize().toSize().height() - viewport.height()));
setValue(m_view->page()->scrollPosition().toPoint().y());
} else {
setFixedWidth(viewport.width());
move(0, m_view->height() - height());
setPageStep(viewport.width());
setMaximum(std::max(0, m_view->page()->contentsSize().toSize().width() - viewport.width()));
setValue(m_view->page()->scrollPosition().toPoint().x());
}
m_blockScrolling = false;
setVisible(maximum() > minimum());
}
void WebScrollBar::performScroll()
{
if (m_blockScrolling) {
return;
}
QPointF pos = m_view->page()->scrollPosition();
if (orientation() == Qt::Vertical) {
pos.setY(value());
} else {
pos.setX(value());
}
m_view->page()->setScrollPosition(pos);
}
void WebScrollBar::paintEvent(QPaintEvent *ev)
{
QPainter painter(this);
painter.fillRect(ev->rect(), m_view->page()->backgroundColor());
QScrollBar::paintEvent(ev);
}

View File

@ -0,0 +1,46 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2016 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef WEBSCROLLBAR_H
#define WEBSCROLLBAR_H
#include <QScrollBar>
#include "qzcommon.h"
class WebView;
class WebScrollBar : public QScrollBar
{
Q_OBJECT
public:
explicit WebScrollBar(Qt::Orientation orientation, WebView *view);
int thickness() const;
void updateValues(const QSize &viewport);
private:
void performScroll();
void paintEvent(QPaintEvent *ev) override;
WebView *m_view;
bool m_blockScrolling = false;
};
#endif // WEBSCROLLBAR_H

View File

@ -0,0 +1,186 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2016 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "webscrollbarmanager.h"
#include "webscrollbar.h"
#include "webview.h"
#include "webpage.h"
#include "mainapplication.h"
#include "scripts.h"
#include "settings.h"
#include <QPaintEvent>
#include <QWebEngineProfile>
#include <QWebEngineScriptCollection>
Q_GLOBAL_STATIC(WebScrollBarManager, qz_web_scrollbar_manager)
class WebScrollBarCornerWidget : QWidget
{
public:
explicit WebScrollBarCornerWidget(WebView *view)
: QWidget()
, m_view(view)
{
}
void updateVisibility(bool visible, int thickness)
{
if (visible) {
setParent(m_view->overlayWidget());
resize(thickness, thickness);
move(m_view->width() - width(), m_view->height() - height());
show();
} else {
hide();
}
}
private:
void paintEvent(QPaintEvent *ev) override
{
QPainter painter(this);
painter.fillRect(ev->rect(), m_view->page()->backgroundColor());
QWidget::paintEvent(ev);
}
WebView *m_view;
};
struct ScrollBarData {
~ScrollBarData() {
delete vscrollbar;
delete hscrollbar;
delete corner;
}
WebScrollBar *vscrollbar;
WebScrollBar *hscrollbar;
WebScrollBarCornerWidget *corner;
};
WebScrollBarManager::WebScrollBarManager(QObject *parent)
: QObject(parent)
{
loadSettings();
}
void WebScrollBarManager::loadSettings()
{
m_enabled = Settings().value(QSL("Web-Browser-Settings/UseNativeScrollbars"), true).toBool();
if (!m_enabled) {
for (WebView *view : m_scrollbars.keys()) {
removeWebView(view);
}
}
}
void WebScrollBarManager::addWebView(WebView *view)
{
if (!m_enabled) {
return;
}
delete m_scrollbars.value(view);
ScrollBarData *data = new ScrollBarData;
data->vscrollbar = new WebScrollBar(Qt::Vertical, view);
data->hscrollbar = new WebScrollBar(Qt::Horizontal, view);
data->corner = new WebScrollBarCornerWidget(view);
m_scrollbars[view] = data;
auto updateValues = [=]() {
const int thickness = data->vscrollbar->thickness();
const QSize viewport = viewportSize(view, thickness);
data->vscrollbar->updateValues(viewport);
data->hscrollbar->updateValues(viewport);
data->corner->updateVisibility(data->vscrollbar->isVisible() && data->hscrollbar->isVisible(), thickness);
};
connect(view, &WebView::viewportResized, this, updateValues);
connect(view->page(), &WebPage::contentsSizeChanged, this, updateValues);
connect(view->page(), &WebPage::scrollPositionChanged, this, updateValues);
if (m_scrollbars.size() == 1) {
createUserScript();
}
}
void WebScrollBarManager::removeWebView(WebView *view)
{
if (m_scrollbars.size() == 1) {
removeUserScript();
}
disconnect(view, 0, this, 0);
disconnect(view->page(), 0, this, 0);
delete m_scrollbars.take(view);
}
WebScrollBarManager *WebScrollBarManager::instance()
{
return qz_web_scrollbar_manager();
}
void WebScrollBarManager::createUserScript()
{
Q_ASSERT(!m_scrollbars.isEmpty());
const int thickness = (*m_scrollbars.begin())->vscrollbar->thickness();
QWebEngineScript script;
script.setName(QSL("_qupzilla_scrollbar"));
script.setInjectionPoint(QWebEngineScript::DocumentReady);
script.setWorldId(WebPage::SafeJsWorld);
script.setSourceCode(Scripts::setCss(QSL("body::-webkit-scrollbar{width:%1px;height:%1px;}").arg(thickness)));
mApp->webProfile()->scripts()->insert(script);
}
void WebScrollBarManager::removeUserScript()
{
QWebEngineScript script = mApp->webProfile()->scripts()->findScript(QSL("_qupzilla_scrollbar"));
mApp->webProfile()->scripts()->remove(script);
}
QSize WebScrollBarManager::viewportSize(WebView *view, int thickness) const
{
QSize viewport = view->size();
const QSize content = view->page()->contentsSize().toSize();
// Check both axis
if (content.width() - viewport.width() > 0) {
viewport.setHeight(viewport.height() - thickness);
}
if (content.height() - viewport.height() > 0) {
viewport.setWidth(viewport.width() - thickness);
}
// Check again against adjusted size
if (viewport.height() == view->height() && content.width() - viewport.width() > 0) {
viewport.setHeight(viewport.height() - thickness);
}
if (viewport.width() == view->width() && content.height() - viewport.height() > 0) {
viewport.setWidth(viewport.width() - thickness);
}
return viewport;
}

View File

@ -0,0 +1,50 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2016 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef WEBSCROLLBARMANAGER_H
#define WEBSCROLLBARMANAGER_H
#include <QObject>
#include <QHash>
class WebView;
class WebScrollBarManager : public QObject
{
Q_OBJECT
public:
explicit WebScrollBarManager(QObject *parent = 0);
void loadSettings();
void addWebView(WebView *view);
void removeWebView(WebView *view);
static WebScrollBarManager *instance();
private:
void createUserScript();
void removeUserScript();
QSize viewportSize(WebView *view, int thickness) const;
bool m_enabled = true;
QHash<WebView*, struct ScrollBarData*> m_scrollbars;
};
#endif // WEBSCROLLBARMANAGER_H

View File

@ -34,6 +34,7 @@
#include "webinspector.h"
#include "scripts.h"
#include "webhittestresult.h"
#include "webscrollbarmanager.h"
#include <iostream>
@ -88,6 +89,7 @@ WebView::WebView(QWidget* parent)
WebView::~WebView()
{
WebInspector::unregisterView(this);
WebScrollBarManager::instance()->removeWebView(this);
}
QIcon WebView::icon() const
@ -147,9 +149,12 @@ void WebView::setPage(WebPage *page)
// Set default zoom level
zoomReset();
// Actions needs to be initialized for every QWebPage change
// Actions needs to be initialized for every QWebEnginePage change
initializeActions();
// Scrollbars must be added only after QWebEnginePage is set
WebScrollBarManager::instance()->addWebView(this);
mApp->plugins()->emitWebPageCreated(m_page);
}
@ -1235,5 +1240,19 @@ bool WebView::eventFilter(QObject *obj, QEvent *event)
}
}
return QWebEngineView::eventFilter(obj, event);
const bool res = QWebEngineView::eventFilter(obj, event);
if (obj == m_rwhvqt) {
switch (event->type()) {
case QEvent::FocusIn:
case QEvent::FocusOut:
emit focusChanged(hasFocus());
break;
default:
break;
}
}
return res;
}

View File

@ -74,6 +74,7 @@ public:
static void setForceContextMenuOnMouseRelease(bool force);
signals:
void focusChanged(bool);
void viewportResized(QSize);
void showNotification(QWidget*);
void privacyChanged(bool);