gnome-shell r139 - in trunk: js/ui src



Author: jmatthew
Date: Mon Dec 29 04:44:03 2008
New Revision: 139
URL: http://svn.gnome.org/viewvc/gnome-shell?rev=139&view=rev

Log:
implement some basic window management effects.  #563844


Modified:
   trunk/js/ui/windowManager.js
   trunk/src/gnome-shell-plugin.c
   trunk/src/shell-marshal.list
   trunk/src/shell-wm.c
   trunk/src/shell-wm.h

Modified: trunk/js/ui/windowManager.js
==============================================================================
--- trunk/js/ui/windowManager.js	(original)
+++ trunk/js/ui/windowManager.js	Mon Dec 29 04:44:03 2008
@@ -8,6 +8,7 @@
 
 const Main = imports.ui.main;
 
+const WINDOW_ANIMATION_TIME = 0.25;
 const SWITCH_ANIMATION_TIME = 0.5;
 
 function WindowManager() {
@@ -20,20 +21,219 @@
 
         this._global = Shell.Global.get();
         this._shellwm = this._global.window_manager;
+        this._minimizing = [];
+        this._maximizing = [];
+        this._unmaximizing = [];
+        this._mapping = [];
+        this._destroying = [];
 
         this._switchData = null;
         this._shellwm.connect('switch-workspace',
             function(o, from, to, direction) {
                 let actors = me._shellwm.get_switch_workspace_actors();
-                me.switchWorkspace(actors, from, to, direction);
+                me._switchWorkspace(actors, from, to, direction);
             });
         this._shellwm.connect('kill-switch-workspace',
             function(o) {
-                me.switchWorkspaceDone();
+                me._switchWorkspaceDone();
             });
+        this._shellwm.connect('minimize',
+            function(o, actor) {
+                me._minimizeWindow(actor);
+            });
+        this._shellwm.connect('kill-minimize',
+            function(o, actor) {
+                me._minimizeWindowDone(actor);
+            });
+        this._shellwm.connect('maximize',
+            function(o, actor, tx, ty, tw, th) {
+                me._maximizeWindow(actor, tx, ty, tw, th);
+            });
+        this._shellwm.connect('kill-maximize',
+            function(o, actor) {
+                me._maximizeWindowDone(actor);
+            });
+        this._shellwm.connect('unmaximize',
+            function(o, actor, tx, ty, tw, th) {
+                me._unmaximizeWindow(actor, tx, ty, tw, th);
+            });
+        this._shellwm.connect('kill-unmaximize',
+            function(o, actor) {
+                me._unmaximizeWindowDone(actor);
+            });
+        this._shellwm.connect('map',
+            function(o, actor) {
+                me._mapWindow(actor);
+            });
+        this._shellwm.connect('kill-map',
+            function(o, actor) {
+                me._mapWindowDone(actor);
+            });
+        this._shellwm.connect('destroy',
+            function(o, actor) {
+                me._destroyWindow(actor);
+            });
+        this._shellwm.connect('kill-destroy',
+            function(o, actor) {
+                me._destroyWindowDone(actor);
+            });
+    },
+
+
+    _minimizeWindow : function(actor) {
+        if (actor.get_window_type() != Meta.CompWindowType.NORMAL) {
+            this._shellwm.completed_minimize(actor);
+            return;
+        }
+
+        actor.set_scale(1.0, 1.0);
+        actor.move_anchor_point_from_gravity(Clutter.Gravity.CENTER);
+
+        /* scale window down to 0x0.
+         * maybe TODO: get icon geometry passed through and move the window towards it?
+         */
+        this._minimizing.push(actor);
+        Tweener.addTween(actor,
+                         { scale_x: 0.0,
+                           scale_y: 0.0,
+                           time: WINDOW_ANIMATION_TIME,
+                           transition: "easeOutQuad",
+                           onComplete: this._minimizeWindowDone,
+                           onCompleteScope: this,
+                           onCompleteParams: [actor]
+                         });
+    },
+
+    _minimizeWindowDone : function(actor) {
+        let idx = this._minimizing.indexOf(actor);
+        if (idx != -1) {
+            Tweener.removeTweens(actor);
+            actor.set_scale(1.0, 1.0);
+            actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
+            this._shellwm.completed_minimize(actor);
+
+            this._minimizing.splice(idx, 1);
+        }
     },
