Further revisions to the patches to cleanup the screenshot behavior in
Sugar.  Effects are as stated previously:

On Fri, Sep 05, 2008 at 01:31:54AM -0300, Erik Garrison wrote:
>   before, screenshots taken on these events:
>     - frame visibility
>     - tabbing start
>     - activity next tab
>     - activity previous tab
>     - zoom into activity view
>     - activity close (twice)
>
>   after, screenshots taken on these events:
>     - activity close (once)
>     - activity keep / save

 ... but I have resolved an issue noted by Eben:

    "I still think this is going to be doing the wrong thing about half
the time, as long as there is no check to be sure that the activity is
visible at the time the screenshot is taken. (There also seems to be no
avoiding the fact that the Frame will be in many of them...) I'd rather
have no preview than an incorrect one."  (quoted by C. Scott @
http://dev.laptop.org/ticket/8432)

I resolved this issue by adding functionality to the Activity class
defined in activity.py which processes visibility-notify-events from X
and sets a flag Activity._visibible to True when the window is in any
state but fully obscured.  This state is publicly accessible via
Activity.is_visible().

NB. I wanted to use the gtk.gdk.VISIBILITY_UNOBSCURED to trigger this,
as it would guarantee that the frame is not in the way of the window
when the screenshot is taken, but found that this inhibited taking the
screenshot if there was a palette of any kind drawn over top of the root
Activity window.

Comments?  Please test.  This is an 8.2 target (Greg has tagged it
'polish').

Erik
diff --git a/src/view/Shell.py b/src/view/Shell.py
index bfaa72e..30ccd5c 100644
--- a/src/view/Shell.py
+++ b/src/view/Shell.py
@@ -191,8 +191,6 @@ class Shell(gobject.GObject):
         if level == self._model.get_zoom_level():
             return
 
-        self.take_activity_screenshot()
-
         if level == shellmodel.ShellModel.ZOOM_ACTIVITY:
             host = self.get_current_activity()
             if host is not None:
@@ -209,7 +207,6 @@ class Shell(gobject.GObject):
         home_model = self._model.get_home()
         previous_activity = home_model.get_previous_activity()
         if previous_activity:
-            self.take_activity_screenshot()
             previous_activity.get_window().activate(
 						gtk.get_current_event_time())
 
@@ -217,7 +214,6 @@ class Shell(gobject.GObject):
         home_model = self._model.get_home()
         next_activity = home_model.get_next_activity()
         if next_activity:
-            self.take_activity_screenshot()
             next_activity.get_window().activate(gtk.get_current_event_time())
 
     def close_current_activity(self):
@@ -229,7 +225,6 @@ class Shell(gobject.GObject):
         if active_activity.is_journal():
             return
 
-        self.take_activity_screenshot()
         self.get_current_activity().close()
 
     def get_current_activity(self):
diff --git a/src/view/frame/frame.py b/src/view/frame/frame.py
index 6009e7f..c3f0de9 100644
--- a/src/view/frame/frame.py
+++ b/src/view/frame/frame.py
@@ -146,8 +146,6 @@ class Frame(object):
         if self._animator:
             self._animator.stop()
 
-        view.Shell.get_instance().take_activity_screenshot()
-
         self.mode = mode
 
         self._animator = animator.Animator(0.5)
diff --git a/src/view/tabbinghandler.py b/src/view/tabbinghandler.py
index 03ce275..e3153b0 100644
--- a/src/view/tabbinghandler.py
+++ b/src/view/tabbinghandler.py
@@ -58,7 +58,6 @@ class TabbingHandler(object):
                 self._tabbing = False
             else:
                 shell = view.Shell.get_instance()
-                shell.take_activity_screenshot()
                 
                 self._frame.show(self._frame.MODE_NON_INTERACTIVE)
 
diff --git a/src/sugar/activity/activity.py b/src/sugar/activity/activity.py
index f34553d..a2bcea0 100644
--- a/src/sugar/activity/activity.py
+++ b/src/sugar/activity/activity.py
@@ -174,7 +174,6 @@ class ActivityToolbar(gtk.Toolbar):
         self._activity.copy()
 
     def __stop_clicked_cb(self, button):
-        self._activity.take_screenshot()
         self._activity.close()
 
     def __jobject_updated_cb(self, jobject):
@@ -467,6 +466,12 @@ class Activity(Window, gtk.Container):
         self.connect('realize', self.__realize_cb)
         self.connect('delete-event', self.__delete_event_cb)
 
+        # watch visibility-notify-events to know when we can safely
+        # take a screenshot of the activity
+        self.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
+        self.connect('visibility-notify-event', self.__visibility_notify_event_cb)
+        self._visible = False
+
         self._active = False
         self._activity_id = handle.activity_id
         self._pservice = presenceservice.get_instance()
@@ -575,6 +580,12 @@ class Activity(Window, gtk.Container):
     active = gobject.property(
         type=bool, default=False, getter=get_active, setter=set_active)
 
+    def is_visible(self):
+        """Returns True if the last visibility-notify-event received by the
+        activity root window was not gtk.gdk.VISIBILITY_FULLY_OBSCURED.
+        Returns False otherwise."""
+        return self._visible
+
     def get_max_participants(self):
         return self._max_participants
 
@@ -724,19 +735,12 @@ class Activity(Window, gtk.Container):
         pixbuf = pixbuf.scale_simple(style.zoom(300), style.zoom(225),
                                      gtk.gdk.INTERP_BILINEAR)
 
-        # TODO: Find a way of taking a png out of the pixbuf without saving
-        # to a temp file. Impementing gtk.gdk.Pixbuf.save_to_buffer in pygtk
-        # would solve this.
-        fd, file_path = tempfile.mkstemp('.png')
-        os.close(fd)
+        preview_data = []
+        def save_func(buf, data):
+            data.append(buf)
 
-        pixbuf.save(file_path, 'png')
-        f = open(file_path)
-        try:
-            preview_data = f.read()
-        finally:
-            f.close()
-            os.remove(file_path)
+        pixbuf.save_to_callback(save_func, 'png', user_data=preview_data)
+        preview_data = ''.join(preview_data)
 
         self._preview.clear()
 
@@ -813,6 +817,8 @@ class Activity(Window, gtk.Container):
         copy work that needs to be done in write_file()
         """
         logging.debug('Activity.copy: %r' % self._jobject.object_id)
+        if self.is_visible():
+            self.take_screenshot()
         self.save()
         self._jobject.object_id = None
 
@@ -968,6 +974,8 @@ class Activity(Window, gtk.Container):
         write_file() to do any state saving instead. If the application wants
         to control wether it can close, it should override can_close().
         """
+        if self.is_visible():
+            self.take_screenshot()
 
         if not self.can_close():
             return
@@ -987,6 +995,15 @@ class Activity(Window, gtk.Container):
         self.close()
         return True
 
+    def __visibility_notify_event_cb(self, widget, event):
+        """Visibility state is used when deciding if we can take screenshots.
+        Currently we allow screenshots whenever the activity window is fully
+        visible or partially obscured."""
+        if event.state is gtk.gdk.VISIBILITY_FULLY_OBSCURED:
+            self._visible = False
+        else:
+            self._visible = True
+
     def get_metadata(self):
         """Returns the jobject metadata or None if there is no jobject.
         
_______________________________________________
Sugar mailing list
[email protected]
http://lists.laptop.org/listinfo/sugar

Reply via email to