2016-12-26 12:38:51 +01:00
|
|
|
/* ============================================================
|
|
|
|
* QupZilla - Qt web browser
|
2017-01-26 17:14:18 +01:00
|
|
|
* Copyright (C) 2016-2017 David Rosca <nowrep@gmail.com>
|
2016-12-26 12:38:51 +01:00
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
|
2017-01-26 17:14:18 +01:00
|
|
|
#include <QPointer>
|
2016-12-26 12:38:51 +01:00
|
|
|
#include <QPaintEvent>
|
|
|
|
#include <QWebEngineProfile>
|
|
|
|
#include <QWebEngineScriptCollection>
|
2017-01-26 21:13:57 +01:00
|
|
|
#include <QStyle>
|
|
|
|
#include <QStyleOption>
|
2016-12-26 12:38:51 +01:00
|
|
|
|
|
|
|
Q_GLOBAL_STATIC(WebScrollBarManager, qz_web_scrollbar_manager)
|
|
|
|
|
2017-01-26 21:13:57 +01:00
|
|
|
class WebScrollBarCornerWidget : public QWidget
|
2016-12-26 12:38:51 +01:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit WebScrollBarCornerWidget(WebView *view)
|
|
|
|
: QWidget()
|
|
|
|
, m_view(view)
|
|
|
|
{
|
2017-01-26 21:13:57 +01:00
|
|
|
setAutoFillBackground(true);
|
2016-12-26 12:38:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2017-01-26 21:13:57 +01:00
|
|
|
Q_UNUSED(ev)
|
|
|
|
|
|
|
|
QStyleOption option;
|
|
|
|
option.initFrom(this);
|
|
|
|
option.rect = rect();
|
|
|
|
|
|
|
|
QPainter p(this);
|
|
|
|
style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this);
|
2016-12-26 12:38:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
WebView *m_view;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ScrollBarData {
|
|
|
|
~ScrollBarData() {
|
|
|
|
delete vscrollbar;
|
|
|
|
delete hscrollbar;
|
|
|
|
delete corner;
|
|
|
|
}
|
|
|
|
|
|
|
|
WebScrollBar *vscrollbar;
|
|
|
|
WebScrollBar *hscrollbar;
|
2017-01-26 17:59:45 +01:00
|
|
|
bool vscrollbarVisible = false;
|
|
|
|
bool hscrollbarVisible = false;
|
2016-12-26 12:38:51 +01:00
|
|
|
WebScrollBarCornerWidget *corner;
|
|
|
|
};
|
|
|
|
|
|
|
|
WebScrollBarManager::WebScrollBarManager(QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
{
|
2016-12-27 13:12:10 +01:00
|
|
|
m_scrollbarJs = QL1S("(function() {"
|
2016-12-27 16:51:01 +01:00
|
|
|
"var head = document.getElementsByTagName('head')[0];"
|
|
|
|
"if (!head) return;"
|
2016-12-27 13:12:10 +01:00
|
|
|
"var css = document.createElement('style');"
|
|
|
|
"css.setAttribute('type', 'text/css');"
|
|
|
|
"var size = %1 / window.devicePixelRatio + 'px';"
|
|
|
|
"css.appendChild(document.createTextNode('"
|
|
|
|
" body::-webkit-scrollbar{width:'+size+';height:'+size+';}"
|
|
|
|
"'));"
|
2016-12-27 16:51:01 +01:00
|
|
|
"head.appendChild(css);"
|
2016-12-27 13:12:10 +01:00
|
|
|
"})()");
|
|
|
|
|
2016-12-26 12:38:51 +01:00
|
|
|
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;
|
|
|
|
|
2016-12-27 13:12:10 +01:00
|
|
|
const int thickness = data->vscrollbar->thickness();
|
|
|
|
|
2016-12-26 12:38:51 +01:00
|
|
|
auto updateValues = [=]() {
|
|
|
|
const QSize viewport = viewportSize(view, thickness);
|
|
|
|
data->vscrollbar->updateValues(viewport);
|
2017-01-26 17:59:45 +01:00
|
|
|
data->vscrollbar->setVisible(data->vscrollbarVisible);
|
2016-12-26 12:38:51 +01:00
|
|
|
data->hscrollbar->updateValues(viewport);
|
2017-01-26 17:59:45 +01:00
|
|
|
data->hscrollbar->setVisible(data->hscrollbarVisible);
|
|
|
|
data->corner->updateVisibility(data->vscrollbarVisible && data->hscrollbarVisible, thickness);
|
2016-12-26 12:38:51 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
connect(view, &WebView::viewportResized, this, updateValues);
|
|
|
|
connect(view->page(), &WebPage::scrollPositionChanged, this, updateValues);
|
|
|
|
|
2017-01-26 17:14:18 +01:00
|
|
|
connect(view->page(), &WebPage::contentsSizeChanged, this, [=]() {
|
|
|
|
const QString source = QL1S("var out = {"
|
2017-01-26 20:56:52 +01:00
|
|
|
"vertical: document.documentElement && window.innerWidth > document.documentElement.clientWidth,"
|
|
|
|
"horizontal: document.documentElement && window.innerHeight > document.documentElement.clientHeight"
|
2017-01-26 17:14:18 +01:00
|
|
|
"};out;");
|
|
|
|
|
|
|
|
QPointer<WebView> p(view);
|
|
|
|
view->page()->runJavaScript(source, WebPage::SafeJsWorld, [=](const QVariant &res) {
|
2017-01-26 20:45:38 +01:00
|
|
|
if (!p || !m_scrollbars.contains(view)) {
|
2017-01-26 17:14:18 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const QVariantMap map = res.toMap();
|
2017-01-26 17:59:45 +01:00
|
|
|
data->vscrollbarVisible = map.value(QSL("vertical")).toBool();
|
|
|
|
data->hscrollbarVisible = map.value(QSL("horizontal")).toBool();
|
|
|
|
updateValues();
|
2017-01-26 17:14:18 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-12-27 13:12:10 +01:00
|
|
|
connect(view, &WebView::zoomLevelChanged, this, [=]() {
|
|
|
|
view->page()->runJavaScript(m_scrollbarJs.arg(thickness));
|
|
|
|
});
|
|
|
|
|
2016-12-26 12:38:51 +01:00
|
|
|
if (m_scrollbars.size() == 1) {
|
2016-12-27 13:12:10 +01:00
|
|
|
createUserScript(thickness);
|
2016-12-26 12:38:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-12-26 20:17:53 +01:00
|
|
|
QScrollBar *WebScrollBarManager::scrollBar(Qt::Orientation orientation, WebView *view) const
|
|
|
|
{
|
|
|
|
ScrollBarData *d = m_scrollbars.value(view);
|
|
|
|
if (!d) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return orientation == Qt::Vertical ? d->vscrollbar : d->hscrollbar;
|
|
|
|
}
|
|
|
|
|
2016-12-26 12:38:51 +01:00
|
|
|
WebScrollBarManager *WebScrollBarManager::instance()
|
|
|
|
{
|
|
|
|
return qz_web_scrollbar_manager();
|
|
|
|
}
|
|
|
|
|
2016-12-27 13:12:10 +01:00
|
|
|
void WebScrollBarManager::createUserScript(int thickness)
|
2016-12-26 12:38:51 +01:00
|
|
|
{
|
|
|
|
QWebEngineScript script;
|
|
|
|
script.setName(QSL("_qupzilla_scrollbar"));
|
|
|
|
script.setInjectionPoint(QWebEngineScript::DocumentReady);
|
|
|
|
script.setWorldId(WebPage::SafeJsWorld);
|
2016-12-27 13:12:10 +01:00
|
|
|
script.setSourceCode(m_scrollbarJs.arg(thickness));
|
2016-12-26 12:38:51 +01:00
|
|
|
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();
|
|
|
|
|
2016-12-27 13:41:12 +01:00
|
|
|
thickness /= view->devicePixelRatioF();
|
|
|
|
|
2017-01-26 17:59:45 +01:00
|
|
|
ScrollBarData *data = m_scrollbars.value(view);
|
|
|
|
Q_ASSERT(data);
|
|
|
|
|
|
|
|
if (data->vscrollbarVisible) {
|
|
|
|
viewport.setWidth(viewport.width() - thickness);
|
2017-01-26 20:56:52 +01:00
|
|
|
}
|
|
|
|
if (data->hscrollbarVisible) {
|
2017-01-26 17:59:45 +01:00
|
|
|
viewport.setHeight(viewport.height() - thickness);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
const QSize content = view->page()->contentsSize().toSize();
|
|
|
|
|
2016-12-26 12:38:51 +01:00
|
|
|
// 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);
|
|
|
|
}
|
2017-01-26 17:59:45 +01:00
|
|
|
#endif
|
2016-12-26 12:38:51 +01:00
|
|
|
|
|
|
|
return viewport;
|
|
|
|
}
|