[mutter] cursor-renderer: Track cursor position using floats



commit 197401fbf82d639de3e510b5a27c7b967431420f
Author: Jonas Ådahl <jadahl gmail com>
Date:   Thu Jun 8 22:13:16 2017 +0800

    cursor-renderer: Track cursor position using floats
    
    To be able to render the pointer cursor sprite at sub-(logical)-pixel
    positions, track the pointer position using floats instead of ints.
    This also requires users of the cursor sprite rect to deal with
    floating points, when e.g. finding the logical monitor etc.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=765011

 src/backends/meta-cursor-renderer.c               |   30 ++++++----
 src/backends/meta-cursor-renderer.h               |    7 +-
 src/backends/meta-cursor-tracker-private.h        |    4 +-
 src/backends/meta-cursor-tracker.c                |    4 +-
 src/backends/meta-stage.c                         |   46 +++++++-------
 src/backends/meta-stage.h                         |    8 +-
 src/backends/native/meta-cursor-renderer-native.c |   68 +++++++++++++--------
 src/core/boxes-private.h                          |   15 +++++
 src/core/screen.c                                 |   10 ++-
 src/wayland/meta-wayland-surface-role-cursor.c    |    8 ++-
 src/wayland/meta-wayland-tablet-tool.c            |    4 +-
 src/wayland/meta-wayland-tablet-tool.h            |    4 +-
 12 files changed, 127 insertions(+), 81 deletions(-)
---
diff --git a/src/backends/meta-cursor-renderer.c b/src/backends/meta-cursor-renderer.c
index d27922d..716378b 100644
--- a/src/backends/meta-cursor-renderer.c
+++ b/src/backends/meta-cursor-renderer.c
@@ -37,7 +37,8 @@
 
 struct _MetaCursorRendererPrivate
 {
-  int current_x, current_y;
+  float current_x;
+  float current_y;
 
   MetaCursorSprite *displayed_cursor;
   MetaOverlay *stage_overlay;
@@ -69,7 +70,7 @@ queue_redraw (MetaCursorRenderer *renderer,
   MetaBackend *backend = meta_get_backend ();
   ClutterActor *stage = meta_backend_get_stage (backend);
   CoglTexture *texture;
-  MetaRectangle rect = { 0 };
+  ClutterRect rect = { 0 };
 
   if (cursor_sprite)
     rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
@@ -159,7 +160,7 @@ meta_cursor_renderer_init (MetaCursorRenderer *renderer)
                                            NULL);
 }
 
-MetaRectangle
+ClutterRect
 meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
                                      MetaCursorSprite   *cursor_sprite)
 {
@@ -172,18 +173,22 @@ meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
 
   texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
   if (!texture)
-    return (MetaRectangle) { 0 };
+    return (ClutterRect) { 0 };
 
   meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y);
   texture_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite);
   width = cogl_texture_get_width (texture);
   height = cogl_texture_get_height (texture);
 
-  return (MetaRectangle) {
-    .x = (int)roundf (priv->current_x - (hot_x * texture_scale)),
-    .y = (int)roundf (priv->current_y - (hot_y * texture_scale)),
-    .width = (int)roundf (width * texture_scale),
-    .height = (int)roundf (height * texture_scale),
+  return (ClutterRect) {
+    .origin = {
+      .x = priv->current_x - (hot_x * texture_scale),
+      .y = priv->current_y - (hot_y * texture_scale)
+    },
+    .size = {
+      .width = width * texture_scale,
+      .height = height * texture_scale
+    }
   };
 }
 
@@ -197,8 +202,8 @@ update_cursor (MetaCursorRenderer *renderer,
 
   if (cursor_sprite)
     meta_cursor_sprite_prepare_at (cursor_sprite,
-                                   priv->current_x,
-                                   priv->current_y);
+                                   (int) priv->current_x,
+                                   (int) priv->current_y);
 
   handled_by_backend =
     META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer,
@@ -246,7 +251,8 @@ meta_cursor_renderer_force_update (MetaCursorRenderer *renderer)
 
 void
 meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
-                                   int x, int y)
+                                   float               x,
+                                   float               y)
 {
   MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
 
diff --git a/src/backends/meta-cursor-renderer.h b/src/backends/meta-cursor-renderer.h
index 73f6dfc..8ac0fe7 100644
--- a/src/backends/meta-cursor-renderer.h
+++ b/src/backends/meta-cursor-renderer.h
@@ -60,13 +60,14 @@ void meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
                                       MetaCursorSprite   *cursor_sprite);
 
 void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
