{"action":"created","comment":{"url":"https://api.github.com/repos/pybee/toga/pulls/comments/154552631","pull_request_review_id":80730651,"id":154552631,"diff_hunk":"@@ -66,3 +68,78 @@ def evaluate(self, javascript):\n         :type  javascript: ``str``\n         \"\"\"\n         return self.native.stringByEvaluatingJavaScriptFromString(javascript)\n+\n+\n+if \"WKWebView\" in vars():\n+    class TogaWKWebView(WKWebView):\n+        @objc_method\n+        def webView_didFinish_(self, navi):\n+            if self.interface.on_webview_load:\n+            self.interface.on_webview_load(self.interface)\n+\n+        @objc_method\n+        def acceptsFirstResponder(self) -> bool:\n+            return True\n+\n+        @objc_method\n+        def keyDown_(self, event) -> None:\n+            print('in keyDown', event.keyCode)\n+            if self.interface.on_key_down:\n+                self.interface.on_key_down(event.keyCode, event.modifierFlags)\n+\n+        @objc_method\n+        def touchBar(self):\n+            # Disable the touchbar.\n+            return None\n+\n+    class WebKit2WebView(Widget):\n+        def create(self):\n+            self.native = TogaWKWebView.alloc().init()\n+            self.native.interface = self.interface\n+\n+            self.native.uiDelegate = self.native\n+            self.native.navigationDelegate = self.native\n+\n+            self.add_constraints()\n+\n+        def get_dom(self):\n+            return self.evaluate(\n+                'document.getElementsByTagName(\"html\")[0].outerHTML')\n+\n+        def set_url(self, value):\n+            if value:\n+                self.interface.url = value\n+\n+            request = NSURLRequest.requestWithURL(NSURL.URLWithString(\n+                self.interface.url))\n+            self.native.load(request)\n+\n+        def set_content(self, root_url, content):\n+            self.native.loadHTMLString_baseURL_(\n+                content, NSURL.URLWithString(root_url))\n+\n+        def set_user_agent(self, value):\n+            self.native.customUserAgent = value\n+\n+        def evaluate(self, js_str):\n+            fur = Future()  # type: concurrent.futures.Future\n+\n+            def when_finish(result, err):\n+                if fur.done():\n+                    return\n+\n+                if err:\n+                    fur.set_exception(err)\n+\n+                else:\n+                    fur.set_result(result)\n+\n+            self.native.evaluateJavaScript_completionHandler_(\n+                js_str, when_finish)\n+\n+            return fur","path":"src/cocoa/toga_cocoa/widgets/webview.py","position":91,"original_position":91,"commit_id":"3f864d18777e3a1cf6c59e48b4c38b7d57d0819b","original_commit_id":"3f864d18777e3a1cf6c59e48b4c38b7d57d0819b","user":{"login":"futursolo","id":11693215,"avatar_url":"https://avatars0.githubusercontent.com/u/11693215?v=4","gravatar_id":"","url":"https://api.github.com/users/futursolo","html_url":"https://github.com/futursolo","followers_url":"https://api.github.com/users/futursolo/followers","following_url":"https://api.github.com/users/futursolo/following{/other_user}","gists_url":"https://api.github.com/users/futursolo/gists{/gist_id}","starred_url":"https://api.github.com/users/futursolo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/futursolo/subscriptions","organizations_url":"https://api.github.com/users/futursolo/orgs","repos_url":"https://api.github.com/users/futursolo/repos","events_url":"https://api.github.com/users/futursolo/events{/privacy}","received_events_url":"https://api.github.com/users/futursolo/received_events","type":"User","site_admin":false},"body":"@freakboy3742 Unfortunately, this is the truth when using `asyncio`. Asynchrony must be explicit. You idea is actually making the asynchrony implicit. The only library that I know deals well with that is `gevent`. However, it requires monkey patching, which I will definitely avoid. \r\n\r\n@ncoghlan \r\n1. No. `fur.result()` blocks the entire thread, including the event loop. It is just a simple dead lock if you are trying to use it. The only reason that I use it is because that I don't have to use `loop.call_soon_threadsafe` for `asyncio.Future`.\r\n2. `asyncio.Future` is awaitable. You can just return an future object(This is not to be confused with `concurrent.futures.Future`.) from `WKWebView.evaluate()`. If you don't want the result, do not `await` it.\r\n3. `asyncio` is not thread safe, and you have to create `WKWebView` on the UI thread. So...\r\n\r\n`concurrent.futures.Future` works with threads, so `fur.result()` will block the thread to wait the result(sending from the other threads).\r\n\r\nHowever, `asyncio.Future` works with coroutines, so it will not block the thread when calling `fur.result()` and it will raise an error to prevent the thread from being blocked. You should use `await` to block the current coroutine instead of the thread.\r\n\r\nUsing `asyncio.Future` here is definitely a better choice. I was thinking about thread safety at that point of time and now it seems a little bit silly. ","created_at":"2017-12-04T03:14:54Z","updated_at":"2017-12-04T03:14:54Z","html_url":"https://github.com/pybee/toga/pull/296#discussion_r154552631","pull_request_url":"https://api.github.com/repos/pybee/toga/pulls/296","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/pybee/toga/pulls/comments/154552631"},"html":{"href":"https://github.com/pybee/toga/pull/296#discussion_r154552631"},"pull_request":{"href":"https://api.github.com/repos/pybee/toga/pulls/296"}},"in_reply_to_id":154487289},"pull_request":{"url":"https://api.github.com/repos/pybee/toga/pulls/296","id":155976517,"html_url":"https://github.com/pybee/toga/pull/296","diff_url":"https://github.com/pybee/toga/pull/296.diff","patch_url":"https://github.com/pybee/toga/pull/296.patch","issue_url":"https://api.github.com/repos/pybee/toga/issues/296","number":296,"state":"open","locked":false,"title":"[WIP] Switch WebView implementation for iOS & Cocoa from WebKit1(WebView/UIWebView) to WebKit2(WKWebView).","user":{"login":"futursolo","id":11693215,"avatar_url":"https://avatars0.githubusercontent.com/u/11693215?v=4","gravatar_id":"","url":"https://api.github.com/users/futursolo","html_url":"https://github.com/futursolo","followers_url":"https://api.github.com/users/futursolo/followers","following_url":"https://api.github.com/users/futursolo/following{/other_user}","gists_url":"https://api.github.com/users/futursolo/gists{/gist_id}","starred_url":"https://api.github.com/users/futursolo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/futursolo/subscriptions","organizations_url":"https://api.github.com/users/futursolo/orgs","repos_url":"https://api.github.com/users/futursolo/repos","events_url":"https://api.github.com/users/futursolo/events{/privacy}","received_events_url":"https://api.github.com/users/futursolo/received_events","type":"User","site_admin":false},"body":"The new WKWebView is a new and unified API across macOS and iOS based on WebKit2 aiming to replace the existing WebView and UIWebView which both are based on WebKit1.\r\n\r\nThe main advantage is that it splits UI process and web processes and isolates different web pages into different processes, which makes it more stable and will not affect the UI process and the other web pages when one web process crashes.\r\n\r\nHowever, UI process and web processes communicate via IPC, which means `evaluate` and `get_dom` will not return instantly and result in breaking API changes.\r\n\r\nIn addition, I haven't tested it yet as I am stilling working on it.\r\n\r\nSee: https://trac.webkit.org/wiki/WebKit2","created_at":"2017-12-01T22:59:13Z","updated_at":"2017-12-04T03:14:54Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4f0f8ac7f757f2a1863755a1ae5c18fec0256eda","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/pybee/toga/pulls/296/commits","review_comments_url":"https://api.github.com/repos/pybee/toga/pulls/296/comments","review_comment_url":"https://api.github.com/repos/pybee/toga/pulls/comments{/number}","comments_url":"https://api.github.com/repos/pybee/toga/issues/296/comments","statuses_url":"https://api.github.com/repos/pybee/toga/statuses/3f864d18777e3a1cf6c59e48b4c38b7d57d0819b","head":{"label":"futursolo:wkwebview","ref":"wkwebview","sha":"3f864d18777e3a1cf6c59e48b4c38b7d57d0819b","user":{"login":"futursolo","id":11693215,"avatar_url":"https://avatars0.githubusercontent.com/u/11693215?v=4","gravatar_id":"","url":"https://api.github.com/users/futursolo","html_url":"https://github.com/futursolo","followers_url":"https://api.github.com/users/futursolo/followers","following_url":"https://api.github.com/users/futursolo/following{/other_user}","gists_url":"https://api.github.com/users/futursolo/gists{/gist_id}","starred_url":"https://api.github.com/users/futursolo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/futursolo/subscriptions","organizations_url":"https://api.github.com/users/futursolo/orgs","repos_url":"https://api.github.com/users/futursolo/repos","events_url":"https://api.github.com/users/futursolo/events{/privacy}","received_events_url":"https://api.github.com/users/futursolo/received_events","type":"User","site_admin":false},"repo":{"id":112686576,"name":"toga","full_name":"futursolo/toga","owner":{"login":"futursolo","id":11693215,"avatar_url":"https://avatars0.githubusercontent.com/u/11693215?v=4","gravatar_id":"","url":"https://api.github.com/users/futursolo","html_url":"https://github.com/futursolo","followers_url":"https://api.github.com/users/futursolo/followers","following_url":"https://api.github.com/users/futursolo/following{/other_user}","gists_url":"https://api.github.com/users/futursolo/gists{/gist_id}","starred_url":"https://api.github.com/users/futursolo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/futursolo/subscriptions","organizations_url":"https://api.github.com/users/futursolo/orgs","repos_url":"https://api.github.com/users/futursolo/repos","events_url":"https://api.github.com/users/futursolo/events{/privacy}","received_events_url":"https://api.github.com/users/futursolo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/futursolo/toga","description":"A Python native, OS native GUI toolkit.","fork":true,"url":"https://api.github.com/repos/futursolo/toga","forks_url":"https://api.github.com/repos/futursolo/toga/forks","keys_url":"https://api.github.com/repos/futursolo/toga/keys{/key_id}","collaborators_url":"https://api.github.com/repos/futursolo/toga/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/futursolo/toga/teams","hooks_url":"https://api.github.com/repos/futursolo/toga/hooks","issue_events_url":"https://api.github.com/repos/futursolo/toga/issues/events{/number}","events_url":"https://api.github.com/repos/futursolo/toga/events","assignees_url":"https://api.github.com/repos/futursolo/toga/assignees{/user}","branches_url":"https://api.github.com/repos/futursolo/toga/branches{/branch}","tags_url":"https://api.github.com/repos/futursolo/toga/tags","blobs_url":"https://api.github.com/repos/futursolo/toga/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/futursolo/toga/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/futursolo/toga/git/refs{/sha}","trees_url":"https://api.github.com/repos/futursolo/toga/git/trees{/sha}","statuses_url":"https://api.github.com/repos/futursolo/toga/statuses/{sha}","languages_url":"https://api.github.com/repos/futursolo/toga/languages","stargazers_url":"https://api.github.com/repos/futursolo/toga/stargazers","contributors_url":"https://api.github.com/repos/futursolo/toga/contributors","subscribers_url":"https://api.github.com/repos/futursolo/toga/subscribers","subscription_url":"https://api.github.com/repos/futursolo/toga/subscription","commits_url":"https://api.github.com/repos/futursolo/toga/commits{/sha}","git_commits_url":"https://api.github.com/repos/futursolo/toga/git/commits{/sha}","comments_url":"https://api.github.com/repos/futursolo/toga/comments{/number}","issue_comment_url":"https://api.github.com/repos/futursolo/toga/issues/comments{/number}","contents_url":"https://api.github.com/repos/futursolo/toga/contents/{+path}","compare_url":"https://api.github.com/repos/futursolo/toga/compare/{base}...{head}","merges_url":"https://api.github.com/repos/futursolo/toga/merges","archive_url":"https://api.github.com/repos/futursolo/toga/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/futursolo/toga/downloads","issues_url":"https://api.github.com/repos/futursolo/toga/issues{/number}","pulls_url":"https://api.github.com/repos/futursolo/toga/pulls{/number}","milestones_url":"https://api.github.com/repos/futursolo/toga/milestones{/number}","notifications_url":"https://api.github.com/repos/futursolo/toga/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/futursolo/toga/labels{/name}","releases_url":"https://api.github.com/repos/futursolo/toga/releases{/id}","deployments_url":"https://api.github.com/repos/futursolo/toga/deployments","created_at":"2017-12-01T02:42:55Z","updated_at":"2017-12-01T02:42:57Z","pushed_at":"2017-12-01T04:36:02Z","git_url":"git://github.com/futursolo/toga.git","ssh_url":"git@github.com:futursolo/toga.git","clone_url":"https://github.com/futursolo/toga.git","svn_url":"https://github.com/futursolo/toga","homepage":"https://toga.readthedocs.io/en/latest/","size":4353,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"pybee:master","ref":"master","sha":"ddb5acd4f0d97cb3fb4cb59e8aaa2c445b4571e4","user":{"login":"pybee","id":5001767,"avatar_url":"https://avatars0.githubusercontent.com/u/5001767?v=4","gravatar_id":"","url":"https://api.github.com/users/pybee","html_url":"https://github.com/pybee","followers_url":"https://api.github.com/users/pybee/followers","following_url":"https://api.github.com/users/pybee/following{/other_user}","gists_url":"https://api.github.com/users/pybee/gists{/gist_id}","starred_url":"https://api.github.com/users/pybee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pybee/subscriptions","organizations_url":"https://api.github.com/users/pybee/orgs","repos_url":"https://api.github.com/users/pybee/repos","events_url":"https://api.github.com/users/pybee/events{/privacy}","received_events_url":"https://api.github.com/users/pybee/received_events","type":"Organization","site_admin":false},"repo":{"id":22529973,"name":"toga","full_name":"pybee/toga","owner":{"login":"pybee","id":5001767,"avatar_url":"https://avatars0.githubusercontent.com/u/5001767?v=4","gravatar_id":"","url":"https://api.github.com/users/pybee","html_url":"https://github.com/pybee","followers_url":"https://api.github.com/users/pybee/followers","following_url":"https://api.github.com/users/pybee/following{/other_user}","gists_url":"https://api.github.com/users/pybee/gists{/gist_id}","starred_url":"https://api.github.com/users/pybee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pybee/subscriptions","organizations_url":"https://api.github.com/users/pybee/orgs","repos_url":"https://api.github.com/users/pybee/repos","events_url":"https://api.github.com/users/pybee/events{/privacy}","received_events_url":"https://api.github.com/users/pybee/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pybee/toga","description":"A Python native, OS native GUI toolkit.","fork":false,"url":"https://api.github.com/repos/pybee/toga","forks_url":"https://api.github.com/repos/pybee/toga/forks","keys_url":"https://api.github.com/repos/pybee/toga/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pybee/toga/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pybee/toga/teams","hooks_url":"https://api.github.com/repos/pybee/toga/hooks","issue_events_url":"https://api.github.com/repos/pybee/toga/issues/events{/number}","events_url":"https://api.github.com/repos/pybee/toga/events","assignees_url":"https://api.github.com/repos/pybee/toga/assignees{/user}","branches_url":"https://api.github.com/repos/pybee/toga/branches{/branch}","tags_url":"https://api.github.com/repos/pybee/toga/tags","blobs_url":"https://api.github.com/repos/pybee/toga/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pybee/toga/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pybee/toga/git/refs{/sha}","trees_url":"https://api.github.com/repos/pybee/toga/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pybee/toga/statuses/{sha}","languages_url":"https://api.github.com/repos/pybee/toga/languages","stargazers_url":"https://api.github.com/repos/pybee/toga/stargazers","contributors_url":"https://api.github.com/repos/pybee/toga/contributors","subscribers_url":"https://api.github.com/repos/pybee/toga/subscribers","subscription_url":"https://api.github.com/repos/pybee/toga/subscription","commits_url":"https://api.github.com/repos/pybee/toga/commits{/sha}","git_commits_url":"https://api.github.com/repos/pybee/toga/git/commits{/sha}","comments_url":"https://api.github.com/repos/pybee/toga/comments{/number}","issue_comment_url":"https://api.github.com/repos/pybee/toga/issues/comments{/number}","contents_url":"https://api.github.com/repos/pybee/toga/contents/{+path}","compare_url":"https://api.github.com/repos/pybee/toga/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pybee/toga/merges","archive_url":"https://api.github.com/repos/pybee/toga/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pybee/toga/downloads","issues_url":"https://api.github.com/repos/pybee/toga/issues{/number}","pulls_url":"https://api.github.com/repos/pybee/toga/pulls{/number}","milestones_url":"https://api.github.com/repos/pybee/toga/milestones{/number}","notifications_url":"https://api.github.com/repos/pybee/toga/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pybee/toga/labels{/name}","releases_url":"https://api.github.com/repos/pybee/toga/releases{/id}","deployments_url":"https://api.github.com/repos/pybee/toga/deployments","created_at":"2014-08-01T21:44:10Z","updated_at":"2017-12-03T04:45:36Z","pushed_at":"2017-12-03T20:55:01Z","git_url":"git://github.com/pybee/toga.git","ssh_url":"git@github.com:pybee/toga.git","clone_url":"https://github.com/pybee/toga.git","svn_url":"https://github.com/pybee/toga","homepage":"https://toga.readthedocs.io/en/latest/","size":4366,"stargazers_count":1326,"watchers_count":1326,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":148,"mirror_url":null,"archived":false,"open_issues_count":58,"license":{"key":"bsd-3-clause","name":"BSD 3-clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause"},"forks":148,"open_issues":58,"watchers":1326,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/pybee/toga/pulls/296"},"html":{"href":"https://github.com/pybee/toga/pull/296"},"issue":{"href":"https://api.github.com/repos/pybee/toga/issues/296"},"comments":{"href":"https://api.github.com/repos/pybee/toga/issues/296/comments"},"review_comments":{"href":"https://api.github.com/repos/pybee/toga/pulls/296/comments"},"review_comment":{"href":"https://api.github.com/repos/pybee/toga/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/pybee/toga/pulls/296/commits"},"statuses":{"href":"https://api.github.com/repos/pybee/toga/statuses/3f864d18777e3a1cf6c59e48b4c38b7d57d0819b"}},"author_association":"NONE"}}
{"actor":{"display_login":"futursolo"}}