Logo Search packages:      
Sourcecode: f-spot version File versions  Download package

SlideView.cs

using Gtk;
using Gdk;
using Gnome;
using GtkSharp;
using System;
using GLib;
using System.Runtime.InteropServices;

namespace FSpot {
      public class XScreenSaverSlide : Gtk.Window {
            public const string ScreenSaverEnviroment = "XSCREENSAVER_WINDOW";

            public XScreenSaverSlide () : base ("")
            {
            }
             
            protected override void OnRealized ()
            {
                  string env = Environment.GetEnvironmentVariable (ScreenSaverEnviroment);
                  
                  if (env != null) {
                        try {
                              env = env.ToLower ();
                              
                              if (env.StartsWith ("0x"))
                                    env = env.Substring (2);

                              uint xid = UInt32.Parse (env, System.Globalization.NumberStyles.HexNumber);
                              
                              GdkWindow = Gdk.Window.ForeignNew (xid);
                              Style.Attach (GdkWindow);
                              GdkWindow.Events = EventMask.ExposureMask 
                                    | EventMask.StructureMask 
                                    | EventMask.EnterNotifyMask 
                                    | EventMask.LeaveNotifyMask 
                                    | EventMask.FocusChangeMask;
                              
                              Style.SetBackground (GdkWindow, Gtk.StateType.Normal);
                              GdkWindow.SetDecorations ((Gdk.WMDecoration) 0);
                              GdkWindow.UserData = this.Handle;
                              SetFlag (WidgetFlags.Realized);
                              SizeRequest ();
                              Gdk.Rectangle geom;
                              int depth;
                              GdkWindow.GetGeometry (out geom.X, out geom.Y, out geom.Width, out geom.Height, out depth);
                              SizeAllocate (new Gdk.Rectangle (geom.X, geom.Y, geom.Width, geom.Height));
                              Resize (geom.Width, geom.Height);
                              return;
                        } catch (System.Exception e) {
                              System.Console.WriteLine (e);
                        }
                  } else {
                        System.Console.WriteLine ("{0} not set, falling back to window", ScreenSaverEnviroment);
                  }

                  SetSizeRequest (640, 480);
                  base.OnRealized ();
            }
      }

      public class FullSlide : Gtk.Window {
            private SlideView slideview;
            private Gdk.Pixbuf screenshot;
            private Delay hide;
            private Gdk.Cursor busy;
            private Gdk.Cursor none;
            
            public FullSlide (Gtk.Window parent, IBrowsableItem [] items) : base ("Slideshow")
            {
                  screenshot =  PixbufUtils.LoadFromScreen (parent.GdkWindow);
                  
                  this.Destroyed += HandleDestroyed;

                  this.TransientFor = parent;

                  this.ButtonPressEvent += HandleSlideViewButtonPressEvent;
                  this.KeyPressEvent += HandleSlideViewKeyPressEvent;
                  this.AddEvents ((int) (EventMask.ButtonPressMask | EventMask.KeyPressMask | EventMask.PointerMotionMask));
                  slideview = new SlideView (screenshot, items);
                  this.Add (slideview);
                  this.Decorated = false;
                  this.Fullscreen();
                  this.Realize ();

                  busy = new Gdk.Cursor (Gdk.CursorType.Watch);
                  this.GdkWindow.Cursor = busy;
                  none = Empty ();

                  hide = new Delay (2000, new GLib.IdleHandler (HideCursor));
            }

            [DllImport("libgdk-2.0-0.dll")]
            static extern IntPtr gdk_cursor_new_from_pixbuf (IntPtr display, IntPtr pixbuf, int x, int y);

            public Gdk.Cursor Empty () 
            {
                  Gdk.Cursor cempty = null;
                  
                  try {
                        Gdk.Pixbuf empty = new Gdk.Pixbuf (Gdk.Colorspace.Rgb, true, 8, 1, 1);
                          empty.Fill (0x00000000);
                        IntPtr raw = gdk_cursor_new_from_pixbuf (this.GdkWindow.Display.Handle, empty.Handle, 0, 0);
                        cempty = new Gdk.Cursor (raw);
                  } catch (System.Exception e){
                        System.Console.WriteLine (e.ToString ());
                        return null;
                  }

                  return cempty;
            }



