From 10977ccb07e9dac2e839eaa6cce3f1c3c56b7361 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Sat, 19 Feb 2022 11:15:06 +0000 Subject: [PATCH 1/3] Prevent plugin widget code issues from breaking theme changes This adds a try/except around a bunch of .configure() calls on widgets. Yes, sure, this could then leave the widget in question in a broken state, but at least our entire UI won't fall flat on its face. --- theme.py | 105 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 44 deletions(-) diff --git a/theme.py b/theme.py index 8515bfbb..eea1072a 100644 --- a/theme.py +++ b/theme.py @@ -14,6 +14,9 @@ from tkinter import ttk from config import config from ttkHyperlinkLabel import HyperlinkLabel +from EDMCLogging import get_main_logger + +logger = get_main_logger() if __debug__: from traceback import print_exc @@ -266,50 +269,64 @@ class _Theme(object): widget.winfo_class(), widget, 'text' in widget.keys() and widget['text']) attribs = self.widgets.get(widget, []) - if isinstance(widget, tk.BitmapImage): - # not a widget - if 'fg' not in attribs: - widget.configure(foreground=self.current['foreground']), - if 'bg' not in attribs: - widget.configure(background=self.current['background']) - elif 'cursor' in widget.keys() and str(widget['cursor']) not in ['', 'arrow']: - # Hack - highlight widgets like HyperlinkLabel with a non-default cursor - if 'fg' not in attribs: - widget.configure(foreground=self.current['highlight']), - if 'insertbackground' in widget.keys(): # tk.Entry - widget.configure(insertbackground=self.current['foreground']), - if 'bg' not in attribs: - widget.configure(background=self.current['background']) - if 'highlightbackground' in widget.keys(): # tk.Entry - widget.configure(highlightbackground=self.current['background']) - if 'font' not in attribs: - widget.configure(font=self.current['font']) - elif 'activeforeground' in widget.keys(): - # e.g. tk.Button, tk.Label, tk.Menu - if 'fg' not in attribs: - widget.configure(foreground=self.current['foreground'], - activeforeground=self.current['activeforeground'], - disabledforeground=self.current['disabledforeground']) - if 'bg' not in attribs: - widget.configure(background=self.current['background'], - activebackground=self.current['activebackground']) - if sys.platform == 'darwin' and isinstance(widget, tk.Button): - widget.configure(highlightbackground=self.current['background']) - if 'font' not in attribs: - widget.configure(font=self.current['font']) - elif 'foreground' in widget.keys(): - # e.g. ttk.Label - if 'fg' not in attribs: - widget.configure(foreground=self.current['foreground']), - if 'bg' not in attribs: - widget.configure(background=self.current['background']) - if 'font' not in attribs: - widget.configure(font=self.current['font']) - elif 'background' in widget.keys() or isinstance(widget, tk.Canvas): - # e.g. Frame, Canvas - if 'bg' not in attribs: - widget.configure(background=self.current['background'], - highlightbackground=self.current['disabledforeground']) + try: + if isinstance(widget, tk.BitmapImage): + # not a widget + if 'fg' not in attribs: + widget.configure(foreground=self.current['foreground']), + + if 'bg' not in attribs: + widget.configure(background=self.current['background']) + + elif 'cursor' in widget.keys() and str(widget['cursor']) not in ['', 'arrow']: + # Hack - highlight widgets like HyperlinkLabel with a non-default cursor + if 'fg' not in attribs: + widget.configure(foreground=self.current['highlight']), + if 'insertbackground' in widget.keys(): # tk.Entry + widget.configure(insertbackground=self.current['foreground']), + + if 'bg' not in attribs: + widget.configure(background=self.current['background']) + if 'highlightbackground' in widget.keys(): # tk.Entry + widget.configure(highlightbackground=self.current['background']) + + if 'font' not in attribs: + widget.configure(font=self.current['font']) + + elif 'activeforeground' in widget.keys(): + # e.g. tk.Button, tk.Label, tk.Menu + if 'fg' not in attribs: + widget.configure(foreground=self.current['foreground'], + activeforeground=self.current['activeforeground'], + disabledforeground=self.current['disabledforeground']) + + if 'bg' not in attribs: + widget.configure(background=self.current['background'], + activebackground=self.current['activebackground']) + if sys.platform == 'darwin' and isinstance(widget, tk.Button): + widget.configure(highlightbackground=self.current['background']) + + if 'font' not in attribs: + widget.configure(font=self.current['font']) + elif 'foreground' in widget.keys(): + # e.g. ttk.Label + if 'fg' not in attribs: + widget.configure(foreground=self.current['foreground']), + + if 'bg' not in attribs: + widget.configure(background=self.current['background']) + + if 'font' not in attribs: + widget.configure(font=self.current['font']) + + elif 'background' in widget.keys() or isinstance(widget, tk.Canvas): + # e.g. Frame, Canvas + if 'bg' not in attribs: + widget.configure(background=self.current['background'], + highlightbackground=self.current['disabledforeground']) + + except Exception: + logger.exception('Plugin widget issue ?') # Apply configured theme From 17530c2d2b56e13939f0a710d72d45dbb32b7d26 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Sat, 19 Feb 2022 11:48:27 +0000 Subject: [PATCH 2/3] theme.py: Log widget if exception is thrown --- theme.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme.py b/theme.py index eea1072a..ce9318bd 100644 --- a/theme.py +++ b/theme.py @@ -326,7 +326,7 @@ class _Theme(object): highlightbackground=self.current['disabledforeground']) except Exception: - logger.exception('Plugin widget issue ?') + logger.exception(f'Plugin widget issue ? {widget=}') # Apply configured theme From 520ff5868fddd339c10a80800c242f6ef8ff3cc4 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Sun, 20 Feb 2022 19:05:41 +0000 Subject: [PATCH 3/3] theme.py: Apply .configure() paranoia on button enter/leave --- theme.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/theme.py b/theme.py index ce9318bd..4f60f976 100644 --- a/theme.py +++ b/theme.py @@ -195,17 +195,35 @@ class _Theme(object): def _enter(self, event, image): widget = event.widget if widget and widget['state'] != tk.DISABLED: - widget.configure(state=tk.ACTIVE) + try: + widget.configure(state=tk.ACTIVE) + + except Exception: + logger.exception(f'Failure setting widget active: {widget=}') + if image: - image.configure(foreground=self.current['activeforeground'], - background=self.current['activebackground']) + try: + image.configure(foreground=self.current['activeforeground'], + background=self.current['activebackground']) + + except Exception: + logger.exception(f'Failure configuring image: {image=}') def _leave(self, event, image): widget = event.widget if widget and widget['state'] != tk.DISABLED: - widget.configure(state=tk.NORMAL) + try: + widget.configure(state=tk.NORMAL) + + except Exception: + logger.exception(f'Failure setting widget normal: {widget=}') + if image: - image.configure(foreground=self.current['foreground'], background=self.current['background']) + try: + image.configure(foreground=self.current['foreground'], background=self.current['background']) + + except Exception: + logger.exception(f'Failure configuring image: {image=}') # Set up colors def _colors(self, root, theme):