tkinterweb 4.17.1__tar.gz → 4.17.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tkinterweb-4.17.1/tkinterweb.egg-info → tkinterweb-4.17.3}/PKG-INFO +1 -1
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/setup.py +1 -1
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/bindings.py +13 -11
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/handlers.py +43 -40
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/htmlwidgets.py +12 -6
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/utilities.py +9 -8
- {tkinterweb-4.17.1 → tkinterweb-4.17.3/tkinterweb.egg-info}/PKG-INFO +1 -1
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/LICENSE.md +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/MANIFEST.in +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/README.md +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/setup.cfg +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/__init__.py +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/dom.py +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/extensions.py +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/imageutils.py +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/js.py +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/resources/combobox-2.3.tm +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/resources/pkgIndex.tcl +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb/subwidgets.py +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb.egg-info/SOURCES.txt +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb.egg-info/dependency_links.txt +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb.egg-info/requires.txt +0 -0
- {tkinterweb-4.17.1 → tkinterweb-4.17.3}/tkinterweb.egg-info/top_level.txt +0 -0
|
@@ -532,13 +532,13 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
532
532
|
self.queue_after = None
|
|
533
533
|
self.queue = None
|
|
534
534
|
|
|
535
|
-
def post_to_queue(self, callback):
|
|
535
|
+
def post_to_queue(self, callback, thread_safe=True):
|
|
536
536
|
"""Use this method to send a callback to TkinterWeb's thread-safety queue. The callback will be evaluated on the main thread.
|
|
537
537
|
Use this when running Tkinter commands from within a thread.
|
|
538
538
|
If the queue is not running (i.e. threading is disabled), the callback will be evaluated immediately.
|
|
539
539
|
|
|
540
540
|
New in version 4.9."""
|
|
541
|
-
if self.queue:
|
|
541
|
+
if thread_safe and self.queue:
|
|
542
542
|
self.queue.put(callback)
|
|
543
543
|
else:
|
|
544
544
|
callback()
|
|
@@ -546,6 +546,7 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
546
546
|
def post_event(self, event, thread_safe=False):
|
|
547
547
|
"Generate a virtual event."
|
|
548
548
|
# NOTE: when thread_safe=True, this method is thread-safe
|
|
549
|
+
# Would you believe that?
|
|
549
550
|
if not self.events_enabled:
|
|
550
551
|
return
|
|
551
552
|
|
|
@@ -565,6 +566,7 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
565
566
|
def post_message(self, message, thread_safe=False):
|
|
566
567
|
"Post a message."
|
|
567
568
|
# NOTE: when thread_safe=True, this method is thread-safe
|
|
569
|
+
# Amazing stuff, eh?
|
|
568
570
|
if not self.messages_enabled:
|
|
569
571
|
return
|
|
570
572
|
|
|
@@ -722,20 +724,20 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
722
724
|
else:
|
|
723
725
|
return utilities.cache_download(url, *args, insecure=self.insecure_https, cafile=self.ssl_cafile, headers=tuple(self.headers.items()), timeout=self.request_timeout)
|
|
724
726
|
|
|
725
|
-
def _thread_check(self, callback, *args, **kwargs):
|
|
727
|
+
def _thread_check(self, callback, url, *args, **kwargs):
|
|
726
728
|
if not self.downloads_have_occured:
|
|
727
729
|
self.downloads_have_occured = True
|
|
728
730
|
|
|
729
|
-
if not self.threading_enabled:
|
|
730
|
-
callback(*args, **kwargs)
|
|
731
|
+
if not self.threading_enabled or url.startswith("file://"):
|
|
732
|
+
callback(url, *args, **kwargs)
|
|
731
733
|
elif len(self.active_threads) >= self.maximum_thread_count:
|
|
732
|
-
self.after(500, lambda callback=callback, args=args: self._thread_check(callback, *args, **kwargs))
|
|
734
|
+
self.after(500, lambda callback=callback, url=url, args=args: self._thread_check(callback, url, *args, **kwargs))
|
|
733
735
|
else:
|
|
734
|
-
thread = utilities.StoppableThread(target=callback, args=args, kwargs=kwargs)
|
|
736
|
+
thread = utilities.StoppableThread(target=callback, args=(url, *args,), kwargs=kwargs)
|
|
735
737
|
thread.start()
|
|
736
738
|
|
|
737
739
|
def _begin_download(self):
|
|
738
|
-
# NOTE: this
|
|
740
|
+
# NOTE: this runs in a thread
|
|
739
741
|
|
|
740
742
|
thread = utilities.get_current_thread()
|
|
741
743
|
self.active_threads.append(thread)
|
|
@@ -743,13 +745,13 @@ It is likely that not all dependencies are installed. Make sure Cairo is install
|
|
|
743
745
|
return thread
|
|
744
746
|
|
|
745
747
|
def _finish_download(self, thread):
|
|
746
|
-
# NOTE: this
|
|
748
|
+
# NOTE: this runs in a thread
|
|
747
749
|
|
|
748
750
|
self.active_threads.remove(thread)
|
|
749
751
|
if len(self.active_threads) == 0:
|
|
750
|
-
self.post_to_queue(self._handle_load_finish)
|
|
752
|
+
self.post_to_queue(self._handle_load_finish, thread.is_subthread)
|
|
751
753
|
else:
|
|
752
|
-
self.post_to_queue(lambda: self._handle_load_finish(False))
|
|
754
|
+
self.post_to_queue(lambda: self._handle_load_finish(False), thread.is_subthread)
|
|
753
755
|
|
|
754
756
|
def _finish_resource_load(self, message, url, resource, success):
|
|
755
757
|
# NOTE: this must run in the main thread
|
|
@@ -471,7 +471,7 @@ class ScriptManager(utilities.BaseManager):
|
|
|
471
471
|
attributes = dict(zip(attributes[::2], attributes[1::2])) # Make attributes a dict
|
|
472
472
|
|
|
473
473
|
if "src" in attributes:
|
|
474
|
-
self.html._thread_check(self.fetch_scripts,
|
|
474
|
+
self.html._thread_check(self.fetch_scripts, self.html.resolve_url(attributes["src"]), attributes)
|
|
475
475
|
elif "defer" in attributes:
|
|
476
476
|
self.pending_scripts.append((attributes, tag_contents))
|
|
477
477
|
else:
|
|
@@ -479,27 +479,27 @@ class ScriptManager(utilities.BaseManager):
|
|
|
479
479
|
|
|
480
480
|
def fetch_scripts(self, attributes, url=None, data=None):
|
|
481
481
|
"Fetch and run scripts"
|
|
482
|
-
# NOTE: this
|
|
482
|
+
# NOTE: this runs in a thread
|
|
483
483
|
|
|
484
484
|
thread = self.html._begin_download()
|
|
485
485
|
|
|
486
486
|
if url and thread.isrunning():
|
|
487
|
-
self.html.post_message(f"Fetching script from {utilities.shorten(url)}",
|
|
487
|
+
self.html.post_message(f"Fetching script from {utilities.shorten(url)}", thread.is_subthread)
|
|
488
488
|
try:
|
|
489
489
|
data = self.html.download_url(url)[1]
|
|
490
490
|
except Exception as error:
|
|
491
491
|
self.html.post_to_queue(lambda message=f"ERROR: could not load script {url}: {error}",
|
|
492
|
-
url=url: self.html._finish_resource_load(message, url, "script", False))
|
|
492
|
+
url=url: self.html._finish_resource_load(message, url, "script", False), thread.is_subthread)
|
|
493
493
|
|
|
494
494
|
if data and thread.isrunning():
|
|
495
495
|
if "defer" in attributes:
|
|
496
496
|
self.pending_scripts.append((attributes, data))
|
|
497
497
|
else:
|
|
498
|
-
self.html.post_to_queue(lambda attributes=attributes, data=data: self.html.on_script(attributes, data))
|
|
498
|
+
self.html.post_to_queue(lambda attributes=attributes, data=data: self.html.on_script(attributes, data), thread.is_subthread)
|
|
499
499
|
|
|
500
500
|
if url:
|
|
501
501
|
self.html.post_to_queue(lambda message=f"Successfully loaded {utilities.shorten(url)}",
|
|
502
|
-
url=url: self.html._finish_resource_load(message, url, "script", True))
|
|
502
|
+
url=url: self.html._finish_resource_load(message, url, "script", True), thread.is_subthread)
|
|
503
503
|
|
|
504
504
|
self.html._finish_download(thread)
|
|
505
505
|
|
|
@@ -520,7 +520,7 @@ class StyleManager(utilities.BaseManager):
|
|
|
520
520
|
|
|
521
521
|
def _on_style(self, attributes, tag_contents):
|
|
522
522
|
"Handle <style> elements."
|
|
523
|
-
self.
|
|
523
|
+
self._finish_fetching_styles(data=tag_contents)
|
|
524
524
|
|
|
525
525
|
def _on_link(self, node):
|
|
526
526
|
"Handle <link> elements."
|
|
@@ -532,11 +532,9 @@ class StyleManager(utilities.BaseManager):
|
|
|
532
532
|
except tk.TclError:
|
|
533
533
|
return
|
|
534
534
|
|
|
535
|
-
if (
|
|
536
|
-
("
|
|
537
|
-
|
|
538
|
-
):
|
|
539
|
-
self.html._thread_check(self.fetch_styles, node, url)
|
|
535
|
+
if (("stylesheet" in rel)
|
|
536
|
+
and ("all" in media or "screen" in media)):
|
|
537
|
+
self.html._thread_check(self.fetch_styles, url, node)
|
|
540
538
|
# Onload is fired if and when the stylesheet is parsed
|
|
541
539
|
elif "icon" in rel:
|
|
542
540
|
self.html.icon = url
|
|
@@ -550,8 +548,7 @@ class StyleManager(utilities.BaseManager):
|
|
|
550
548
|
try:
|
|
551
549
|
new_url = self.html.resolve_url(new_url, parent_url)
|
|
552
550
|
self.html.post_message(f"Loading stylesheet from {utilities.shorten(new_url)}")
|
|
553
|
-
|
|
554
|
-
self.html._thread_check(self.fetch_styles, url=new_url)
|
|
551
|
+
self.html._thread_check(self.fetch_styles, new_url)
|
|
555
552
|
|
|
556
553
|
except Exception as error:
|
|
557
554
|
self.html.post_message(f"ERROR: could not load stylesheet {new_url}: {error}")
|
|
@@ -564,25 +561,25 @@ class StyleManager(utilities.BaseManager):
|
|
|
564
561
|
newurl = f"url('{newurl}')"
|
|
565
562
|
return newurl
|
|
566
563
|
|
|
567
|
-
def fetch_styles(self,
|
|
564
|
+
def fetch_styles(self, url=None, node=None):
|
|
568
565
|
"Fetch stylesheets and parse the CSS code they contain"
|
|
569
|
-
# NOTE: this
|
|
566
|
+
# NOTE: this runs in a thread
|
|
570
567
|
|
|
571
568
|
thread = self.html._begin_download()
|
|
572
569
|
if url and thread.isrunning():
|
|
573
|
-
self.html.post_message(f"Fetching stylesheet from {utilities.shorten(url)}",
|
|
570
|
+
self.html.post_message(f"Fetching stylesheet from {utilities.shorten(url)}", thread.is_subthread)
|
|
574
571
|
try:
|
|
575
572
|
data = self.html.download_url(url)[1]
|
|
573
|
+
if data and thread.isrunning():
|
|
574
|
+
self.html.post_to_queue(lambda node=node, url=url, data=data: self._finish_fetching_styles(node, url, data), thread.is_subthread)
|
|
575
|
+
|
|
576
576
|
except Exception as error:
|
|
577
577
|
self.html.post_to_queue(lambda message=f"ERROR: could not load stylesheet {url}: {error}",
|
|
578
|
-
url=url: self.html._finish_resource_load(message, url, "stylesheet", False))
|
|
579
|
-
|
|
580
|
-
if data and thread.isrunning():
|
|
581
|
-
self.html.post_to_queue(lambda node=node, url=url, data=data: self._finish_fetching_styles(node, url, data))
|
|
578
|
+
url=url: self.html._finish_resource_load(message, url, "stylesheet", False), thread.is_subthread)
|
|
582
579
|
|
|
583
580
|
self.html._finish_download(thread)
|
|
584
581
|
|
|
585
|
-
def _finish_fetching_styles(self, node, url, data):
|
|
582
|
+
def _finish_fetching_styles(self, node=None, url=None, data=None):
|
|
586
583
|
# NOTE: this must run in the main thread
|
|
587
584
|
|
|
588
585
|
self.html._style_count += 1
|
|
@@ -648,7 +645,7 @@ class ImageManager(utilities.BaseManager):
|
|
|
648
645
|
self.bad_paths.add(url)
|
|
649
646
|
|
|
650
647
|
if not self.html.ignore_invalid_images:
|
|
651
|
-
image, data_is_image = self.check_images(utilities.BROKEN_IMAGE, name, url, "image/png")
|
|
648
|
+
image, data_is_image = self.check_images(utilities.BROKEN_IMAGE, name, url, "image/png", False)
|
|
652
649
|
image = imageutils.data_to_image(image, name, "image/png", data_is_image)
|
|
653
650
|
|
|
654
651
|
self.loaded_images.setdefault(name, set()).add(image)
|
|
@@ -695,29 +692,32 @@ class ImageManager(utilities.BaseManager):
|
|
|
695
692
|
|
|
696
693
|
def fetch_images(self, url, name):
|
|
697
694
|
"Fetch images and display them in the document."
|
|
698
|
-
# NOTE: this
|
|
695
|
+
# NOTE: this runs in a thread
|
|
699
696
|
|
|
700
697
|
thread = self.html._begin_download()
|
|
701
698
|
if thread.isrunning():
|
|
702
|
-
self.html.post_message(f"Fetching image from {utilities.shorten(url)}",
|
|
699
|
+
self.html.post_message(f"Fetching image from {utilities.shorten(url)}", thread.is_subthread)
|
|
703
700
|
|
|
704
701
|
if url == self.html.base_url:
|
|
705
|
-
self.html.post_to_queue(lambda url=url, name=name, error="ERROR: image url not specified":
|
|
702
|
+
self.html.post_to_queue(lambda url=url, name=name, error="ERROR: image url not specified":
|
|
703
|
+
self._on_image_error(url, name, error), thread.is_subthread)
|
|
706
704
|
else:
|
|
707
705
|
try:
|
|
708
706
|
url, data, filetype, code = self.html.download_url(url)
|
|
709
|
-
data, data_is_image = self.check_images(data, name, url, filetype)
|
|
707
|
+
data, data_is_image = self.check_images(data, name, url, filetype, thread.is_subthread)
|
|
710
708
|
|
|
711
709
|
if thread.isrunning():
|
|
712
|
-
self.html.post_to_queue(lambda data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image:
|
|
710
|
+
self.html.post_to_queue(lambda data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image:
|
|
711
|
+
self.finish_fetching_images(data, name, url, filetype, data_is_image), thread.is_subthread)
|
|
713
712
|
except Exception as error:
|
|
714
|
-
self.html.post_to_queue(lambda url=url, name=name, error=f"ERROR: could not load image {url}: {error}":
|
|
713
|
+
self.html.post_to_queue(lambda url=url, name=name, error=f"ERROR: could not load image {url}: {error}":
|
|
714
|
+
self._on_image_error(url, name, error), thread.is_subthread)
|
|
715
715
|
|
|
716
716
|
self.html._finish_download(thread)
|
|
717
717
|
|
|
718
|
-
def check_images(self, data, name, url, filetype):
|
|
718
|
+
def check_images(self, data, name, url, filetype, thread_safe):
|
|
719
719
|
"Invert images if needed and convert SVG images to PNGs."
|
|
720
|
-
# NOTE: this
|
|
720
|
+
# NOTE: this runs in a thread
|
|
721
721
|
|
|
722
722
|
data_is_image = False
|
|
723
723
|
if "svg" in filetype:
|
|
@@ -732,7 +732,7 @@ class ImageManager(utilities.BaseManager):
|
|
|
732
732
|
data_is_image = True
|
|
733
733
|
except (ImportError, ModuleNotFoundError,):
|
|
734
734
|
error = f"ERROR: could not invert the image {url}: PIL and PIL.ImageTk must be installed."
|
|
735
|
-
self.html.post_to_queue(lambda url=url, name=name, error=error: self._on_image_error(url, name, error))
|
|
735
|
+
self.html.post_to_queue(lambda url=url, name=name, error=error: self._on_image_error(url, name, error), thread_safe)
|
|
736
736
|
|
|
737
737
|
return data, data_is_image
|
|
738
738
|
|
|
@@ -887,7 +887,7 @@ class ObjectManager(utilities.BaseManager):
|
|
|
887
887
|
return
|
|
888
888
|
|
|
889
889
|
self.html.post_message(f"Creating object from {utilities.shorten(data)}")
|
|
890
|
-
self.html._thread_check(self.fetch_objects,
|
|
890
|
+
self.html._thread_check(self.fetch_objects, data, node)
|
|
891
891
|
|
|
892
892
|
def _on_object_value_change(self, node, attribute, value):
|
|
893
893
|
if attribute == "data":
|
|
@@ -898,10 +898,11 @@ class ObjectManager(utilities.BaseManager):
|
|
|
898
898
|
# Force reset because it might contain widgets that are added internally
|
|
899
899
|
self.html.widget_manager.map_node(node, True)
|
|
900
900
|
|
|
901
|
-
def fetch_objects(self,
|
|
902
|
-
# NOTE: this
|
|
901
|
+
def fetch_objects(self, url, node):
|
|
902
|
+
# NOTE: this runs in a thread
|
|
903
903
|
|
|
904
904
|
thread = self.html._begin_download()
|
|
905
|
+
|
|
905
906
|
if thread.isrunning():
|
|
906
907
|
try:
|
|
907
908
|
url, data, filetype, code = self.html.download_url(url)
|
|
@@ -909,10 +910,12 @@ class ObjectManager(utilities.BaseManager):
|
|
|
909
910
|
if data and thread.isrunning():
|
|
910
911
|
if filetype.startswith("image"):
|
|
911
912
|
name = self.html.image_manager.allocate_image_name()
|
|
912
|
-
data, data_is_image = self.html.image_manager.check_images(data, name, url, filetype)
|
|
913
|
-
self.html.post_to_queue(lambda node=node, data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image:
|
|
913
|
+
data, data_is_image = self.html.image_manager.check_images(data, name, url, filetype, thread.is_subthread)
|
|
914
|
+
self.html.post_to_queue(lambda node=node, data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image:
|
|
915
|
+
self._finish_fetching_image_objects(node, data, name, url, filetype, data_is_image), thread.is_subthread)
|
|
914
916
|
elif filetype == "text/html":
|
|
915
|
-
self.html.post_to_queue(lambda node=node, data=data,
|
|
917
|
+
self.html.post_to_queue(lambda node=node, data=data, url=url, filetype=filetype:
|
|
918
|
+
self._finish_fetching_HTML_objects(node, data, url, filetype), thread.is_subthread)
|
|
916
919
|
|
|
917
920
|
except Exception as error:
|
|
918
921
|
self.html.post_message(f"ERROR: could not load object element with data {url}: {error}", True)
|
|
@@ -920,9 +923,9 @@ class ObjectManager(utilities.BaseManager):
|
|
|
920
923
|
self.html._finish_download(thread)
|
|
921
924
|
|
|
922
925
|
def _finish_fetching_image_objects(self, node, data, name, url, filetype, data_is_image):
|
|
923
|
-
# NOTE: this must run in the main thread
|
|
926
|
+
# NOTE: this must run in the main thread
|
|
924
927
|
|
|
925
|
-
image = self.html.image_manager.finish_fetching_images(
|
|
928
|
+
image = self.html.image_manager.finish_fetching_images(data, name, filetype, url, data_is_image)
|
|
926
929
|
self.html.override_node_properties(node, "-tkhtml-replacement-image", f"url({image})")
|
|
927
930
|
self.html.event_manager.post_element_event(node, "onload", None, utilities.ELEMENT_LOADED_EVENT)
|
|
928
931
|
|
|
@@ -437,7 +437,7 @@ class HtmlFrame(Frame):
|
|
|
437
437
|
file_url = "file://" + str(file_url)
|
|
438
438
|
self._current_url = file_url
|
|
439
439
|
self._html.post_event(utilities.URL_CHANGED_EVENT)
|
|
440
|
-
self.
|
|
440
|
+
self.load_url(file_url, decode, force)
|
|
441
441
|
|
|
442
442
|
def load_website(self, website_url, decode=None, force=False):
|
|
443
443
|
"""Convenience method to load a website.
|
|
@@ -482,7 +482,8 @@ class HtmlFrame(Frame):
|
|
|
482
482
|
|
|
483
483
|
if self._thread_in_progress:
|
|
484
484
|
self._thread_in_progress.stop()
|
|
485
|
-
|
|
485
|
+
|
|
486
|
+
if self._html.threading_enabled and not url.startswith("file://"):
|
|
486
487
|
thread = utilities.StoppableThread(target=self._continue_loading, args=(
|
|
487
488
|
url,), kwargs={"decode": decode, "force": force, "thread_safe": True})
|
|
488
489
|
self._thread_in_progress = thread
|
|
@@ -1131,6 +1132,9 @@ class HtmlFrame(Frame):
|
|
|
1131
1132
|
|
|
1132
1133
|
if self.unshrink:
|
|
1133
1134
|
if event.x and self._prev_configure != (event.width, event.x):
|
|
1135
|
+
# if not self._html.using_tkhtml30:
|
|
1136
|
+
# self._html.configure(textwrap=False)
|
|
1137
|
+
# self.after(10, lambda: self._html.configure(textwrap=True))
|
|
1134
1138
|
self.after_idle(lambda: self._html.configure(
|
|
1135
1139
|
width=self.winfo_screenwidth(),
|
|
1136
1140
|
height=event.height)
|
|
@@ -1183,7 +1187,7 @@ class HtmlFrame(Frame):
|
|
|
1183
1187
|
|
|
1184
1188
|
def _continue_loading(self, url, data="", method="GET", decode=None, force=False, thread_safe=False):
|
|
1185
1189
|
"Finish loading urls and handle URI fragments."
|
|
1186
|
-
# NOTE: this
|
|
1190
|
+
# NOTE: this runs in a thread
|
|
1187
1191
|
|
|
1188
1192
|
code = 404
|
|
1189
1193
|
self._current_url = url
|
|
@@ -1219,6 +1223,8 @@ class HtmlFrame(Frame):
|
|
|
1219
1223
|
url = url.replace("view-source:", "")
|
|
1220
1224
|
parsed = urlparse(url)
|
|
1221
1225
|
|
|
1226
|
+
thread = utilities.get_current_thread()
|
|
1227
|
+
|
|
1222
1228
|
location = parsed.netloc if parsed.netloc else parsed.path
|
|
1223
1229
|
self._html.post_message(f"Connecting to {location}", True)
|
|
1224
1230
|
if self._html.insecure_https: self._html.post_message("WARNING: Using insecure HTTPS session", True)
|
|
@@ -1226,7 +1232,7 @@ class HtmlFrame(Frame):
|
|
|
1226
1232
|
newurl, data, filetype, code = self._html.download_url(url, data, method, decode)
|
|
1227
1233
|
self._html.post_message(f"Successfully connected to {location}", True)
|
|
1228
1234
|
|
|
1229
|
-
if
|
|
1235
|
+
if thread.isrunning():
|
|
1230
1236
|
if view_source:
|
|
1231
1237
|
newurl = "view-source:"+newurl
|
|
1232
1238
|
if self._current_url != newurl:
|
|
@@ -1246,7 +1252,7 @@ class HtmlFrame(Frame):
|
|
|
1246
1252
|
elif "image" in filetype:
|
|
1247
1253
|
name = self._html.image_manager.allocate_image_name()
|
|
1248
1254
|
if name:
|
|
1249
|
-
data, data_is_image = self._html.image_manager.check_images(data, name, url, filetype)
|
|
1255
|
+
data, data_is_image = self._html.image_manager.check_images(data, name, url, filetype, thread.is_subthread)
|
|
1250
1256
|
self._html.post_to_queue(lambda data=data, name=name, url=url, filetype=filetype, data_is_image=data_is_image: self._finish_loading_image(data, name, url, filetype, data_is_image))
|
|
1251
1257
|
else:
|
|
1252
1258
|
self.load_html(self._get_about_page("about:image", name), newurl, _thread_safe=thread_safe)
|
|
@@ -1271,7 +1277,7 @@ class HtmlFrame(Frame):
|
|
|
1271
1277
|
if self._current_url != url:
|
|
1272
1278
|
self._html.post_event(utilities.URL_CHANGED_EVENT)
|
|
1273
1279
|
text = self._get_about_page("about:image", name)
|
|
1274
|
-
self._html.image_manager.finish_fetching_images(
|
|
1280
|
+
self._html.image_manager.finish_fetching_images(data, name, url, filetype, data_is_image)
|
|
1275
1281
|
self.load_html(text, url)
|
|
1276
1282
|
|
|
1277
1283
|
def _finish_loading_nothing(self):
|
|
@@ -31,7 +31,7 @@ __title__ = "TkinterWeb"
|
|
|
31
31
|
__author__ = "Andrew Clarke"
|
|
32
32
|
__copyright__ = "(c) 2021-2025 Andrew Clarke"
|
|
33
33
|
__license__ = "MIT"
|
|
34
|
-
__version__ = "4.17.
|
|
34
|
+
__version__ = "4.17.3"
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
ROOT_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "resources")
|
|
@@ -686,6 +686,8 @@ class StoppableThread(threading.Thread):
|
|
|
686
686
|
self.daemon = True
|
|
687
687
|
self.running = True
|
|
688
688
|
|
|
689
|
+
self.is_subthread = True
|
|
690
|
+
|
|
689
691
|
def stop(self):
|
|
690
692
|
self.running = False
|
|
691
693
|
|
|
@@ -697,6 +699,9 @@ class PlaceholderThread:
|
|
|
697
699
|
"""Fake StoppableThread. The only purpose of this is to provide fake methods that mirror the StoppableThread class.
|
|
698
700
|
This means that if a download is running in the MainThread, the stop flags can still be set without raising errors, though they won't do anything."""
|
|
699
701
|
|
|
702
|
+
def __init__(self, *args, **kwargs):
|
|
703
|
+
self.is_subthread = False
|
|
704
|
+
|
|
700
705
|
def stop(self):
|
|
701
706
|
return
|
|
702
707
|
|
|
@@ -855,14 +860,11 @@ def download(url, data=None, method="GET", decode=None, insecure=False, cafile=N
|
|
|
855
860
|
parsed = urlparse(url)
|
|
856
861
|
url = urlunparse(parsed._replace(query=""))
|
|
857
862
|
|
|
858
|
-
thread = get_current_thread()
|
|
859
863
|
url = url.replace(" ", "%20")
|
|
860
864
|
if data and (method == "POST"):
|
|
861
865
|
req = Request(url, data, headers=dict(headers))
|
|
862
866
|
else:
|
|
863
867
|
req = Request(url, headers=dict(headers))
|
|
864
|
-
if not thread.isrunning():
|
|
865
|
-
return None, url, "", ""
|
|
866
868
|
|
|
867
869
|
with urlopen(req, context=context, timeout=timeout) as res:
|
|
868
870
|
data = res.read()
|
|
@@ -893,10 +895,8 @@ def download(url, data=None, method="GET", decode=None, insecure=False, cafile=N
|
|
|
893
895
|
data = data.decode(decode, errors="ignore")
|
|
894
896
|
else:
|
|
895
897
|
data = data.decode(errors="ignore")
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
else:
|
|
899
|
-
return url, data, filetype, code
|
|
898
|
+
|
|
899
|
+
return url, data, filetype, code
|
|
900
900
|
|
|
901
901
|
|
|
902
902
|
@lru_cache()
|
|
@@ -915,6 +915,7 @@ def shorten(string):
|
|
|
915
915
|
def get_current_thread():
|
|
916
916
|
"Return the currently running thread"
|
|
917
917
|
thread = threading.current_thread()
|
|
918
|
+
# Py 3.4+: Use is threading.main_thread()
|
|
918
919
|
if thread.name == "MainThread":
|
|
919
920
|
thread = PlaceholderThread()
|
|
920
921
|
return thread
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|