            public void Play ()
            {
                  Gdk.GCValues values = new Gdk.GCValues ();
                  values.SubwindowMode = SubwindowMode.IncludeInferiors;
                  Gdk.GC fillgc = new Gdk.GC (this.GdkWindow, values, Gdk.GCValuesMask.Subwindow);
                  
                  slideview.Show ();
                  this.GdkWindow.SetBackPixmap (null, false);
                  this.Show ();
                  screenshot.RenderToDrawable (this.GdkWindow, fillgc, 
                                         0, 0, 0, 0, -1, -1, RgbDither.Normal, 0, 0);
                  
                  slideview.Play ();
                  hide.Start ();
            }
            
            [GLib.ConnectBefore]
            private void HandleSlideViewKeyPressEvent (object sender, KeyPressEventArgs args)
            {
                  this.Destroy ();
                  args.RetVal = true;
            }

            protected override bool OnMotionNotifyEvent (Gdk.EventMotion args)
            {
                  base.OnMotionNotifyEvent (args);
                  this.GdkWindow.Cursor = busy;
                  hide.Start ();
                  return true;
            }
            
            private bool HideCursor ()
            {
                  this.GdkWindow.Cursor = none;
                  return false;
            }
            
            private void HandleDestroyed (object sender, System.EventArgs args)
            {
                  hide.Stop ();
            }

            private void HandleSlideViewButtonPressEvent (object sender, ButtonPressEventArgs args)
            {
                  this.Destroy ();
                  args.RetVal = true;
            }
      }
      
      public class SlideView : Gtk.Image {
            IBrowsableItem [] photos;
            Pixbuf last;
            Pixbuf next;
            
            
            Pixbuf [] tweens = new Pixbuf [10]; 
            int current_tween;
            uint tween_idle;
            uint resize_idle;
            
            int current_idx = 0;    
            int next_idx = 0;
            
            uint flip_timer = 0;
            uint transition_timer = 0;
            
            uint fail_count = 0;
            bool animate = true;
            uint animate_max = 200;
            
            bool black = false;
            uint flip_interval = 2000;
            uint transition_interval = 75;
            
            public bool Running {
                  get {
                        return flip_timer != 0 || transition_timer != 0;
                  }
            }
            
            public bool Animate {
                  get { return animate; }
                  set { animate = value; }
            }
            
            public void Play () 
            {
                  if (photos.Length < 1)
                        return;

                  StopTweenIdle ();
                  if (current_idx >= 0) {
                        Pixbuf frame = GetScaled (photos[current_idx]);
                        this.Pixbuf = frame;
                        frame.Dispose ();
                  } 
                  
                  if (PreloadNextImage (current_idx + 1))
                        StartFlipTimer ();
            }
            
            public void Pause () 
            {
                  StopTranstionTimer ();
                  StopFlipTimer ();
            }
            
            public void Stop ()
            {
                  StopTweenIdle ();
                  StopTranstionTimer ();
                  StopFlipTimer ();
            }
            
            public void Forward ()
            {
                  if (PreloadNextImage (current_idx + 1))
                        ShowNext ();
            }
            
            public void Back ()
            {
                  if (PreloadNextImage (current_idx - 1))
                        ShowNext ();
            }     
            
            private void ShowNext ()
            {
                  StopTweenIdle ();
                  
                  if (current_idx != next_idx && next != null)
                        this.Pixbuf = next;
                  
                  current_idx = next_idx;
                  
                  black = false;
                  transition_interval = 75;
                  flip_interval = 2000;
            }
            