-                                        int x, int y);
+                                        float               x,
+                                        float               y);
 void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer);
 
 MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
 
-MetaRectangle meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
-                                                   MetaCursorSprite   *cursor_sprite);
+ClutterRect meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
+                                                 MetaCursorSprite   *cursor_sprite);
 
 #ifdef HAVE_WAYLAND
 void meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
diff --git a/src/backends/meta-cursor-tracker-private.h b/src/backends/meta-cursor-tracker-private.h
index 24f8b85..3c19b43 100644
--- a/src/backends/meta-cursor-tracker-private.h
+++ b/src/backends/meta-cursor-tracker-private.h
@@ -62,8 +62,8 @@ void     meta_cursor_tracker_set_root_cursor     (MetaCursorTracker *tracker,
                                                   MetaCursorSprite  *cursor_sprite);
 
 void     meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
-                                             int                new_x,
-                                             int                new_y);
+                                              float              new_x,
+                                              float              new_y);
 
 MetaCursorSprite * meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker);
 
diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c
index 3e1d76b..59e242b 100644
--- a/src/backends/meta-cursor-tracker.c
+++ b/src/backends/meta-cursor-tracker.c
@@ -350,8 +350,8 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
 
 void
 meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
-                                     int                new_x,
-                                     int                new_y)
+                                     float              new_x,
+                                     float              new_y)
 {
   MetaBackend *backend = meta_get_backend ();
   MetaCursorRenderer *cursor_renderer =
diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c
index 1bb3e1f..eb0dd0e 100644
--- a/src/backends/meta-stage.c
+++ b/src/backends/meta-stage.c
@@ -36,8 +36,8 @@ struct _MetaOverlay {
   CoglPipeline *pipeline;
   CoglTexture *texture;
 
-  MetaRectangle current_rect;
-  MetaRectangle previous_rect;
+  ClutterRect current_rect;
+  ClutterRect previous_rect;
   gboolean previous_is_valid;
 };
 
@@ -71,9 +71,9 @@ meta_overlay_free (MetaOverlay *overlay)
 }
 
 static void
-meta_overlay_set (MetaOverlay   *overlay,
-                  CoglTexture   *texture,
-                  MetaRectangle *rect)
+meta_overlay_set (MetaOverlay *overlay,
+                  CoglTexture *texture,
+                  ClutterRect *rect)
 {
   if (overlay->texture != texture)
     {
@@ -104,12 +104,12 @@ meta_overlay_paint (MetaOverlay *overlay)
 
   cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
                                    overlay->pipeline,
-                                   overlay->current_rect.x,
-                                   overlay->current_rect.y,
-                                   overlay->current_rect.x +
-                                   overlay->current_rect.width,
-                                   overlay->current_rect.y +
-                                   overlay->current_rect.height);
+                                   overlay->current_rect.origin.x,
+                                   overlay->current_rect.origin.y,
+                                   (overlay->current_rect.origin.x +
+                                    overlay->current_rect.size.width),
+                                   (overlay->current_rect.origin.y +
+                                    overlay->current_rect.size.height));
 
   overlay->previous_rect = overlay->current_rect;
   overlay->previous_is_valid = TRUE;
@@ -204,10 +204,10 @@ queue_redraw_for_overlay (MetaStage   *stage,
   /* Clear the location the overlay was at before, if we need to. */
   if (overlay->previous_is_valid)
     {
-      clip.x = overlay->previous_rect.x;
-      clip.y = overlay->previous_rect.y;
-      clip.width = overlay->previous_rect.width;
-      clip.height = overlay->previous_rect.height;
+      clip.x = floorf (overlay->previous_rect.origin.x),
+      clip.y = floorf (overlay->previous_rect.origin.y),
+      clip.width = ceilf (overlay->previous_rect.size.width),
+      clip.height = ceilf (overlay->previous_rect.size.height),
       clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip);
       overlay->previous_is_valid = FALSE;
     }
@@ -215,10 +215,10 @@ queue_redraw_for_overlay (MetaStage   *stage,
   /* Draw the overlay at the new position */
   if (overlay->enabled)
     {
-      clip.x = overlay->current_rect.x;
-      clip.y = overlay->current_rect.y;
-      clip.width = overlay->current_rect.width;
-      clip.height = overlay->current_rect.height;
+      clip.x = floorf (overlay->current_rect.origin.x),
+      clip.y = floorf (overlay->current_rect.origin.y),
+      clip.width = ceilf (overlay->current_rect.size.width),
+      clip.height = ceilf (overlay->current_rect.size.height),
       clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip);
     }
 }
