[pygobject] gtk-demo: Avoid crash in CSS demos



commit 2ef59b89311529e34366d4d7aa8f8ae9a8ea6371
Author: Simon Feltman <sfeltman src gnome org>
Date:   Tue Dec 31 13:41:20 2013 -0800

    gtk-demo: Avoid crash in CSS demos
    
    Avoid a potential crash in the CSS demos where the text editing buffer is
    out of sync with the last good CSS parsing buffer. In the case of CSS
    warnings, we get a parsing-error callback but no exception is raised.
    This would cause the buffers to become out of sync and accessing position
    information from the parsing-error section would crash the text editor due
    to an out of range iterator being created.

 demos/gtk-demo/demos/Css/css_basics.py      |   31 ++++++++++++++++++++-------
 demos/gtk-demo/demos/Css/css_multiplebgs.py |   31 ++++++++++++++++++++-------
 2 files changed, 46 insertions(+), 16 deletions(-)
---
diff --git a/demos/gtk-demo/demos/Css/css_basics.py b/demos/gtk-demo/demos/Css/css_basics.py
index bd3f873..18c3d12 100644
--- a/demos/gtk-demo/demos/Css/css_basics.py
+++ b/demos/gtk-demo/demos/Css/css_basics.py
@@ -32,7 +32,13 @@ from gi.repository import Gtk, Gdk, Pango, Gio, GLib
 class CSSBasicsApp:
     def __init__(self, demoapp):
         self.demoapp = demoapp
+        #: Store the last successful parsing of the css so we can revert
+        #: this in case of an error.
         self.last_good_text = ''
+        #: Set when we receive a parsing-error callback. This is needed
+        #: to handle logic after a parsing-error callback which does not raise
+        #: an exception with provider.load_from_data()
+        self.last_error_code = 0
 
         self.window = Gtk.Window()
         self.window.set_title('CSS Basics')
@@ -86,12 +92,14 @@ class CSSBasicsApp:
         end = buffer.get_iter_at_line_index(section.get_end_line(),
                                             section.get_end_position())
 
-        if error:
-            tag_name = "error"
-            self.infolabel.set_text(error.message)
-            self.infobar.show_all()
-        else:
+        if error.code == Gtk.CssProviderError.DEPRECATED:
             tag_name = "warning"
+        else:
+            tag_name = "error"
+        self.last_error_code = error.code
+
+        self.infolabel.set_text(error.message)
+        self.infobar.show_all()
 
         buffer.apply_tag_by_name(tag_name, start, end)
 
@@ -106,10 +114,17 @@ class CSSBasicsApp:
         try:
             provider.load_from_data(text)
         except GLib.GError as e:
-            if e.domain == 'gtk-css-provider-error-quark':
-                provider.load_from_data(self.last_good_text)
-            else:
+            if e.domain != 'gtk-css-provider-error-quark':
                 raise e
+
+        # If the parsing-error callback is ever run (even in the case of warnings)
+        # load the last good css text that ran without any warnings. Otherwise
+        # we may have a discrepancy in "last_good_text" vs the current buffer
+        # causing section.get_start_position() to give back an invalid position
+        # for the editor buffer.
+        if self.last_error_code:
+            provider.load_from_data(self.last_good_text)
+            self.last_error_code = 0
         else:
             self.last_good_text = text
             self.infobar.hide()
diff --git a/demos/gtk-demo/demos/Css/css_multiplebgs.py b/demos/gtk-demo/demos/Css/css_multiplebgs.py
index 803c853..9e1b011 100644
--- a/demos/gtk-demo/demos/Css/css_multiplebgs.py
+++ b/demos/gtk-demo/demos/Css/css_multiplebgs.py
@@ -31,7 +31,13 @@ from gi.repository import Gtk, Gdk, Pango, Gio, GLib
 class CSSMultiplebgsApp:
     def __init__(self, demoapp):
         self.demoapp = demoapp
+        #: Store the last successful parsing of the css so we can revert
+        #: this in case of an error.
         self.last_good_text = ''
+        #: Set when we receive a parsing-error callback. This is needed
+        #: to handle logic after a parsing-error callback which does not raise
+        #: an exception with provider.load_from_data()
+        self.last_error_code = 0
 
         self.window = Gtk.Window()
         self.window.set_title('CSS Multiplebgs')
@@ -124,12 +130,14 @@ class CSSMultiplebgsApp:
         end = buffer.get_iter_at_line_index(section.get_end_line(),
                                             section.get_end_position())
 
-        if error:
-            tag_name = "error"
-            self.infolabel.set_text(error.message)
-            self.infobar.show_all()
-        else:
+        if error.code == Gtk.CssProviderError.DEPRECATED:
             tag_name = "warning"
+        else:
+            tag_name = "error"
+        self.last_error_code = error.code
+
+        self.infolabel.set_text(error.message)
+        self.infobar.show_all()
 
         buffer.apply_tag_by_name(tag_name, start, end)
 
@@ -144,10 +152,17 @@ class CSSMultiplebgsApp:
         try:
             provider.load_from_data(text)
         except GLib.GError as e:
-            if e.domain == 'gtk-css-provider-error-quark':
-                provider.load_from_data(self.last_good_text)
-            else:
+            if e.domain != 'gtk-css-provider-error-quark':
                 raise e
+
+        # If the parsing-error callback is ever run (even in the case of warnings)
+        # load the last good css text that ran without any warnings. Otherwise
+        # we may have a discrepancy in "last_good_text" vs the current buffer
+        # causing section.get_start_position() to give back an invalid position
+        # for the editor buffer.
+        if self.last_error_code:
+            provider.load_from_data(self.last_good_text)
+            self.last_error_code = 0
         else:
             self.last_good_text = text
             self.infobar.hide()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]