            private bool PreloadNextImage (int idx)
            {
                  try {
                        if (idx < photos.Length && idx >= 0) {
                              if (next != null)
                                    next.Dispose ();
                              
                              next = GetScaled (photos [idx]);
                              if (next == null)
                                    next = GetScaled (PixbufUtils.ShallowCopy (PixbufUtils.ErrorPixbuf));
                              
                              next_idx = idx;
                              StartTweenIdle ();
                              
                              return true;
                        } else {
                              if (next != null)
                                    next.Dispose ();

                              next = GetScaled (photos [0]);
                              next_idx = 0;
                              StartTweenIdle ();
                              
                              return false;
                        }
                  } catch (GLib.GException e) {
                        System.Console.WriteLine (e);
                        idx = (idx + 1) % photos.Length;
                        return PreloadNextImage (idx);
                  }
            }
            
            private Pixbuf CrossFade (Pixbuf current, Pixbuf prev, Pixbuf next, double percent)
            { 
                  int width = Allocation.Width;
                  int height = Allocation.Height;
                  
                  prev.CopyArea (0, 0, width, height, current, 0, 0);
                  next.Composite (current, 0,0, width, height, 0, 0, 1, 1,
                              Gdk.InterpType.Nearest, (int) System.Math.Round (255 * percent));
                  return current;
            }
            
            private Pixbuf BlackFade (Pixbuf current, Pixbuf prev, Pixbuf next, double percent)
            { 
                  int width = Allocation.Width;
                  int height = Allocation.Height;
                  
                  current.Fill (0);       
                  
                  if (percent < 0.5)
                        prev.Composite (current, 0,0, width, height, 0, 0, 1, 1,
                                    Gdk.InterpType.Nearest, (int)System.Math.Round (255  * (1 - percent * 2)));
                  else
                        next.Composite (current, 0,0, width, height, 0, 0, 1, 1,
                                    Gdk.InterpType.Nearest, (int)System.Math.Round (255 * (percent * 2 - 1)));
                  return current;
            }
            
            private Pixbuf Blend (Pixbuf current, Pixbuf prev, Pixbuf next, double percent)
            {
                  if (black) {
                        return BlackFade (current, prev, next, percent);
                  } else {
                        return CrossFade (current, prev, next, percent);
                  }
            }
            
            private Pixbuf GetScaled (Pixbuf orig)
            {
                  Pixbuf scaled = PixbufUtils.ScaleToAspect (orig, Allocation.Width, Allocation.Height);
                  
                  orig.Dispose ();
                  return scaled;
            }
            
            private Pixbuf GetScaled (IBrowsableItem photo)
            {
                  Pixbuf orig;
                  try { 
                        orig = FSpot.PhotoLoader.LoadAtMaxSize (photo, Allocation.Width, Allocation.Height);
                  } catch {
                        orig = null;
                  }

                  if (orig == null)
                        return null;

                  Pixbuf result = GetScaled (orig);
                  if (orig != result)
                        orig.Dispose ();
                  
                  return result;
            }
            
            private bool HandleFlipTimer ()
            {     
                  StopTweenIdle ();
                  
                  StartTransitionTimer ();
                  
                  flip_timer = 0;
                  return false;
            }
            
            private bool HandleTransitionTimer ()
            {                 
                  System.DateTime start_time = System.DateTime.Now;
                  transition_timer = 0;
                  if (current_tween--  > 0) {
                        StartTransitionTimer ();
                        this.Pixbuf = tweens[current_tween];
                        GdkWindow.ProcessUpdates (false);
                        System.TimeSpan span = System.DateTime.Now  - start_time;
                        
                        if (Animate) { 
                              if (span.TotalMilliseconds > animate_max) {
                                    fail_count++;
                                    
                                    if (fail_count > 3) {
                                          Animate = false;
                                          System.Console.WriteLine ("Disabling slide animation due to 3 consecutive excessive frame intervals {0}ms", 
                                                              span.TotalMilliseconds);
                                          current_tween = 0;
                                    }
                              } else {
                                    fail_count = 0;
                              }
                        } 
                  } else {
                        ShowNext ();

                        PreloadNextImage (current_idx + 1);
                        StartFlipTimer ();
                  }
                  
                  return false;                 
            }

            
            private bool HandleTweenIdle ()
            {
                  using (Pixbuf prev = this.Pixbuf) { 
                        if (!Animate) {
                              ClearTweens ();
                              return false;
                        }
                        
                        if (photos.Length < 2) { // Only one photo. Nothing to do
                              ClearTweens ();
                              return false;
                        }
                        
                        if (current_tween >= tweens.Length) {
                              tween_idle = 0;
                              return false;
                        }

                        if (current_tween < tweens.Length && tweens[current_tween] == null) {
                              tweens[current_tween] = new Pixbuf (Colorspace.Rgb, false, 8, 
                                                          Allocation.Width, Allocation.Height);
                        }

                        double blend_val;
#if USE_EXP
                        double blend_t = (-10 * current_tween) / ((double)tweens.Length - 1);
                        blend_val = 1.0 - (.01 / (.01 + (.99 * Math.Exp(blend_t))));
#else
                        double [] blends = new double [] { .99, .97, .9, .8, .7, .6, .5, .4, .3, .15};
                        blend_val = blends [current_tween];
#endif
                        tweens[current_tween] = Blend (tweens[current_tween], prev, next, blend_val);
                        current_tween++;
                        return true;
                  }
            }     
            
