import clutter, eog, itertools, gtk class Cluttershow(eog.Plugin): def __init__(self): eog.Plugin.__init__(self) self.stage = None self.action_group = None def activate(self, window): manager = window.get_ui_manager() if self.action_group is None: self.action_group = gtk.ActionGroup("CluttershowPluginActions") action = gtk.Action(name="Cluttershow", label="Cluttershow", tooltip="Cluttershow", stock_id=None) action.connect("activate", self._on_action, window) self.action_group.add_action(action) self.mid = manager.new_merge_id() manager.insert_action_group(self.action_group, -1) manager.add_ui(merge_id=self.mid, path="/MainMenu/View/Slideshow", name="Cluttershow", action="Blingshow!", type=gtk.UI_MANAGER_MENUITEM, top=False) if self.stage is None: self._init_clutter() def deactivate(self, window): window.get_ui_manager().remove_ui(self.mid) self.mid = None def get_next_pixbuf(self): image = self.files.next()[2] if not image.has_data(1): image.load(1, None) pixbuf = image.get_pixbuf() if (pixbuf.get_width () > self.stage.get_width () or pixbuf.get_height() > self.stage.get_height()): factor = min ((float (self.stage.get_width ())/pixbuf.get_width ()), (float(self.stage.get_height ())/pixbuf.get_height ())) scaled_pixbuf = pixbuf.scale_simple (pixbuf.get_width ()*factor, pixbuf.get_height ()*factor, gtk.gdk.INTERP_TILES) pixbuf = scaled_pixbuf return pixbuf def _init_clutter(self): stage = clutter.stage_get_default() stage.set_color(clutter.color_parse('Black')) stage.fullscreen() stage.set_title('Cluttershow') def key_press (stage, event): if event.keyval == clutter.keysyms.q: self.stage.hide() self.current_tex.destroy() self.next_tex.destroy() return True return False stage.connect('key-press-event', key_press) self.timeline = clutter.Timeline(15, 30) # 15 frames at 30fps self.behaviour_in = clutter.BehaviourOpacity(clutter.Alpha(self.timeline, clutter.sine_inc_func), 0x00, 0xFF) self.behaviour_out = clutter.BehaviourOpacity(clutter.Alpha(self.timeline, clutter.sine_dec_func), 0x00, 0xFF) def completed(timeline): self.behaviour_in.remove_all() self.behaviour_out.remove_all() temp = self.current_tex self.current_tex = self.next_tex self.next_tex = temp self.next_tex.hide() self.next_tex.set_pixbuf(self.get_next_pixbuf()) self.next_tex.set_position((self.stage.get_width() - self.next_tex.get_width())/2, (self.stage.get_height() - self.next_tex.get_height())/2) self.timeline.connect("completed", completed) stage.connect('button-press-event', self.swap) self.stage = stage def swap(self, stage, event): # Don't swap if we're already swapping if self.timeline.is_playing(): return self.behaviour_out.apply(self.current_tex) self.behaviour_in.apply(self.next_tex) # Set the default state self.next_tex.raise_top() self.next_tex.set_opacity(0) self.next_tex.show() # Start the timeline again self.timeline.rewind() self.timeline.start() def _on_action(self, action, window): self.files = itertools.cycle(iter(window.get_store())) # The current texture starts blank, so the initial state is just black self.current_tex = clutter.Texture() self.current_tex.set_position(0, 0) self.current_tex.show() self.stage.add(self.current_tex) # The next texture is the first image we're displaying self.next_tex = clutter.texture_new_from_pixbuf(self.get_next_pixbuf()) self.next_tex.set_position((self.stage.get_width() - self.next_tex.get_width())/2, (self.stage.get_height() - self.next_tex.get_height())/2) self.stage.add(self.next_tex) # Schedule a swap so the first image fades in self.swap(self.stage, None) self.stage.show()