+    
+    _maximizeWindow : function(actor, target_x, target_y, target_width, target_height) {
+        if (actor.get_window_type() != Meta.CompWindowType.NORMAL) {
+            this._shellwm.completed_maximize(actor);
+            return;
+        }
+
+        /* this doesn't work very well, as simply scaling up the existing
+         * window contents doesn't produce anything like the same results as
+         * actually maximizing the window.
+         */
+        let scale_x = target_width / actor.width;
+        let scale_y = target_height / actor.height;
+        let anchor_x = (actor.x - target_x) * actor.width/(target_width - actor.width);
+        let anchor_y = (actor.y - target_y) * actor.height/(target_height - actor.height);
+        
+        actor.move_anchor_point(anchor_x, anchor_y);
+
+        this._maximizing.push(actor);
+        Tweener.addTween(actor,
+                         { scale_x: scale_x,
+                           scale_y: scale_y,
+                           time: WINDOW_ANIMATION_TIME,
+                           transition: "easeOutQuad",
+                           onComplete: this._maximizeWindowDone,
+                           onCompleteScope: this,
+                           onCompleteParams: [actor]
+                         });
+    },
+
+    _maximizeWindowDone : function(actor) {
+        let idx = this._maximizing.indexOf(actor);
+        if (idx != -1) {
+            Tweener.removeTweens(actor);
+            actor.set_scale(1.0, 1.0);
+            actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
+            this._shellwm.completed_maximize(actor);
+            
+            this._maximizing.splice(idx, 1);
+        }
+    },
+
+    _unmaximizeWindow : function(actor, target_x, target_y, target_width, target_height) {
+        this._shellwm.completed_unmaximize(actor);
+    },
+
+    _unmaximizeWindowDone : function(actor) {
+    },
+
+
+    _mapWindow : function(actor) {
+        if (actor.get_window_type() != Meta.CompWindowType.NORMAL) {
+            this._shellwm.completed_map(actor);
+            return;
+        }
+
+        actor.move_anchor_point_from_gravity(Clutter.Gravity.CENTER);
+        actor.set_scale(0.0, 0.0);
+        actor.show();
+        
+        /* scale window up from 0x0 to normal size */
+        this._mapping.push(actor);
+        Tweener.addTween(actor,
+                         { scale_x: 1.0,
+                           scale_y: 1.0,
+                           time: WINDOW_ANIMATION_TIME,
+                           transition: "easeOutQuad",
+                           onComplete: this._mapWindowDone,
+                           onCompleteScope: this,
+                           onCompleteParams: [actor]
+                         });
+    },
+
+    _mapWindowDone : function(actor) {
+        let idx = this._mapping.indexOf(actor);
+        if (idx != -1) {
+            Tweener.removeTweens(actor);
+            actor.set_scale(1.0, 1.0);
+            actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
+            this._shellwm.completed_map(actor);
+            
+            this._mapping.splice(idx, 1);
+        }
+    },
+
+    _destroyWindow : function(actor) {
+        if (actor.get_window_type() != Meta.CompWindowType.NORMAL) {
+            this._shellwm.completed_destroy(actor);
+            return;
+        }
+
+        actor.move_anchor_point_from_gravity(Clutter.Gravity.CENTER);
+        
+        /* anachronistic 'tv-like' effect - squash on y axis, leave x alone */
+        this._destroying.push(actor);
+        Tweener.addTween(actor,
+                         { scale_x: 1.0,
+                           scale_y: 0.0,
+                           time: WINDOW_ANIMATION_TIME,
+                           transition: "easeOutQuad",
+                           onComplete: this._destroyWindowDone,
+                           onCompleteScope: this,
+                           onCompleteParams: [actor]
+                         });
+    },
+    
+    _destroyWindowDone : function(actor) {
+        let idx = this._destroying.indexOf(actor);
+        if (idx != -1) {
+            this._shellwm.completed_destroy(actor);
+            Tweener.removeTweens(actor);
+            actor.set_scale(1.0, 1.0);
+            
+            this._mapping.splice(idx, 1);
+        }
+    },
+
 