@@ -251,10 +251,10 @@ meta_stage_remove_cursor_overlay (MetaStage   *stage,
 }
 
 void
-meta_stage_update_cursor_overlay (MetaStage          *stage,
-                                  MetaOverlay        *overlay,
-                                  CoglTexture        *texture,
-                                  MetaRectangle      *rect)
+meta_stage_update_cursor_overlay (MetaStage   *stage,
+                                  MetaOverlay *overlay,
+                                  CoglTexture *texture,
+                                  ClutterRect *rect)
 {
   g_assert (meta_is_wayland_compositor () || texture == NULL);
 
diff --git a/src/backends/meta-stage.h b/src/backends/meta-stage.h
index 028a347..7043832 100644
--- a/src/backends/meta-stage.h
+++ b/src/backends/meta-stage.h
@@ -56,10 +56,10 @@ MetaOverlay      *meta_stage_create_cursor_overlay   (MetaStage   *stage);
 void              meta_stage_remove_cursor_overlay   (MetaStage   *stage,
                                                      MetaOverlay *overlay);
 
-void              meta_stage_update_cursor_overlay   (MetaStage     *stage,
-                                                     MetaOverlay   *overlay,
-                                                     CoglTexture   *texture,
-                                                     MetaRectangle *rect);
+void              meta_stage_update_cursor_overlay   (MetaStage   *stage,
+                                                      MetaOverlay *overlay,
+                                                      CoglTexture *texture,
+                                                      ClutterRect *rect);
 
 void meta_stage_set_active (MetaStage *stage,
                             gboolean   is_active);
diff --git a/src/backends/native/meta-cursor-renderer-native.c 
b/src/backends/native/meta-cursor-renderer-native.c
index 0a50ea9..bcaa195 100644
--- a/src/backends/native/meta-cursor-renderer-native.c
+++ b/src/backends/native/meta-cursor-renderer-native.c
@@ -39,6 +39,7 @@
 #include "backends/meta-monitor.h"
 #include "backends/meta-monitor-manager-private.h"
 #include "backends/native/meta-renderer-native.h"
+#include "core/boxes-private.h"
 #include "meta/boxes.h"
 
 #ifndef DRM_CAP_CURSOR_WIDTH
@@ -220,7 +221,7 @@ typedef struct
 {
   MetaCursorRendererNative *in_cursor_renderer_native;
   MetaLogicalMonitor *in_logical_monitor;
-  MetaRectangle in_local_cursor_rect;
+  ClutterRect in_local_cursor_rect;
   MetaCursorSprite *in_cursor_sprite;
 
   gboolean out_painted;
@@ -238,7 +239,7 @@ update_monitor_crtc_cursor (MetaMonitor         *monitor,
     data->in_cursor_renderer_native;
   MetaCursorRendererNativePrivate *priv =
     meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
-  MetaRectangle scaled_crtc_rect;
+  ClutterRect scaled_crtc_rect;
   float scale;
   int crtc_x, crtc_y;
 
@@ -252,29 +253,36 @@ update_monitor_crtc_cursor (MetaMonitor         *monitor,
                                    META_MONITOR_TRANSFORM_NORMAL,
                                    &crtc_x, &crtc_y);
 
-  scaled_crtc_rect = (MetaRectangle) {
-    .x = crtc_x / scale,
-    .y = crtc_y / scale,
-    .width = monitor_crtc_mode->crtc_mode->width / scale,
-    .height = monitor_crtc_mode->crtc_mode->height / scale
+  scaled_crtc_rect = (ClutterRect) {
+    .origin = {
+      .x = crtc_x / scale,
+      .y = crtc_y / scale
+    },
+    .size = {
+      .width = monitor_crtc_mode->crtc_mode->width / scale,
+      .height = monitor_crtc_mode->crtc_mode->height / scale
+    },
   };
 
   if (priv->has_hw_cursor &&
-      meta_rectangle_overlap (&scaled_crtc_rect,
-                              &data->in_local_cursor_rect))
+      clutter_rect_intersection (&scaled_crtc_rect,
+                                 &data->in_local_cursor_rect,
+                                 NULL))
     {
-      int crtc_cursor_x, crtc_cursor_y;
+      float crtc_cursor_x, crtc_cursor_y;
 
       set_crtc_cursor (data->in_cursor_renderer_native,
                        monitor_crtc_mode->output->crtc,
                        data->in_cursor_sprite);
 
-      crtc_cursor_x = (data->in_local_cursor_rect.x - scaled_crtc_rect.x) * scale;
-      crtc_cursor_y = (data->in_local_cursor_rect.y - scaled_crtc_rect.y) * scale;
+      crtc_cursor_x = (data->in_local_cursor_rect.origin.x -
+                       scaled_crtc_rect.origin.x) * scale;
+      crtc_cursor_y = (data->in_local_cursor_rect.origin.y -
+                       scaled_crtc_rect.origin.y) * scale;
       drmModeMoveCursor (priv->drm_fd,
                          monitor_crtc_mode->output->crtc->crtc_id,
-                         crtc_cursor_x,
-                         crtc_cursor_y);
+                         roundf (crtc_cursor_x),
+                         roundf (crtc_cursor_y));
 
       data->out_painted = data->out_painted || TRUE;
     }
@@ -298,13 +306,13 @@ update_hw_cursor (MetaCursorRendererNative *native,
     meta_backend_get_monitor_manager (backend);
   GList *logical_monitors;
   GList *l;
-  MetaRectangle rect;
+  ClutterRect rect;
   gboolean painted = FALSE;
 
   if (cursor_sprite)
     rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
   else
-    rect = (MetaRectangle) { 0 };
+    rect = (ClutterRect) { 0 };
 
   logical_monitors =
     meta_monitor_manager_get_logical_monitors (monitor_manager);
@@ -318,11 +326,12 @@ update_hw_cursor (MetaCursorRendererNative *native,
       data = (UpdateCrtcCursorData) {
         .in_cursor_renderer_native = native,
         .in_logical_monitor = logical_monitor,
-        .in_local_cursor_rect = (MetaRectangle) {
-          .x = rect.x - logical_monitor->rect.x,
-          .y = rect.y - logical_monitor->rect.y,
-          .width = rect.width,
-          .height = rect.height
+        .in_local_cursor_rect = (ClutterRect) {
+          .origin = {
+            .x = rect.origin.x - logical_monitor->rect.x,
+            .y = rect.origin.y - logical_monitor->rect.y
+          },
+          .size = rect.size
         },
         .in_cursor_sprite = cursor_sprite
       };
@@ -380,7 +389,7 @@ cursor_over_transformed_crtc (MetaCursorRenderer *renderer,
   MetaMonitorManager *monitors;
   MetaCrtc *crtcs;
   unsigned int i, n_crtcs;
-  MetaRectangle rect;
+  ClutterRect rect;
 
   monitors = meta_monitor_manager_get ();
   meta_monitor_manager_get_resources (monitors, NULL, NULL,
@@ -389,10 +398,13 @@ cursor_over_transformed_crtc (MetaCursorRenderer *renderer,
 
   for (i = 0; i < n_crtcs; i++)
     {
-      if (!meta_rectangle_overlap (&rect, &crtcs[i].rect))
+      MetaCrtc *crtc = &crtcs[i];
+      ClutterRect crtc_rect = meta_rectangle_to_clutter_rect (&crtc->rect);
+
+      if (!clutter_rect_intersection (&rect, &crtc_rect, NULL))
         continue;
 
-      if (crtcs[i].transform != META_MONITOR_TRANSFORM_NORMAL)
+      if (crtc->transform != META_MONITOR_TRANSFORM_NORMAL)
         return TRUE;
     }
 
@@ -413,7 +425,7 @@ can_draw_cursor_unscaled (MetaCursorRenderer *renderer,
 {
   MetaBackend *backend;
   MetaMonitorManager *monitor_manager;
-  MetaRectangle cursor_rect;
+  ClutterRect cursor_rect;
   GList *logical_monitors;
   GList *l;
   gboolean has_visible_crtc_sprite = FALSE;
@@ -434,8 +446,12 @@ can_draw_cursor_unscaled (MetaCursorRenderer *renderer,
   for (l = logical_monitors; l; l = l->next)
     {
       MetaLogicalMonitor *logical_monitor = l->data;
+      ClutterRect logical_monitor_rect =
+        meta_rectangle_to_clutter_rect (&logical_monitor->rect);
 
-      if (!meta_rectangle_overlap (&cursor_rect, &logical_monitor->rect))
+      if (!clutter_rect_intersection (&cursor_rect,
+                                      &logical_monitor_rect,
+                                      NULL))
         continue;
 
       if (calculate_cursor_crtc_sprite_scale (cursor_sprite,
diff --git a/src/core/boxes-private.h b/src/core/boxes-private.h
index 9b6811c..bf019b4 100644
--- a/src/core/boxes-private.h
+++ b/src/core/boxes-private.h
@@ -218,4 +218,19 @@ GList* meta_rectangle_find_nonintersected_monitor_edges (
 gboolean meta_rectangle_is_adjecent_to (MetaRectangle *rect,
                                         MetaRectangle *other);
 
+static inline ClutterRect
+meta_rectangle_to_clutter_rect (MetaRectangle *rect)
+{
+  return (ClutterRect) {
+    .origin = {
+      .x = rect->x,
+      .y = rect->y
+    },
+    .size = {
+      .width = rect->width,
+      .height = rect->height
+    }
+  };
+}
+
 #endif /* META_BOXES_PRIVATE_H */
diff --git a/src/core/screen.c b/src/core/screen.c
index c6aa9e1..503c201 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -1286,21 +1286,25 @@ find_highest_logical_monitor_scale (MetaBackend      *backend,
     meta_backend_get_monitor_manager (backend);
   MetaCursorRenderer *cursor_renderer =
     meta_backend_get_cursor_renderer (backend);
-  MetaRectangle cursor_rect;
+  ClutterRect cursor_rect;
   GList *logical_monitors;
   GList *l;
   int highest_scale = 0.0;
 
   cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
-                                                     cursor_sprite);
+                                                    cursor_sprite);
 
   logical_monitors =
     meta_monitor_manager_get_logical_monitors (monitor_manager);
   for (l = logical_monitors; l; l = l->next)
     {
       MetaLogicalMonitor *logical_monitor = l->data;
+      ClutterRect logical_monitor_rect =
+             meta_rectangle_to_clutter_rect (&logical_monitor->rect);
 
-      if (!meta_rectangle_overlap (&cursor_rect, &logical_monitor->rect))
+      if (!clutter_rect_intersection (&cursor_rect,
+                                     &logical_monitor_rect,
+                                     NULL))
         continue;
 
       highest_scale = MAX (highest_scale, logical_monitor->scale);
diff --git a/src/wayland/meta-wayland-surface-role-cursor.c b/src/wayland/meta-wayland-surface-role-cursor.c
index 8e1a3ff..1c8ba94 100644
--- a/src/wayland/meta-wayland-surface-role-cursor.c
+++ b/src/wayland/meta-wayland-surface-role-cursor.c
@@ -30,6 +30,7 @@
 #include "meta-wayland-private.h"
 #include "backends/meta-backend-private.h"
 #include "backends/meta-logical-monitor.h"
+#include "core/boxes-private.h"
 
 typedef struct _MetaWaylandSurfaceRoleCursorPrivate MetaWaylandSurfaceRoleCursorPrivate;
 
@@ -194,11 +195,14 @@ cursor_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *role,
     META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
   MetaWaylandSurfaceRoleCursorPrivate *priv =
     meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
-  MetaRectangle rect;
+  ClutterRect rect;
+  ClutterRect logical_monitor_rect;
 
   rect = meta_cursor_renderer_calculate_rect (priv->cursor_renderer,
                                               priv->cursor_sprite);
-  return meta_rectangle_overlap (&rect, &logical_monitor->rect);
+  logical_monitor_rect =
+    meta_rectangle_to_clutter_rect (&logical_monitor->rect);
+  return clutter_rect_intersection (&rect, &logical_monitor_rect, NULL);
 }
 
 static void
diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c
index cd55f20..51f8fc9 100644
--- a/src/wayland/meta-wayland-tablet-tool.c
+++ b/src/wayland/meta-wayland-tablet-tool.c
@@ -921,8 +921,8 @@ meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool,
 
 void
 meta_wayland_tablet_tool_set_cursor_position (MetaWaylandTabletTool *tool,
-                                              int                    new_x,
-                                              int                    new_y)
+                                              float                  new_x,
+                                              float                  new_y)
 {
   if (tool->cursor_renderer)
     meta_cursor_renderer_set_position (tool->cursor_renderer, new_x, new_y);
diff --git a/src/wayland/meta-wayland-tablet-tool.h b/src/wayland/meta-wayland-tablet-tool.h
index 351abbc..8cd9300 100644
--- a/src/wayland/meta-wayland-tablet-tool.h
+++ b/src/wayland/meta-wayland-tablet-tool.h
@@ -79,8 +79,8 @@ gboolean meta_wayland_tablet_tool_handle_event        (MetaWaylandTabletTool  *t
                                                        const ClutterEvent     *event);
 
 void     meta_wayland_tablet_tool_set_cursor_position (MetaWaylandTabletTool  *tool,
-                                                       int                     new_x,
-                                                       int                     new_y);
+                                                       float                   new_x,
+                                                       float                   new_y);
 
 gboolean meta_wayland_tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool,
                                                     MetaWaylandSurface    *surface,


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