From b184d2f94dc40f07e1c857348264c0e3dbfcde3a Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Thu, 16 Nov 2017 19:22:08 +0600 Subject: [PATCH 001/574] dirty initial port of chrome caretbrowser extension --- qutebrowser/browser/webengine/webenginetab.py | 5 +- qutebrowser/javascript/axs_testing.js | 2643 +++++++++++++++++ qutebrowser/javascript/webengine_caret.js | 2188 ++++++++++++++ qutebrowser/keyinput/modeman.py | 4 - 4 files changed, 4835 insertions(+), 5 deletions(-) create mode 100644 qutebrowser/javascript/axs_testing.js create mode 100644 qutebrowser/javascript/webengine_caret.js diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 7339cd422..3a779f480 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -179,7 +179,8 @@ class WebEngineCaret(browsertab.AbstractCaret): @pyqtSlot(usertypes.KeyMode) def _on_mode_entered(self, mode): - pass + js_code = javascript.assemble('caret', 'setInitialCursor') + self._tab.run_js_async(js_code) @pyqtSlot(usertypes.KeyMode) def _on_mode_left(self): @@ -547,6 +548,8 @@ class WebEngineTab(browsertab.AbstractTab): 'window._qutebrowser = {};', utils.read_file('javascript/scroll.js'), utils.read_file('javascript/webelem.js'), + utils.read_file('javascript/webengine_caret.js'), + utils.read_file('javascript/axs_testing.js'), ]) script = QWebEngineScript() script.setInjectionPoint(QWebEngineScript.DocumentCreation) diff --git a/qutebrowser/javascript/axs_testing.js b/qutebrowser/javascript/axs_testing.js new file mode 100644 index 000000000..e6b1a3755 --- /dev/null +++ b/qutebrowser/javascript/axs_testing.js @@ -0,0 +1,2643 @@ +/* + * Copyright 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Generated from http://github.com/GoogleChrome/accessibility-developer-tools/tree/7d778f7da58af341a47b3a6f6457c2842b24d4d8 + * + * See project README for build steps. + */ + +// AUTO-GENERATED CONTENT BELOW: DO NOT EDIT! See above for details. + +var fn = (function() { + var COMPILED = !0, goog = goog || {}; +goog.global = this; +goog.isDef = function(a) { + return void 0 !== a; +}; +goog.exportPath_ = function(a, b, c) { + a = a.split("."); + c = c || goog.global; + a[0] in c || !c.execScript || c.execScript("var " + a[0]); + for (var d;a.length && (d = a.shift());) { + !a.length && goog.isDef(b) ? c[d] = b : c = c[d] ? c[d] : c[d] = {}; + } +}; +goog.define = function(a, b) { + var c = b; + COMPILED || (goog.global.CLOSURE_UNCOMPILED_DEFINES && Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_UNCOMPILED_DEFINES, a) ? c = goog.global.CLOSURE_UNCOMPILED_DEFINES[a] : goog.global.CLOSURE_DEFINES && Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_DEFINES, a) && (c = goog.global.CLOSURE_DEFINES[a])); + goog.exportPath_(a, c); +}; +goog.DEBUG = !0; +goog.LOCALE = "en"; +goog.TRUSTED_SITE = !0; +goog.STRICT_MODE_COMPATIBLE = !1; +goog.DISALLOW_TEST_ONLY_CODE = COMPILED && !goog.DEBUG; +goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING = !1; +goog.provide = function(a) { + if (goog.isInModuleLoader_()) { + throw Error("goog.provide can not be used within a goog.module."); + } + if (!COMPILED && goog.isProvided_(a)) { + throw Error('Namespace "' + a + '" already declared.'); + } + goog.constructNamespace_(a); +}; +goog.constructNamespace_ = function(a, b) { + if (!COMPILED) { + delete goog.implicitNamespaces_[a]; + for (var c = a;(c = c.substring(0, c.lastIndexOf("."))) && !goog.getObjectByName(c);) { + goog.implicitNamespaces_[c] = !0; + } + } + goog.exportPath_(a, b); +}; +goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/; +goog.module = function(a) { + if (!goog.isString(a) || !a || -1 == a.search(goog.VALID_MODULE_RE_)) { + throw Error("Invalid module identifier"); + } + if (!goog.isInModuleLoader_()) { + throw Error("Module " + a + " has been loaded incorrectly."); + } + if (goog.moduleLoaderState_.moduleName) { + throw Error("goog.module may only be called once per module."); + } + goog.moduleLoaderState_.moduleName = a; + if (!COMPILED) { + if (goog.isProvided_(a)) { + throw Error('Namespace "' + a + '" already declared.'); + } + delete goog.implicitNamespaces_[a]; + } +}; +goog.module.get = function(a) { + return goog.module.getInternal_(a); +}; +goog.module.getInternal_ = function(a) { + if (!COMPILED) { + return goog.isProvided_(a) ? a in goog.loadedModules_ ? goog.loadedModules_[a] : goog.getObjectByName(a) : null; + } +}; +goog.moduleLoaderState_ = null; +goog.isInModuleLoader_ = function() { + return null != goog.moduleLoaderState_; +}; +goog.module.declareLegacyNamespace = function() { + if (!COMPILED && !goog.isInModuleLoader_()) { + throw Error("goog.module.declareLegacyNamespace must be called from within a goog.module"); + } + if (!COMPILED && !goog.moduleLoaderState_.moduleName) { + throw Error("goog.module must be called prior to goog.module.declareLegacyNamespace."); + } + goog.moduleLoaderState_.declareLegacyNamespace = !0; +}; +goog.setTestOnly = function(a) { + if (goog.DISALLOW_TEST_ONLY_CODE) { + throw a = a || "", Error("Importing test-only code into non-debug environment" + (a ? ": " + a : ".")); + } +}; +goog.forwardDeclare = function(a) { +}; +COMPILED || (goog.isProvided_ = function(a) { + return a in goog.loadedModules_ || !goog.implicitNamespaces_[a] && goog.isDefAndNotNull(goog.getObjectByName(a)); +}, goog.implicitNamespaces_ = {"goog.module":!0}); +goog.getObjectByName = function(a, b) { + for (var c = a.split("."), d = b || goog.global, e;e = c.shift();) { + if (goog.isDefAndNotNull(d[e])) { + d = d[e]; + } else { + return null; + } + } + return d; +}; +goog.globalize = function(a, b) { + var c = b || goog.global, d; + for (d in a) { + c[d] = a[d]; + } +}; +goog.addDependency = function(a, b, c, d) { + if (goog.DEPENDENCIES_ENABLED) { + var e; + a = a.replace(/\\/g, "/"); + var f = goog.dependencies_; + d && "boolean" !== typeof d || (d = d ? {module:"goog"} : {}); + for (var g = 0;e = b[g];g++) { + f.nameToPath[e] = a, f.loadFlags[a] = d; + } + for (d = 0;b = c[d];d++) { + a in f.requires || (f.requires[a] = {}), f.requires[a][b] = !0; + } + } +}; +goog.ENABLE_DEBUG_LOADER = !0; +goog.logToConsole_ = function(a) { + goog.global.console && goog.global.console.error(a); +}; +goog.require = function(a) { + if (!COMPILED) { + goog.ENABLE_DEBUG_LOADER && goog.IS_OLD_IE_ && goog.maybeProcessDeferredDep_(a); + if (goog.isProvided_(a)) { + return goog.isInModuleLoader_() ? goog.module.getInternal_(a) : null; + } + if (goog.ENABLE_DEBUG_LOADER) { + var b = goog.getPathFromDeps_(a); + if (b) { + return goog.writeScripts_(b), null; + } + } + a = "goog.require could not find: " + a; + goog.logToConsole_(a); + throw Error(a); + } +}; +goog.basePath = ""; +goog.nullFunction = function() { +}; +goog.abstractMethod = function() { + throw Error("unimplemented abstract method"); +}; +goog.addSingletonGetter = function(a) { + a.getInstance = function() { + if (a.instance_) { + return a.instance_; + } + goog.DEBUG && (goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = a); + return a.instance_ = new a; + }; +}; +goog.instantiatedSingletons_ = []; +goog.LOAD_MODULE_USING_EVAL = !0; +goog.SEAL_MODULE_EXPORTS = goog.DEBUG; +goog.loadedModules_ = {}; +goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER; +goog.ALWAYS_TRANSPILE = !1; +goog.NEVER_TRANSPILE = !1; +goog.DEPENDENCIES_ENABLED && (goog.dependencies_ = {loadFlags:{}, nameToPath:{}, requires:{}, visited:{}, written:{}, deferred:{}}, goog.inHtmlDocument_ = function() { + var a = goog.global.document; + return null != a && "write" in a; +}, goog.findBasePath_ = function() { + if (goog.isDef(goog.global.CLOSURE_BASE_PATH)) { + goog.basePath = goog.global.CLOSURE_BASE_PATH; + } else { + if (goog.inHtmlDocument_()) { + for (var a = goog.global.document.getElementsByTagName("SCRIPT"), b = a.length - 1;0 <= b;--b) { + var c = a[b].src, d = c.lastIndexOf("?"), d = -1 == d ? c.length : d; + if ("base.js" == c.substr(d - 7, 7)) { + goog.basePath = c.substr(0, d - 7); + break; + } + } + } + } +}, goog.importScript_ = function(a, b) { + (goog.global.CLOSURE_IMPORT_SCRIPT || goog.writeScriptTag_)(a, b) && (goog.dependencies_.written[a] = !0); +}, goog.IS_OLD_IE_ = !(goog.global.atob || !goog.global.document || !goog.global.document.all), goog.importProcessedScript_ = function(a, b, c) { + goog.importScript_("", 'goog.retrieveAndExec_("' + a + '", ' + b + ", " + c + ");"); +}, goog.queuedModules_ = [], goog.wrapModule_ = function(a, b) { + return goog.LOAD_MODULE_USING_EVAL && goog.isDef(goog.global.JSON) ? "goog.loadModule(" + goog.global.JSON.stringify(b + "\n//# sourceURL=" + a + "\n") + ");" : 'goog.loadModule(function(exports) {"use strict";' + b + "\n;return exports});\n//# sourceURL=" + a + "\n"; +}, goog.loadQueuedModules_ = function() { + var a = goog.queuedModules_.length; + if (0 < a) { + var b = goog.queuedModules_; + goog.queuedModules_ = []; + for (var c = 0;c < a;c++) { + goog.maybeProcessDeferredPath_(b[c]); + } + } +}, goog.maybeProcessDeferredDep_ = function(a) { + goog.isDeferredModule_(a) && goog.allDepsAreAvailable_(a) && (a = goog.getPathFromDeps_(a), goog.maybeProcessDeferredPath_(goog.basePath + a)); +}, goog.isDeferredModule_ = function(a) { + var b = (a = goog.getPathFromDeps_(a)) && goog.dependencies_.loadFlags[a] || {}; + return a && ("goog" == b.module || goog.needsTranspile_(b.lang)) ? goog.basePath + a in goog.dependencies_.deferred : !1; +}, goog.allDepsAreAvailable_ = function(a) { + if ((a = goog.getPathFromDeps_(a)) && a in goog.dependencies_.requires) { + for (var b in goog.dependencies_.requires[a]) { + if (!goog.isProvided_(b) && !goog.isDeferredModule_(b)) { + return !1; + } + } + } + return !0; +}, goog.maybeProcessDeferredPath_ = function(a) { + if (a in goog.dependencies_.deferred) { + var b = goog.dependencies_.deferred[a]; + delete goog.dependencies_.deferred[a]; + goog.globalEval(b); + } +}, goog.loadModuleFromUrl = function(a) { + goog.retrieveAndExec_(a, !0, !1); +}, goog.loadModule = function(a) { + var b = goog.moduleLoaderState_; + try { + goog.moduleLoaderState_ = {moduleName:void 0, declareLegacyNamespace:!1}; + var c; + if (goog.isFunction(a)) { + c = a.call(goog.global, {}); + } else { + if (goog.isString(a)) { + c = goog.loadModuleFromSource_.call(goog.global, a); + } else { + throw Error("Invalid module definition"); + } + } + var d = goog.moduleLoaderState_.moduleName; + if (!goog.isString(d) || !d) { + throw Error('Invalid module name "' + d + '"'); + } + goog.moduleLoaderState_.declareLegacyNamespace ? goog.constructNamespace_(d, c) : goog.SEAL_MODULE_EXPORTS && Object.seal && Object.seal(c); + goog.loadedModules_[d] = c; + } finally { + goog.moduleLoaderState_ = b; + } +}, goog.loadModuleFromSource_ = function(a) { + eval(a); + return {}; +}, goog.writeScriptSrcNode_ = function(a) { + goog.global.document.write(' + + diff --git a/tests/end2end/data/hints/iframe_button.html b/tests/end2end/data/hints/iframe_button.html new file mode 100644 index 000000000..cd7bf203c --- /dev/null +++ b/tests/end2end/data/hints/iframe_button.html @@ -0,0 +1,11 @@ + + + + + + Hinting inside an iframe + + + + + diff --git a/tests/end2end/data/hints/iframe_input.html b/tests/end2end/data/hints/iframe_input.html new file mode 100644 index 000000000..143577747 --- /dev/null +++ b/tests/end2end/data/hints/iframe_input.html @@ -0,0 +1,11 @@ + + + + + + Hinting inside an iframe + + + + + diff --git a/tests/end2end/data/iframe_search.html b/tests/end2end/data/iframe_search.html new file mode 100644 index 000000000..a06c0ef3e --- /dev/null +++ b/tests/end2end/data/iframe_search.html @@ -0,0 +1,11 @@ + + + + + + Hinting inside an iframe + + + + + diff --git a/tests/end2end/features/hints.feature b/tests/end2end/features/hints.feature index 0f7868e31..f575d0423 100644 --- a/tests/end2end/features/hints.feature +++ b/tests/end2end/features/hints.feature @@ -209,6 +209,19 @@ Feature: Using hints And I hint with args "links normal" and follow a Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, *" should be logged + Scenario: Using :follow-hint inside an iframe button + When I open data/hints/iframe_button.html + And I hint with args "all normal" and follow s + Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, *" should be logged + + Scenario: Hinting inputs in an iframe without type + When I open data/hints/iframe_input.html + And I hint with args "inputs" and follow a + And I wait for "Entering mode KeyMode.insert (reason: clicking input)" in the log + And I run :leave-mode + # The actual check is already done above + Then no crash should happen + ### FIXME currenly skipped, see https://github.com/qutebrowser/qutebrowser/issues/1525 @xfail_norun Scenario: Using :follow-hint inside a scrolled iframe @@ -218,7 +231,6 @@ Feature: Using hints And I hint wht args "links normal" and follow a Then "navigation request: url http://localhost:*/data/hello2.txt, type NavigationTypeLinkClicked, *" should be logged - @qtwebengine_skip: Opens in new tab due to Chromium bug Scenario: Opening a link inside a specific iframe When I open data/hints/iframe_target.html And I hint with args "links normal" and follow a diff --git a/tests/end2end/features/search.feature b/tests/end2end/features/search.feature index 3778f963d..483bcc29f 100644 --- a/tests/end2end/features/search.feature +++ b/tests/end2end/features/search.feature @@ -238,3 +238,22 @@ Feature: Searching on a page Then the following tabs should be open: - data/search.html - data/hello.txt (active) + + Scenario: Follow a searched link in an iframe + When I open data/iframe_search.html + And I run :tab-only + And I run :search follow + And I wait for "search found follow" in the log + And I run :follow-selected + Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, is_main_frame False" should be logged + + Scenario: Follow a tabbed searched link in an iframe + When I open data/iframe_search.html + And I run :tab-only + And I run :search follow + And I wait for "search found follow" in the log + And I run :follow-selected -t + And I wait until data/hello.txt is loaded + Then the following tabs should be open: + - data/iframe_search.html + - data/hello.txt (active) From b87f0b6f65d5ca7d05426ee3397fb724e667834a Mon Sep 17 00:00:00 2001 From: Jay Kamat Date: Mon, 18 Dec 2017 17:04:50 -0800 Subject: [PATCH 025/574] Add support for non-link buttons to test_hints --- tests/end2end/test_hints_html.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/end2end/test_hints_html.py b/tests/end2end/test_hints_html.py index abc106505..ff4837020 100644 --- a/tests/end2end/test_hints_html.py +++ b/tests/end2end/test_hints_html.py @@ -106,7 +106,11 @@ def test_hints(test_name, zoom_text_only, zoom_level, find_implementation, quteproc.set_setting('hints.find_implementation', find_implementation) quteproc.send_cmd(':zoom {}'.format(zoom_level)) # follow hint - quteproc.send_cmd(':hint links normal') + if 'button' in test_name: + # We are hinting buttons, link hinting will not work + quteproc.send_cmd(':hint all normal') + else: + quteproc.send_cmd(':hint links normal') quteproc.wait_for(message='hints: a', category='hints') quteproc.send_cmd(':follow-hint a') quteproc.wait_for_load_finished('data/' + parsed.target) From 012e63520f5ba90b9ab8c91754aa160010825954 Mon Sep 17 00:00:00 2001 From: Jay Kamat Date: Mon, 18 Dec 2017 18:20:25 -0800 Subject: [PATCH 026/574] Blacklist non-implemented qtwebkit frame features --- tests/end2end/features/hints.feature | 3 ++- tests/end2end/features/search.feature | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/end2end/features/hints.feature b/tests/end2end/features/hints.feature index f575d0423..5da03a085 100644 --- a/tests/end2end/features/hints.feature +++ b/tests/end2end/features/hints.feature @@ -212,7 +212,7 @@ Feature: Using hints Scenario: Using :follow-hint inside an iframe button When I open data/hints/iframe_button.html And I hint with args "all normal" and follow s - Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, *" should be logged + Then "navigation request: url http://localhost:*/data/hello.txt, *" should be logged Scenario: Hinting inputs in an iframe without type When I open data/hints/iframe_input.html @@ -241,6 +241,7 @@ Feature: Using hints And I run :tab-only And I hint with args "links tab" and follow a And I wait until data/hello.txt is loaded + And I wait 0.5s Then the following tabs should be open: - data/hints/iframe_target.html - data/hello.txt (active) diff --git a/tests/end2end/features/search.feature b/tests/end2end/features/search.feature index 483bcc29f..7779ff28e 100644 --- a/tests/end2end/features/search.feature +++ b/tests/end2end/features/search.feature @@ -239,6 +239,7 @@ Feature: Searching on a page - data/search.html - data/hello.txt (active) + @qtwebkit_skip: Not supported in qtwebkit Scenario: Follow a searched link in an iframe When I open data/iframe_search.html And I run :tab-only @@ -247,6 +248,7 @@ Feature: Searching on a page And I run :follow-selected Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, is_main_frame False" should be logged + @qtwebkit_skip: Not supported in qtwebkit Scenario: Follow a tabbed searched link in an iframe When I open data/iframe_search.html And I run :tab-only From c8ae405bfe7dd3a0b583013ed1b894c71186e4c7 Mon Sep 17 00:00:00 2001 From: seebye Date: Wed, 20 Dec 2017 00:10:21 +0100 Subject: [PATCH 027/574] fix #3396 --- qutebrowser/browser/history.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index ecab730ae..e82e6970d 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -171,7 +171,9 @@ class WebHistory(sql.SqlTable): @pyqtSlot(QUrl, QUrl, str) def add_from_tab(self, url, requested_url, title): """Add a new history entry as slot, called from a BrowserTab.""" - if url.scheme() == 'data' or requested_url.scheme() == 'data': + if any(url.scheme() == 'data' or + ('qute', 'back') == (url.scheme(), url.host()) + for url in (url, requested_url)): return if url.isEmpty(): # things set via setHtml From 801b6b90ce43b78d0a202f018833621b486cc7f7 Mon Sep 17 00:00:00 2001 From: seebye Date: Wed, 20 Dec 2017 01:15:12 +0100 Subject: [PATCH 028/574] pylint adjustments --- qutebrowser/browser/history.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index e82e6970d..e800ac0b2 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -173,7 +173,7 @@ class WebHistory(sql.SqlTable): """Add a new history entry as slot, called from a BrowserTab.""" if any(url.scheme() == 'data' or ('qute', 'back') == (url.scheme(), url.host()) - for url in (url, requested_url)): + for url in (url, requested_url)): return if url.isEmpty(): # things set via setHtml From 125af531cb8519916a29ff79733dd4fb5a660826 Mon Sep 17 00:00:00 2001 From: seebye Date: Fri, 22 Dec 2017 15:44:42 +0100 Subject: [PATCH 029/574] database qute://back --- qutebrowser/browser/history.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index e800ac0b2..04bc1be15 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -32,7 +32,7 @@ from qutebrowser.misc import objects, sql # increment to indicate that HistoryCompletion must be regenerated -_USER_VERSION = 1 +_USER_VERSION = 2 class CompletionHistory(sql.SqlTable): @@ -102,7 +102,8 @@ class WebHistory(sql.SqlTable): data = {'url': [], 'title': [], 'last_atime': []} # select the latest entry for each url q = sql.Query('SELECT url, title, max(atime) AS atime FROM History ' - 'WHERE NOT redirect GROUP BY url ORDER BY atime asc') + 'WHERE NOT redirect and url NOT LIKE "qute://back%" ' + 'GROUP BY url ORDER BY atime asc') for entry in q.run(): data['url'].append(self._format_completion_url(QUrl(entry.url))) data['title'].append(entry.title) @@ -172,7 +173,7 @@ class WebHistory(sql.SqlTable): def add_from_tab(self, url, requested_url, title): """Add a new history entry as slot, called from a BrowserTab.""" if any(url.scheme() == 'data' or - ('qute', 'back') == (url.scheme(), url.host()) + (url.scheme(), url.host()) == ('qute', 'back') for url in (url, requested_url)): return if url.isEmpty(): From d9b00acdc665e88d41d96bdba199f5f69c2302d8 Mon Sep 17 00:00:00 2001 From: RyanJenkins Date: Sat, 23 Dec 2017 23:59:02 -0800 Subject: [PATCH 030/574] Return focus to qutebrowser when external editor finishes. --- qutebrowser/browser/commands.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 92a841d72..a912842f6 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1639,6 +1639,7 @@ class CommandDispatcher: """ try: elem.set_value(text) + mainwindow.raise_window(objreg.last_focused_window()) except webelem.OrphanedError as e: message.error('Edited element vanished') except webelem.Error as e: From 9cb25e0c76e80b311898fd5aace7c27ac2169bdc Mon Sep 17 00:00:00 2001 From: RyanJenkins Date: Tue, 26 Dec 2017 20:19:39 -0800 Subject: [PATCH 031/574] Raise browser window after editor closes regardless of outcome of inserting text and avoid calling QApplication.instance().alert() in this scenario. --- qutebrowser/browser/commands.py | 3 ++- qutebrowser/mainwindow/mainwindow.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index a912842f6..3fffbcfb7 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1639,12 +1639,13 @@ class CommandDispatcher: """ try: elem.set_value(text) - mainwindow.raise_window(objreg.last_focused_window()) except webelem.OrphanedError as e: message.error('Edited element vanished') except webelem.Error as e: raise cmdexc.CommandError(str(e)) + mainwindow.raise_window(objreg.last_focused_window(), alert=False) + @cmdutils.register(instance='command-dispatcher', maxsplit=0, scope='window') def insert_text(self, text): diff --git a/qutebrowser/mainwindow/mainwindow.py b/qutebrowser/mainwindow/mainwindow.py index 3adce7567..9d288b565 100644 --- a/qutebrowser/mainwindow/mainwindow.py +++ b/qutebrowser/mainwindow/mainwindow.py @@ -94,13 +94,15 @@ def get_window(via_ipc, force_window=False, force_tab=False, return window.win_id -def raise_window(window): +def raise_window(window, alert=False): """Raise the given MainWindow object.""" window.setWindowState(window.windowState() & ~Qt.WindowMinimized) window.setWindowState(window.windowState() | Qt.WindowActive) window.raise_() window.activateWindow() - QApplication.instance().alert(window) + + if alert: + QApplication.instance().alert(window) # WORKAROUND for https://github.com/PyCQA/pylint/issues/1770 From 53575aaeed5a1e8389bbf0980fed757e85c34349 Mon Sep 17 00:00:00 2001 From: RyanJenkins Date: Wed, 27 Dec 2017 12:40:55 -0800 Subject: [PATCH 032/574] Default raise_windows() alert param to True to preserve existing behavior --- qutebrowser/mainwindow/mainwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/mainwindow/mainwindow.py b/qutebrowser/mainwindow/mainwindow.py index 9d288b565..dff465c41 100644 --- a/qutebrowser/mainwindow/mainwindow.py +++ b/qutebrowser/mainwindow/mainwindow.py @@ -94,7 +94,7 @@ def get_window(via_ipc, force_window=False, force_tab=False, return window.win_id -def raise_window(window, alert=False): +def raise_window(window, alert=True): """Raise the given MainWindow object.""" window.setWindowState(window.windowState() & ~Qt.WindowMinimized) window.setWindowState(window.windowState() | Qt.WindowActive) From 2a7423a515181001c7a0f2c8b4f9f19c82aec95d Mon Sep 17 00:00:00 2001 From: Manuel Seelaus Date: Wed, 27 Dec 2017 18:00:02 -0700 Subject: [PATCH 033/574] filter out records with None in any field. --- scripts/hist_importer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/hist_importer.py b/scripts/hist_importer.py index 84fada560..526a752e2 100755 --- a/scripts/hist_importer.py +++ b/scripts/hist_importer.py @@ -107,7 +107,7 @@ def clean(history): Args: history: List of records (datetime, url, title) from source database. """ - nulls = [record for record in history if record[0] is None] + nulls = [record for record in history if None in record] for null_datetime in nulls: history.remove(null_datetime) history = [list(record) for record in history] From a01566ed15f3f93ff034810e3d74d36d0d3657a1 Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Thu, 28 Dec 2017 19:17:25 +0600 Subject: [PATCH 034/574] Fix loosed variable --- qutebrowser/browser/commands.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index cb744b23d..5c051a3ff 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -862,6 +862,7 @@ class CommandDispatcher: else: # pragma: no cover raise ValueError("Invalid value {!r} for `what'.".format(what)) + self.yank_object['what'] = what self._yank_to_target(s) def _yank_callback(self, s): From 9728e90401a884a45de7f1bd72441f7ee5a63f37 Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Thu, 28 Dec 2017 20:05:10 +0600 Subject: [PATCH 035/574] Enable test in webengine --- tests/end2end/features/editor.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/end2end/features/editor.feature b/tests/end2end/features/editor.feature index d3c634b0d..f1b53e90d 100644 --- a/tests/end2end/features/editor.feature +++ b/tests/end2end/features/editor.feature @@ -115,7 +115,6 @@ Feature: Opening external editors And I run :click-element id qute-button Then the javascript message "text: foobar" should be logged - @qtwebengine_todo: Caret mode is not implemented yet Scenario: Spawning an editor in caret mode When I set up a fake editor returning "foobar" And I open data/editor.html From 63658d3a1e618e81687827d68961e7829aa3bd7b Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Thu, 28 Dec 2017 20:40:37 +0600 Subject: [PATCH 036/574] Catch userscript exception and show error message --- qutebrowser/browser/commands.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 5c051a3ff..53fb03830 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1247,7 +1247,10 @@ class CommandDispatcher: self.openurl(config.val.url.start_pages[0]) def _selection_callback(self, s): - self._run_userscript(s) + try: + self._run_userscript(s) + except cmdexc.CommandError as e: + message.error(str(e)) def _run_userscript(self, selection): """Run a userscript given as argument. From 83f8d840128248231a98cd3776d4436c4e58cfbf Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Thu, 28 Dec 2017 22:27:47 +0600 Subject: [PATCH 037/574] Finally enable webengine test --- tests/end2end/features/editor.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/end2end/features/editor.feature b/tests/end2end/features/editor.feature index 15da4a6cd..d01e3d229 100644 --- a/tests/end2end/features/editor.feature +++ b/tests/end2end/features/editor.feature @@ -129,7 +129,6 @@ Feature: Opening external editors And I kill the waiting editor Then the error "Edited element vanished" should be shown - @qtwebengine_todo: Caret mode is not implemented yet Scenario: Spawning an editor in caret mode When I set up a fake editor returning "foobar" And I open data/editor.html From 7d181ee4b53edb6064778802f427b52fe91004d5 Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Thu, 28 Dec 2017 23:04:04 +0600 Subject: [PATCH 038/574] Check if document body exists --- qutebrowser/javascript/webengine_caret.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qutebrowser/javascript/webengine_caret.js b/qutebrowser/javascript/webengine_caret.js index 7235c9772..af381f529 100644 --- a/qutebrowser/javascript/webengine_caret.js +++ b/qutebrowser/javascript/webengine_caret.js @@ -965,7 +965,8 @@ window._qutebrowser.caret = (function() { // eslint-disable-line max-statements, window.caretBrowsingLoaded = true; CaretBrowsing.init(); - if (document.body.getAttribute("caretbrowsing") === "on") { + if (document.body && + document.body.getAttribute("caretbrowsing") === "on") { CaretBrowsing.forceEnabled = true; CaretBrowsing.isEnabled = true; CaretBrowsing.updateIsCaretVisible(); From 3b836d34836e90d4cdf7ddbadc91c89c27ea51fa Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Fri, 29 Dec 2017 17:56:16 +0600 Subject: [PATCH 039/574] Fix lint warnings --- qutebrowser/browser/commands.py | 6 ++++-- qutebrowser/javascript/webengine_caret.js | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index d3f865a52..653d70014 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1293,9 +1293,11 @@ class CommandDispatcher: env['QUTE_URL'] = url.toString(QUrl.FullyEncoded) try: + args = self.userscript_object['args'] + verbose = self.userscript_object['verbose'] userscripts.run_async(tab, self.userscript_object['cmd'], - *self.userscript_object['args'], win_id=self._win_id, - env=env, verbose=self.userscript_object['verbose']) + *args, win_id=self._win_id, + env=env, verbose=verbose) except userscripts.Error as e: raise cmdexc.CommandError(e) finally: diff --git a/qutebrowser/javascript/webengine_caret.js b/qutebrowser/javascript/webengine_caret.js index af381f529..be0d6eaa5 100644 --- a/qutebrowser/javascript/webengine_caret.js +++ b/qutebrowser/javascript/webengine_caret.js @@ -965,7 +965,7 @@ window._qutebrowser.caret = (function() { // eslint-disable-line max-statements, window.caretBrowsingLoaded = true; CaretBrowsing.init(); - if (document.body && + if (document.body && document.body.getAttribute("caretbrowsing") === "on") { CaretBrowsing.forceEnabled = true; CaretBrowsing.isEnabled = true; From db16a87e68ca10cac2fcf17e8d4481b7999e7a26 Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Fri, 29 Dec 2017 18:39:29 +0600 Subject: [PATCH 040/574] Removed unused import --- qutebrowser/keyinput/modeman.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qutebrowser/keyinput/modeman.py b/qutebrowser/keyinput/modeman.py index 719d29863..2c21908de 100644 --- a/qutebrowser/keyinput/modeman.py +++ b/qutebrowser/keyinput/modeman.py @@ -29,7 +29,6 @@ from qutebrowser.keyinput import modeparsers, keyparser from qutebrowser.config import config from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.utils import usertypes, log, objreg, utils -from qutebrowser.misc import objects @attr.s(frozen=True) From 882beab3f244ef67742fb8285905af880444cf37 Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Fri, 29 Dec 2017 19:01:12 +0600 Subject: [PATCH 041/574] Try to fix Windows caret ussues --- qutebrowser/javascript/webengine_caret.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/qutebrowser/javascript/webengine_caret.js b/qutebrowser/javascript/webengine_caret.js index be0d6eaa5..4c2771451 100644 --- a/qutebrowser/javascript/webengine_caret.js +++ b/qutebrowser/javascript/webengine_caret.js @@ -468,6 +468,9 @@ window._qutebrowser.caret = (function() { // eslint-disable-line max-statements, CaretBrowsing.blinkFlag = true; + CaretBrowsing.isWindows = + window.navigator.userAgent.indexOf("Windows") !== -1; + CaretBrowsing.isControlThatNeedsArrowKeys = function(node) { // eslint-disable-line complexity,max-len if (!node) { return false; @@ -860,9 +863,15 @@ window._qutebrowser.caret = (function() { // eslint-disable-line max-statements, getSelection(). modify(action, direction, granularity); - window.setTimeout(() => { - CaretBrowsing.updateCaretOrSelection(true); - }, 0); + if (CaretBrowsing.isWindows && + (direction === "forward" || + direction === "right")) { + CaretBrowsing.move("left", "character"); + } else { + window.setTimeout(() => { + CaretBrowsing.updateCaretOrSelection(true); + }, 0); + } }; CaretBrowsing.moveToBlock = function(paragraph, boundary) { From d04a087c2bd9132603b704ed0c5edfefe3f43e02 Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Fri, 29 Dec 2017 20:10:18 +0600 Subject: [PATCH 042/574] Try fix Windows caret issues 2 --- qutebrowser/javascript/webengine_caret.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qutebrowser/javascript/webengine_caret.js b/qutebrowser/javascript/webengine_caret.js index 4c2771451..79fb01dcb 100644 --- a/qutebrowser/javascript/webengine_caret.js +++ b/qutebrowser/javascript/webengine_caret.js @@ -865,7 +865,8 @@ window._qutebrowser.caret = (function() { // eslint-disable-line max-statements, if (CaretBrowsing.isWindows && (direction === "forward" || - direction === "right")) { + direction === "right") && + granularity === "word") { CaretBrowsing.move("left", "character"); } else { window.setTimeout(() => { From e254ea2fa7e617432c656ad7f9055c72af64e2bc Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Fri, 29 Dec 2017 23:43:39 +0600 Subject: [PATCH 043/574] Add license and description --- qutebrowser/javascript/webengine_caret.js | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/qutebrowser/javascript/webengine_caret.js b/qutebrowser/javascript/webengine_caret.js index 79fb01dcb..e7075cd33 100644 --- a/qutebrowser/javascript/webengine_caret.js +++ b/qutebrowser/javascript/webengine_caret.js @@ -1,3 +1,28 @@ +/** + * Copyright 2016-2017 Florian Bruhin (The Compiler) + * + * This file is part of qutebrowser. + * + * qutebrowser 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. + * + * qutebrowser 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 qutebrowser. If not, see . + */ + +/** + * Ported chrome-caretbrowsing extension. + * Create and control div caret, which listen commands from qutebrowser, + * change document selection model and div caret position. + */ + "use strict"; // eslint-disable-line max-lines window._qutebrowser.caret = (function() { // eslint-disable-line max-statements,max-len From a6adbdf167b657e02979559ac5fc5923b2caf7af Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 29 Dec 2017 19:10:33 +0100 Subject: [PATCH 044/574] Clean up testbrowser scripts --- .gitignore | 16 +++--- .../cpp}/webengine/main.cpp | 0 .../cpp}/webengine/testbrowser.pro | 0 .../cpp}/webkit/main.cpp | 0 .../cpp}/webkit/testbrowser.pro | 0 scripts/testbrowser/testbrowser_webengine.py | 50 +++++++++++++++++ scripts/testbrowser/testbrowser_webkit.py | 56 +++++++++++++++++++ 7 files changed, 114 insertions(+), 8 deletions(-) rename scripts/{testbrowser_cpp => testbrowser/cpp}/webengine/main.cpp (100%) rename scripts/{testbrowser_cpp => testbrowser/cpp}/webengine/testbrowser.pro (100%) rename scripts/{testbrowser_cpp => testbrowser/cpp}/webkit/main.cpp (100%) rename scripts/{testbrowser_cpp => testbrowser/cpp}/webkit/testbrowser.pro (100%) create mode 100755 scripts/testbrowser/testbrowser_webengine.py create mode 100755 scripts/testbrowser/testbrowser_webkit.py diff --git a/.gitignore b/.gitignore index cb244557b..54a0dcae6 100644 --- a/.gitignore +++ b/.gitignore @@ -31,12 +31,12 @@ __pycache__ /prof /venv TODO -/scripts/testbrowser_cpp/webkit/Makefile -/scripts/testbrowser_cpp/webkit/main.o -/scripts/testbrowser_cpp/webkit/testbrowser -/scripts/testbrowser_cpp/webkit/.qmake.stash -/scripts/testbrowser_cpp/webengine/Makefile -/scripts/testbrowser_cpp/webengine/main.o -/scripts/testbrowser_cpp/webengine/testbrowser -/scripts/testbrowser_cpp/webengine/.qmake.stash +/scripts/testbrowser/cpp/webkit/Makefile +/scripts/testbrowser/cpp/webkit/main.o +/scripts/testbrowser/cpp/webkit/testbrowser +/scripts/testbrowser/cpp/webkit/.qmake.stash +/scripts/testbrowser/cpp/webengine/Makefile +/scripts/testbrowser/cpp/webengine/main.o +/scripts/testbrowser/cpp/webengine/testbrowser +/scripts/testbrowser/cpp/webengine/.qmake.stash /scripts/dev/pylint_checkers/qute_pylint.egg-info diff --git a/scripts/testbrowser_cpp/webengine/main.cpp b/scripts/testbrowser/cpp/webengine/main.cpp similarity index 100% rename from scripts/testbrowser_cpp/webengine/main.cpp rename to scripts/testbrowser/cpp/webengine/main.cpp diff --git a/scripts/testbrowser_cpp/webengine/testbrowser.pro b/scripts/testbrowser/cpp/webengine/testbrowser.pro similarity index 100% rename from scripts/testbrowser_cpp/webengine/testbrowser.pro rename to scripts/testbrowser/cpp/webengine/testbrowser.pro diff --git a/scripts/testbrowser_cpp/webkit/main.cpp b/scripts/testbrowser/cpp/webkit/main.cpp similarity index 100% rename from scripts/testbrowser_cpp/webkit/main.cpp rename to scripts/testbrowser/cpp/webkit/main.cpp diff --git a/scripts/testbrowser_cpp/webkit/testbrowser.pro b/scripts/testbrowser/cpp/webkit/testbrowser.pro similarity index 100% rename from scripts/testbrowser_cpp/webkit/testbrowser.pro rename to scripts/testbrowser/cpp/webkit/testbrowser.pro diff --git a/scripts/testbrowser/testbrowser_webengine.py b/scripts/testbrowser/testbrowser_webengine.py new file mode 100755 index 000000000..e6353dc23 --- /dev/null +++ b/scripts/testbrowser/testbrowser_webengine.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2014-2017 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser 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. +# +# qutebrowser 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 qutebrowser. If not, see . + +"""Very simple browser for testing purposes.""" + +import sys +import argparse + +from PyQt5.QtCore import QUrl +from PyQt5.QtWidgets import QApplication +from PyQt5.QtWebEngineWidgets import QWebEngineView + + +def parse_args(): + """Parse commandline arguments.""" + parser = argparse.ArgumentParser() + parser.add_argument('url', help='The URL to open') + return parser.parse_known_args()[0] + + +if __name__ == '__main__': + args = parse_args() + app = QApplication(sys.argv) + wv = QWebEngineView() + + wv.loadStarted.connect(lambda: print("Loading started")) + wv.loadProgress.connect(lambda p: print("Loading progress: {}%".format(p))) + wv.loadFinished.connect(lambda: print("Loading finished")) + + wv.load(QUrl.fromUserInput(args.url)) + wv.show() + + app.exec_() diff --git a/scripts/testbrowser/testbrowser_webkit.py b/scripts/testbrowser/testbrowser_webkit.py new file mode 100755 index 000000000..7c7081f18 --- /dev/null +++ b/scripts/testbrowser/testbrowser_webkit.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2014-2017 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser 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. +# +# qutebrowser 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 qutebrowser. If not, see . + +"""Very simple browser for testing purposes.""" + +import sys +import argparse + +from PyQt5.QtCore import QUrl +from PyQt5.QtWidgets import QApplication +from PyQt5.QtWebKit import QWebSettings +from PyQt5.QtWebKitWidgets import QWebView + + +def parse_args(): + """Parse commandline arguments.""" + parser = argparse.ArgumentParser() + parser.add_argument('url', help='The URL to open') + parser.add_argument('--plugins', '-p', help='Enable plugins', + default=False, action='store_true') + return parser.parse_known_args()[0] + + +if __name__ == '__main__': + args = parse_args() + app = QApplication(sys.argv) + wv = QWebView() + + wv.loadStarted.connect(lambda: print("Loading started")) + wv.loadProgress.connect(lambda p: print("Loading progress: {}%".format(p))) + wv.loadFinished.connect(lambda: print("Loading finished")) + + if args.plugins: + wv.settings().setAttribute(QWebSettings.PluginsEnabled, True) + + wv.load(QUrl.fromUserInput(args.url)) + wv.show() + + app.exec_() From e7af961be243ff443cd118a1683650180e66f1ca Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 29 Dec 2017 19:36:52 +0100 Subject: [PATCH 045/574] Remove filtering of mouse events This was needed for the hide-mouse-cursor setting. However, this setting was removed in 2223a285ef4a49adabe735d558db9ab7b65ff78a, so this code has been dead since then. --- qutebrowser/app.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/qutebrowser/app.py b/qutebrowser/app.py index a2d768923..e3d06391d 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -872,10 +872,6 @@ class EventFilter(QObject): super().__init__(parent) self._activated = True self._handlers = { - QEvent.MouseButtonDblClick: self._handle_mouse_event, - QEvent.MouseButtonPress: self._handle_mouse_event, - QEvent.MouseButtonRelease: self._handle_mouse_event, - QEvent.MouseMove: self._handle_mouse_event, QEvent.KeyPress: self._handle_key_event, QEvent.KeyRelease: self._handle_key_event, } @@ -900,19 +896,6 @@ class EventFilter(QObject): # No window available yet, or not a MainWindow return False - def _handle_mouse_event(self, _event): - """Handle a mouse event. - - Args: - _event: The QEvent which is about to be delivered. - - Return: - True if the event should be filtered, False if it's passed through. - """ - # Mouse cursor shown (overrideCursor None) -> don't filter event - # Mouse cursor hidden (overrideCursor not None) -> filter event - return qApp.overrideCursor() is not None - def eventFilter(self, obj, event): """Handle an event. From 28889cf099091a8fb261019bad33c77ef306dbca Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 29 Dec 2017 20:36:55 +0100 Subject: [PATCH 046/574] Use a dict for ModeManager.eventFilter --- qutebrowser/keyinput/modeman.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/qutebrowser/keyinput/modeman.py b/qutebrowser/keyinput/modeman.py index ad9bd06ee..b8c46476f 100644 --- a/qutebrowser/keyinput/modeman.py +++ b/qutebrowser/keyinput/modeman.py @@ -322,10 +322,13 @@ class ModeManager(QObject): if self.mode is None: # We got events before mode is set, so just pass them through. return False - if event.type() == QEvent.KeyPress: - return self._eventFilter_keypress(event) - else: - return self._eventFilter_keyrelease(event) + + handlers = { + QEvent.KeyPress: self._eventFilter_keypress, + QEvent.KeyRelease: self._eventFilter_keyrelease, + } + handler = handlers[event.type()] + return handler(event) @cmdutils.register(instance='mode-manager', scope='window') def clear_keychain(self): From 25436e2544d8224e3422efb7952180e732de122e Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Sat, 30 Dec 2017 09:43:16 +0600 Subject: [PATCH 047/574] Fix eslint warnings --- qutebrowser/javascript/webengine_caret.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qutebrowser/javascript/webengine_caret.js b/qutebrowser/javascript/webengine_caret.js index e7075cd33..001afa8a7 100644 --- a/qutebrowser/javascript/webengine_caret.js +++ b/qutebrowser/javascript/webengine_caret.js @@ -1,3 +1,4 @@ +// eslint-disable-line max-lines /** * Copyright 2016-2017 Florian Bruhin (The Compiler) * @@ -23,7 +24,7 @@ * change document selection model and div caret position. */ -"use strict"; // eslint-disable-line max-lines +"use strict"; window._qutebrowser.caret = (function() { // eslint-disable-line max-statements,max-len function isElementInViewport(node) { // eslint-disable-line complexity From 981f5fd09b93a194f2e768697e6d260dfa078ece Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Sat, 30 Dec 2017 23:20:29 +0600 Subject: [PATCH 048/574] Remove unused import --- tests/end2end/features/test_caret_bdd.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/end2end/features/test_caret_bdd.py b/tests/end2end/features/test_caret_bdd.py index ee6cda82c..abd1821d8 100644 --- a/tests/end2end/features/test_caret_bdd.py +++ b/tests/end2end/features/test_caret_bdd.py @@ -17,8 +17,6 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=unused-import -import pytest import pytest_bdd as bdd from end2end.features.test_yankpaste_bdd import init_fake_clipboard From f5edd4941e9f1bf5e42d3b88eb770777a32fb6a6 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 Dec 2017 18:33:15 +0100 Subject: [PATCH 049/574] Fix MANIFEST.in for testbrowser --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 54bb613f3..b20c2bc77 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -23,7 +23,7 @@ include qutebrowser/config/configdata.yml prune www prune scripts/dev -prune scripts/testbrowser_cpp +prune scripts/testbrowser/cpp prune .github exclude scripts/asciidoc2html.py exclude doc/notes From 6dc31087477e496d3be9b4cf8fc7d6b81adb994b Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Sat, 30 Dec 2017 23:35:12 +0600 Subject: [PATCH 050/574] Get OS name using python --- qutebrowser/browser/webengine/webenginetab.py | 3 ++- qutebrowser/javascript/webengine_caret.js | 15 ++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index b816e8f2a..42cbc3d2a 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -21,6 +21,7 @@ import math import functools +import platform import html as html_utils import sip @@ -202,7 +203,7 @@ class WebEngineCaret(browsertab.AbstractCaret): @pyqtSlot(usertypes.KeyMode) def _on_mode_entered(self, mode): self._tab.run_js_async( - javascript.assemble('caret', 'setInitialCursor')) + javascript.assemble('caret', 'setInitialCursor', platform.platform())) @pyqtSlot(usertypes.KeyMode) def _on_mode_left(self): diff --git a/qutebrowser/javascript/webengine_caret.js b/qutebrowser/javascript/webengine_caret.js index 001afa8a7..89eb9969f 100644 --- a/qutebrowser/javascript/webengine_caret.js +++ b/qutebrowser/javascript/webengine_caret.js @@ -494,9 +494,6 @@ window._qutebrowser.caret = (function() { // eslint-disable-line max-statements, CaretBrowsing.blinkFlag = true; - CaretBrowsing.isWindows = - window.navigator.userAgent.indexOf("Windows") !== -1; - CaretBrowsing.isControlThatNeedsArrowKeys = function(node) { // eslint-disable-line complexity,max-len if (!node) { return false; @@ -590,9 +587,9 @@ window._qutebrowser.caret = (function() { // eslint-disable-line max-statements, document.body.appendChild(node); }; - CaretBrowsing.setInitialCursor = function() { - const sel = window.getSelection(); - if (sel.rangeCount > 0) { + CaretBrowsing.setInitialCursor = function(platform) { + CaretBrowsing.isWindows = platform === "Windows"; + if (window.getSelection().rangeCount > 0) { return; } @@ -960,7 +957,7 @@ window._qutebrowser.caret = (function() { // eslint-disable-line max-statements, CaretBrowsing.isCaretVisible = (CaretBrowsing.isEnabled && CaretBrowsing.isWindowFocused); if (CaretBrowsing.isCaretVisible && !CaretBrowsing.caretElement) { - CaretBrowsing.setInitialCursor(); + CaretBrowsing.setInitialCursor(CaretBrowsing.isWindows); CaretBrowsing.updateCaretOrSelection(true); if (CaretBrowsing.caretElement) { CaretBrowsing.blinkFunctionId = window.setInterval( @@ -1012,9 +1009,9 @@ window._qutebrowser.caret = (function() { // eslint-disable-line max-statements, const funcs = {}; - funcs.setInitialCursor = () => { + funcs.setInitialCursor = (platform) => { if (!CaretBrowsing.initiated) { - CaretBrowsing.setInitialCursor(); + CaretBrowsing.setInitialCursor(platform); return; } From fe4eb19ecfa43badf9c39cdeebff1ddbe0a38058 Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Sat, 30 Dec 2017 23:37:17 +0600 Subject: [PATCH 051/574] Add link to chrome-caretbrowsing extension --- qutebrowser/javascript/webengine_caret.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qutebrowser/javascript/webengine_caret.js b/qutebrowser/javascript/webengine_caret.js index 89eb9969f..9e217fe36 100644 --- a/qutebrowser/javascript/webengine_caret.js +++ b/qutebrowser/javascript/webengine_caret.js @@ -20,6 +20,8 @@ /** * Ported chrome-caretbrowsing extension. + * https://cs.chromium.org/chromium/src/ui/accessibility/extensions/caretbrowsing/ + * * Create and control div caret, which listen commands from qutebrowser, * change document selection model and div caret position. */ From e22dc1b5c6cd8720fde7bfd60762988a157c196a Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Sat, 30 Dec 2017 23:37:57 +0600 Subject: [PATCH 052/574] Update copyright year --- qutebrowser/javascript/webengine_caret.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/javascript/webengine_caret.js b/qutebrowser/javascript/webengine_caret.js index 9e217fe36..99f6bd76a 100644 --- a/qutebrowser/javascript/webengine_caret.js +++ b/qutebrowser/javascript/webengine_caret.js @@ -1,6 +1,6 @@ // eslint-disable-line max-lines /** - * Copyright 2016-2017 Florian Bruhin (The Compiler) + * Copyright 2018 Florian Bruhin (The Compiler) * * This file is part of qutebrowser. * From 695f7341429b2b4e68b8aeb08051363f0261af82 Mon Sep 17 00:00:00 2001 From: Artur Shaikhullin Date: Sat, 30 Dec 2017 23:46:04 +0600 Subject: [PATCH 053/574] Extract js call method --- qutebrowser/browser/webengine/webenginetab.py | 58 +++++++------------ 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 42cbc3d2a..38a16b323 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -208,87 +208,69 @@ class WebEngineCaret(browsertab.AbstractCaret): @pyqtSlot(usertypes.KeyMode) def _on_mode_left(self): self.drop_selection() - self._tab.run_js_async( - javascript.assemble('caret', 'toggle')) + self._js_call('toggle') def move_to_next_line(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveDown')) + self._js_call('moveDown') def move_to_prev_line(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveUp')) + self._js_call('moveUp') def move_to_next_char(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveRight')) + self._js_call('moveRight') def move_to_prev_char(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveLeft')) + self._js_call('moveLeft') def move_to_end_of_word(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToEndOfWord')) + self._js_call('moveToEndOfWord') def move_to_next_word(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToNextWord')) + self._js_call('moveToNextWord') def move_to_prev_word(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToPreviousWord')) + self._js_call('moveToPreviousWord') def move_to_start_of_line(self): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToStartOfLine')) + self._js_call('moveToStartOfLine') def move_to_end_of_line(self): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToEndOfLine')) + self._js_call('moveToEndOfLine') def move_to_start_of_next_block(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToStartOfNextBlock')) + self._js_call('moveToStartOfNextBlock') def move_to_start_of_prev_block(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToStartOfPrevBlock')) + self._js_call('moveToStartOfPrevBlock') def move_to_end_of_next_block(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToEndOfNextBlock')) + self._js_call('moveToEndOfNextBlock') def move_to_end_of_prev_block(self, count=1): for _ in range(count): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToEndOfPrevBlock')) + self._js_call('moveToEndOfPrevBlock') def move_to_start_of_document(self): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToStartOfDocument')) + self._js_call('moveToStartOfDocument') def move_to_end_of_document(self): - self._tab.run_js_async( - javascript.assemble('caret', 'moveToEndOfDocument')) + self._js_call('moveToEndOfDocument') def toggle_selection(self): - self._tab.run_js_async( - javascript.assemble('caret', 'toggleSelection')) + self._js_call('toggleSelection') def drop_selection(self): - self._tab.run_js_async( - javascript.assemble('caret', 'dropSelection')) + self._js_call('dropSelection') def has_selection(self): if qtutils.version_check('5.10'): @@ -351,6 +333,10 @@ class WebEngineCaret(browsertab.AbstractCaret): self._tab.run_js_async(js_code, lambda jsret: self._follow_selected_cb(jsret, tab)) + def _js_call(self, command): + self._tab.run_js_async( + javascript.assemble('caret', command)) + class WebEngineScroller(browsertab.AbstractScroller): From e989d948edd81a7e6afd45592fe6764d35124ae0 Mon Sep 17 00:00:00 2001 From: Slackhead Date: Sun, 31 Dec 2017 14:47:42 +0000 Subject: [PATCH 054/574] Add cycle-inputs.js to userscripts --- misc/userscripts/cycle-inputs.js | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 misc/userscripts/cycle-inputs.js diff --git a/misc/userscripts/cycle-inputs.js b/misc/userscripts/cycle-inputs.js new file mode 100644 index 000000000..c395f6de2 --- /dev/null +++ b/misc/userscripts/cycle-inputs.js @@ -0,0 +1,43 @@ +/* Cycle text boxes. + * works with the types defined in 'types'. + * Note: Does not work for