            private void StartTweenIdle () 
            {
                  if (tween_idle == 0) {
                        current_tween = 0;      
                        tween_idle = GLib.Idle.Add (new GLib.IdleHandler (HandleTweenIdle));
                  }
            }
            
            private void StopTweenIdle ()
            {
                  if (tween_idle != 0) {
                        GLib.Source.Remove (tween_idle);
                  }
                  tween_idle = 0;
      
            }
            
            private void StartTransitionTimer ()
            {
                  if (transition_timer == 0)
                        transition_timer = GLib.Timeout.Add (transition_interval, 
                                                     new TimeoutHandler (HandleTransitionTimer));
            }
            
            private void StopTranstionTimer ()
            {
                  if (transition_timer != 0)
                        GLib.Source.Remove (transition_timer);

                  transition_timer = 0;
            }
            
            private void StartFlipTimer ()
            {
                  if (flip_timer == 0)
                        flip_timer = GLib.Timeout.Add (flip_interval, 
                                                 new TimeoutHandler (HandleFlipTimer));
            }
            
            private void StopFlipTimer ()
            {     
                  if (flip_timer != 0)
                        GLib.Source.Remove (flip_timer);

                  flip_timer = 0;
            }

            
            private void HandleSizeAllocate (object sender, SizeAllocatedArgs args)
            {     
                  Pixbuf current = this.Pixbuf;

                  if (current == null)
                        return;

                  //
                  // The size has changed so we need to reload the images.
                  //
                  if (current.Width != Allocation.Width || current.Height != Allocation.Height) {
                        bool playing = (flip_timer != 0 || transition_timer != 0);
                        
                        if (current_idx < 0) {
                              using (Gdk.Pixbuf old = this.Pixbuf) {
                                    this.Pixbuf = GetScaled (old);
                                    current.Dispose ();
                              }
                        } else {
                              using (Pixbuf frame =  GetScaled (photos[current_idx])) {
                                    this.Pixbuf =  frame;
                                    current.Dispose ();
                              }
                        }
                        
                        Stop ();
                        
                        ClearTweens ();
                        
                        if (playing && current_idx != next_idx)
                              Play ();
                        
                        
                  }
            }

            private void ClearTweens () {
                  for (int i = 0; i < tweens.Length; i++) {
                        if (tweens[i] != null) 
                              tweens[i].Dispose ();
                        tweens[i] = null;
                  }
            }
            
            private void HandleDestroyed (object sender, EventArgs args)
            {
                  ClearTweens ();
                  Stop ();
            }

            public SlideView (Pixbuf background, IBrowsableItem [] photos) : base ()
            {
                  this.photos = photos;

                  if (background != null) {
                        this.Pixbuf = background;
                        background.Dispose ();
                        
                        current_idx = -1;
                        black = true;
                        flip_interval = 1500;
                  }
                  
                  SizeAllocated += new SizeAllocatedHandler (HandleSizeAllocate);
                  Destroyed += new EventHandler (HandleDestroyed);
            }
      }
}           

Generated by  Doxygen 1.6.0   Back to index