-    switchWorkspace : function(windows, from, to, direction) {
+    _switchWorkspace : function(windows, from, to, direction) {
         // If the overlay is active, it will do the transition itself
         if (Main.overlayActive) {
             this._shellwm.completed_switch_workspace();
@@ -96,7 +296,7 @@
                            y: yDest,
                            time: SWITCH_ANIMATION_TIME,
                            transition: "easeOutBack",
-                           onComplete: this.switchWorkspaceDone
+                           onComplete: this._switchWorkspaceDone
                          });
         Tweener.addTween(switchData.inGroup,
                          { x: 0,
@@ -106,7 +306,7 @@
                          });
     },
 
-    switchWorkspaceDone : function() {
+    _switchWorkspaceDone : function() {
         let switchData = this._switchData;
         if (!switchData)
             return;

Modified: trunk/src/gnome-shell-plugin.c
==============================================================================
--- trunk/src/gnome-shell-plugin.c	(original)
+++ trunk/src/gnome-shell-plugin.c	Mon Dec 29 04:44:03 2008
@@ -46,7 +46,6 @@
 static void gnome_shell_plugin_dispose     (GObject *object);
 static void gnome_shell_plugin_finalize    (GObject *object);
 
-#ifdef NOT_YET
 static void     gnome_shell_plugin_minimize         (MutterPlugin         *plugin,
                                                      MutterWindow         *actor);
 static void     gnome_shell_plugin_maximize         (MutterPlugin         *plugin,
@@ -65,7 +64,6 @@
                                                      MutterWindow         *actor);
 static void     gnome_shell_plugin_destroy          (MutterPlugin         *plugin,
                                                      MutterWindow         *actor);
-#endif
 
 static void     gnome_shell_plugin_switch_workspace (MutterPlugin         *plugin,
                                                      const GList         **actors,
@@ -121,13 +119,11 @@
   gobject_class->dispose         = gnome_shell_plugin_dispose;
   gobject_class->finalize        = gnome_shell_plugin_finalize;
 
-#ifdef NOT_YET
   plugin_class->map              = gnome_shell_plugin_map;
   plugin_class->minimize         = gnome_shell_plugin_minimize;
   plugin_class->maximize         = gnome_shell_plugin_maximize;
   plugin_class->unmaximize       = gnome_shell_plugin_unmaximize;
   plugin_class->destroy          = gnome_shell_plugin_destroy;
-#endif
 
   plugin_class->switch_workspace = gnome_shell_plugin_switch_workspace;
   plugin_class->kill_effect      = gnome_shell_plugin_kill_effect;
@@ -213,6 +209,55 @@
 }
 
 static void
+gnome_shell_plugin_minimize (MutterPlugin         *plugin,
+			     MutterWindow         *actor)
+{
+  _shell_wm_minimize (get_shell_wm (),
+                      actor);
+
+}
+
+static void
+gnome_shell_plugin_maximize (MutterPlugin         *plugin,
+                             MutterWindow         *actor,
+                             gint                  x,
+                             gint                  y,
+                             gint                  width,
+                             gint                  height)
+{
+  _shell_wm_maximize (get_shell_wm (),
+                      actor, x, y, width, height);
+}
+
+static void
+gnome_shell_plugin_unmaximize (MutterPlugin         *plugin,
+                               MutterWindow         *actor,
+                               gint                  x,
+                               gint                  y,
+                               gint                  width,
+                               gint                  height)
+{
+  _shell_wm_unmaximize (get_shell_wm (),
+                        actor, x, y, width, height);
+}
+
+static void
+gnome_shell_plugin_map (MutterPlugin         *plugin,
+                        MutterWindow         *actor)
+{
+  _shell_wm_map (get_shell_wm (),
+                 actor);
+}
+
+static void
+gnome_shell_plugin_destroy (MutterPlugin         *plugin,
+                            MutterWindow         *actor)
+{
+  _shell_wm_destroy (get_shell_wm (),
+                     actor);
+}
+
+static void
 gnome_shell_plugin_switch_workspace (MutterPlugin         *plugin,
                                      const GList         **actors,
                                      gint                  from,

Modified: trunk/src/shell-marshal.list
==============================================================================
--- trunk/src/shell-marshal.list	(original)
+++ trunk/src/shell-marshal.list	Mon Dec 29 04:44:03 2008
@@ -1 +1,2 @@
 VOID:INT,INT,INT
+VOID:OBJECT,INT,INT,INT,INT

Modified: trunk/src/shell-wm.c
==============================================================================
--- trunk/src/shell-wm.c	(original)
+++ trunk/src/shell-wm.c	Mon Dec 29 04:44:03 2008
@@ -14,7 +14,6 @@
 /* Signals */
 enum
 {
-#ifdef NOT_YET
   MINIMIZE,
   KILL_MINIMIZE,
   MAXIMIZE,
@@ -25,7 +24,6 @@
   KILL_MAP,
   DESTROY,
   KILL_DESTROY,
-#endif
   SWITCH_WORKSPACE,
   KILL_SWITCH_WORKSPACE,
 
@@ -61,6 +59,96 @@
 
   gobject_class->finalize = shell_wm_finalize;
 
+  shell_wm_signals[MINIMIZE] =
+    g_signal_new ("minimize",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1,
+                  MUTTER_TYPE_COMP_WINDOW);
+  shell_wm_signals[KILL_MINIMIZE] =
+    g_signal_new ("kill-minimize",
+		  G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+		  0,
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__OBJECT,
+		  G_TYPE_NONE, 1,
+		  MUTTER_TYPE_COMP_WINDOW);
+  shell_wm_signals[MAXIMIZE] =
+    g_signal_new ("maximize",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  _shell_marshal_VOID__OBJECT_INT_INT_INT_INT,
+                  G_TYPE_NONE, 5,
+                  MUTTER_TYPE_COMP_WINDOW, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
+  shell_wm_signals[KILL_MAXIMIZE] =
+    g_signal_new ("kill-maximize",
+		  G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+		  0,
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__OBJECT,
+		  G_TYPE_NONE, 1,
+		  MUTTER_TYPE_COMP_WINDOW);
+  shell_wm_signals[UNMAXIMIZE] =
+    g_signal_new ("unmaximize",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  _shell_marshal_VOID__OBJECT_INT_INT_INT_INT,
+                  G_TYPE_NONE, 1,
+                  MUTTER_TYPE_COMP_WINDOW, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
+  shell_wm_signals[KILL_UNMAXIMIZE] =
+    g_signal_new ("kill-unmaximize",
+		  G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+		  0,
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__OBJECT,
+		  G_TYPE_NONE, 1,
+		  MUTTER_TYPE_COMP_WINDOW);
+  shell_wm_signals[MAP] =
+    g_signal_new ("map",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1,
+                  MUTTER_TYPE_COMP_WINDOW);
+  shell_wm_signals[KILL_MAP] =
+    g_signal_new ("kill-map",
+		  G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+		  0,
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__OBJECT,
+		  G_TYPE_NONE, 1,
+		  MUTTER_TYPE_COMP_WINDOW);
+  shell_wm_signals[DESTROY] =
+    g_signal_new ("destroy",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1,
+                  MUTTER_TYPE_COMP_WINDOW);
+  shell_wm_signals[KILL_DESTROY] =
+    g_signal_new ("kill-destroy",
+		  G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+		  0,
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__OBJECT,
+		  G_TYPE_NONE, 1,
+		  MUTTER_TYPE_COMP_WINDOW);
   shell_wm_signals[SWITCH_WORKSPACE] =
     g_signal_new ("switch-workspace",
 		  G_TYPE_FROM_CLASS (klass),
@@ -148,29 +236,149 @@
   shell_wm_set_switch_workspace_actors (wm, NULL);
 }
 
+/**
+ * shell_wm_completed_minimize
+ * @wm: the ShellWM
+ * @actor: the MutterWindow actor
+ *
+ * The plugin must call this when it has completed a window minimize effect.
+ **/
+void
+shell_wm_completed_minimize (ShellWM      *wm,
+                             MutterWindow *actor)
+{
+  mutter_plugin_effect_completed (wm->plugin,
+                                  actor,
+                                  MUTTER_PLUGIN_MINIMIZE);
+}
+
+/**
+ * shell_wm_completed_maximize
+ * @wm: the ShellWM
+ * @actor: the MutterWindow actor
+ *
+ * The plugin must call this when it has completed a window maximize effect.
+ **/
+void
+shell_wm_completed_maximize (ShellWM      *wm,
+                             MutterWindow *actor)
+{
+  mutter_plugin_effect_completed (wm->plugin,
+                                  actor,
+                                  MUTTER_PLUGIN_MAXIMIZE);
+}
+
+/**
+ * shell_wm_completed_unmaximize
+ * @wm: the ShellWM
+ * @actor: the MutterWindow actor
+ *
+ * The plugin must call this when it has completed a window unmaximize effect.
+ **/
+void
+shell_wm_completed_unmaximize (ShellWM      *wm,
+                               MutterWindow *actor)
+{
+  mutter_plugin_effect_completed (wm->plugin,
+                                  actor,
+                                  MUTTER_PLUGIN_UNMAXIMIZE);
+}
+
+/**
+ * shell_wm_completed_map
+ * @wm: the ShellWM
+ * @actor: the MutterWindow actor
+ *
+ * The plugin must call this when it has completed a window map effect.
+ **/
+void
+shell_wm_completed_map (ShellWM      *wm,
+                        MutterWindow *actor)
+{
+  mutter_plugin_effect_completed (wm->plugin,
+                                  actor,
+                                  MUTTER_PLUGIN_MAP);
+}
+
+/**
+ * shell_wm_completed_destroy
+ * @wm: the ShellWM
+ * @actor: the MutterWindow actor
+ *
+ * The plugin must call this when it has completed a window destroy effect.
+ **/
+void
+shell_wm_completed_destroy (ShellWM      *wm,
+                            MutterWindow *actor)
+{
+  mutter_plugin_effect_completed (wm->plugin,
+                                  actor,
+                                  MUTTER_PLUGIN_DESTROY);
+}
 
 void
 _shell_wm_kill_effect (ShellWM      *wm,
                        MutterWindow *actor,
                        gulong        events)
 {
-#ifdef NOT_YET
   if (events & MUTTER_PLUGIN_MINIMIZE)
-    g_signal_emit (wm, shell_wm_signals[KILL_MINIMIZE], 0);
+    g_signal_emit (wm, shell_wm_signals[KILL_MINIMIZE], 0, actor);
   if (events & MUTTER_PLUGIN_MAXIMIZE)
-    g_signal_emit (wm, shell_wm_signals[KILL_MAXIMIZE], 0);
+    g_signal_emit (wm, shell_wm_signals[KILL_MAXIMIZE], 0, actor);
   if (events & MUTTER_PLUGIN_UNMAXIMIZE)
-    g_signal_emit (wm, shell_wm_signals[KILL_UNMAXIMIZE], 0);
+    g_signal_emit (wm, shell_wm_signals[KILL_UNMAXIMIZE], 0, actor);
   if (events & MUTTER_PLUGIN_MAP)
-    g_signal_emit (wm, shell_wm_signals[KILL_MAP], 0);
+    g_signal_emit (wm, shell_wm_signals[KILL_MAP], 0, actor);
   if (events & MUTTER_PLUGIN_DESTROY)
-    g_signal_emit (wm, shell_wm_signals[KILL_DESTROY], 0);
-#endif
+    g_signal_emit (wm, shell_wm_signals[KILL_DESTROY], 0, actor);
   if (events & MUTTER_PLUGIN_SWITCH_WORKSPACE)
     g_signal_emit (wm, shell_wm_signals[KILL_SWITCH_WORKSPACE], 0);
 }
 
 
+void
+_shell_wm_minimize (ShellWM      *wm,
+                    MutterWindow *actor)
+{
+  g_signal_emit (wm, shell_wm_signals[MINIMIZE], 0, actor);
+}
+
+void
+_shell_wm_maximize (ShellWM      *wm,
+                    MutterWindow *actor,
+                    int           target_x,
+                    int           target_y,
+                    int           target_width,
+                    int           target_height)
+{
+  g_signal_emit (wm, shell_wm_signals[MAXIMIZE], 0, actor, target_x, target_y, target_width, target_height);
+}
+
+void
+_shell_wm_unmaximize (ShellWM      *wm,
+                      MutterWindow *actor,
+                      int           target_x,
+                      int           target_y,
+                      int           target_width,
+                      int           target_height)
+{
+  g_signal_emit (wm, shell_wm_signals[UNMAXIMIZE], 0, actor, target_x, target_y, target_width, target_height);
+}
+
+void
+_shell_wm_map (ShellWM      *wm,
+               MutterWindow *actor)
+{
+  g_signal_emit (wm, shell_wm_signals[MAP], 0, actor);
+}
+
+void
+_shell_wm_destroy (ShellWM      *wm,
+                   MutterWindow *actor)
+{
+  g_signal_emit (wm, shell_wm_signals[DESTROY], 0, actor);
+}
+
 /**
  * shell_wm_new:
  * @plugin: the #MutterPlugin

Modified: trunk/src/shell-wm.h
==============================================================================
--- trunk/src/shell-wm.h	(original)
+++ trunk/src/shell-wm.h	Mon Dec 29 04:44:03 2008
@@ -27,12 +27,22 @@
 ShellWM *shell_wm_new                         (MutterPlugin *plugin);
 
 GList   *shell_wm_get_switch_workspace_actors (ShellWM      *wm);
+
+void     shell_wm_completed_minimize          (ShellWM      *wm,
+                                               MutterWindow *actor);
+void     shell_wm_completed_maximize          (ShellWM      *wm,
+                                               MutterWindow *actor);
+void     shell_wm_completed_unmaximize        (ShellWM      *wm,
+                                               MutterWindow *actor);
+void     shell_wm_completed_map               (ShellWM      *wm,
+                                               MutterWindow *actor);
+void     shell_wm_completed_destroy           (ShellWM      *wm,
+                                               MutterWindow *actor);
 void     shell_wm_completed_switch_workspace  (ShellWM      *wm);
 
 
 /* These forward along the different effects from GnomeShellPlugin */
 
-#ifdef NOT_YET
 void _shell_wm_minimize   (ShellWM      *wm,
 			   MutterWindow *actor);
 void _shell_wm_maximize   (ShellWM      *wm,
@@ -51,7 +61,6 @@
 			   MutterWindow *actor);
 void _shell_wm_destroy    (ShellWM      *wm,
 			   MutterWindow *actor);
-#endif
 
 void _shell_wm_switch_workspace (ShellWM              *wm,
 				 const GList         **actors,



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