gegl r2200 - in trunk: . gegl/buffer



Author: ok
Date: Sat Apr 19 17:07:03 2008
New Revision: 2200
URL: http://svn.gnome.org/viewvc/gegl?rev=2200&view=rev

Log:
* gegl/buffer/gegl-buffer-index.h: new file with structures for on
disk serialization of indexes for tiles in files/on swap.
* gegl/buffer/gegl-buffer-save.[ch]: changed to use new structures
large amount of sanity code added.
* gegl/buffer/gegl-buffer-load.[ch]: adapted to use new structures.
* gegl/buffer/gegl-buffer-private.h: some stuff moved from here to
index.
* gegl/buffer/Makefile.am: added gegl-buffer-index.h


Added:
   trunk/gegl/buffer/gegl-buffer-index.h
Modified:
   trunk/ChangeLog
   trunk/gegl/buffer/Makefile.am
   trunk/gegl/buffer/gegl-buffer-load.c
   trunk/gegl/buffer/gegl-buffer-private.h
   trunk/gegl/buffer/gegl-buffer-save.c
   trunk/gegl/buffer/gegl-buffer-save.h

Modified: trunk/gegl/buffer/Makefile.am
==============================================================================
--- trunk/gegl/buffer/Makefile.am	(original)
+++ trunk/gegl/buffer/Makefile.am	Sat Apr 19 17:07:03 2008
@@ -4,6 +4,7 @@
     gegl-buffer.c		\
     gegl-buffer-access.c	\
     gegl-buffer-share.c		\
+    gegl-buffer-index.h		\
     gegl-buffer-save.c		\
     gegl-buffer-load.c		\
     gegl-cache.c		\

Added: trunk/gegl/buffer/gegl-buffer-index.h
==============================================================================
--- (empty file)
+++ trunk/gegl/buffer/gegl-buffer-index.h	Sat Apr 19 17:07:03 2008
@@ -0,0 +1,89 @@
+/* File format building blocks 
+
+GeglBuffer on disk representation
+=================================
+
+*/
+
+#define GEGL_MAGIC             {'G','E','G','L'}
+#define GEGL_FLAG_HEADER       1
+#define GEGL_FLAG_TILE         2
+#define GEGL_FLAG_TILE_IS_FREE 4
+#define GEGL_FLAG_TILE_FREE    (GEGL_FLAG_TILE|GEGL_FLAG_TILE_IS_FREE)
+
+
+/*
+ * This header is the first 256 bytes of the GEGL buffer.
+ */
+typedef struct {
+  gchar     magic[4];    /* - a 4 byte identifier */
+  guint32   flags;
+  guint64   next;        /* offset to next GeglBufferBlock */
+
+  guint32   tile_width;
+  guint32   tile_height;
+  guint16   bytes_per_pixel;
+
+  gchar     description[64]; /* GEGL stores the string of the babl format
+                              * here, as well as after the \0 a debug string
+                              * describing the buffer.
+                              */
+  gint32    x;               /* indication of bounding box for tiles stored. */
+  gint32    y;               /* this isn't really needed as each GeglBuffer as */
+  guint32   width;           /* represented on disk doesn't really have any */
+  guint32   height;          /* dimension restriction. */
+
+  guint32   entry_count;     /* for integrity check. */
+  gint32    padding[36];     /* Pad the structure to be 256 bytes long */
+} GeglBufferHeader;
+
+
+/* The GeglBuffer index is written to the file as a linked list with encoded
+ * offsets. Each element in the list has a GeglBufferBlock header, GeglBufferHeader
+ * abuses the length field to construct a magic marker to recognise the file.
+ */
+
+typedef struct {
+  guint32  length; /* the length of this block */
+  guint32  flags;  /* flags (can be used to handle different block types
+                    * differently
+                    */
+  guint64  next;   /*next block element in file */
+} GeglBufferBlock;
+
+/* The header is followed by elements describing tiles stored in the swap,
+ */
+typedef struct {
+  GeglBufferBlock blockdef; /* The block definition for this tile entry   */
+  gint32  x;                /* upperleft of tile % tile_width coordinates */
+  gint32  y;           
+
+  gint32  z;                /* mipmap subdivision level of tile (0=100%)  */
+  guint64 offset;           /* offset into file for this tile             */
+  guint32 padding[23];
+} GeglBufferTile;
+
+/* A convenience union to allow quick and simple casting */
+typedef union {
+  guint32           length;
+  GeglBufferBlock   block;
+  GeglBufferHeader  def;
+  GeglBufferTile    tile;
+} GeglBufferItem;
+
+#define struct_check_padding(type, size) \
+  if (sizeof (type) != size) \
+    {\
+      g_warning ("%s %s is %i bytes, should be %i padding is off by: %i bytes %i ints", G_STRFUNC, #type,\
+         (int) sizeof (type),\
+         size,\
+         (int) sizeof (type) - size,\
+         (int)(sizeof (type) - size) / 4);\
+      return;\
+    }
+#define GEGL_BUFFER_STRUCT_CHECK_PADDING \
+  {struct_check_padding (GeglBufferBlock, 16);\
+  struct_check_padding (GeglBufferHeader,   256);\
+  struct_check_padding (GeglBufferTile, 128);}
+#define GEGL_BUFFER_SANITY {static gboolean done=FALSE;if(!done){GEGL_BUFFER_STRUCT_CHECK_PADDING;done=TRUE;}}
+

Modified: trunk/gegl/buffer/gegl-buffer-load.c
==============================================================================
--- trunk/gegl/buffer/gegl-buffer-load.c	(original)
+++ trunk/gegl/buffer/gegl-buffer-load.c	Sat Apr 19 17:07:03 2008
@@ -50,19 +50,84 @@
 #include "gegl-buffer-save.h"
 #include "gegl-cache.h"
 #include "gegl-region.h"
+#include "gegl-buffer-index.h"
 
 typedef struct
 {
-  GeglBufferFileHeader header;
-  GList               *tiles;
-  gchar               *path;
-  gint                 fd;
-  gint                 tile_size;
-  gint                 x_tile_shift;
-  gint                 y_tile_shift;
-  Babl                *format;
+  GeglBufferHeader header;
+  GList           *tiles;
+  gchar           *path;
+  gint             fd;
+  gint             tile_size;
+  Babl            *format;
+  gint             pos;
+  glong            next_block;
+  gboolean         got_header;
 } LoadInfo;
 
+static GeglBufferItem *read_header (LoadInfo *info)
+{
+  GeglBufferBlock block;
+  GeglBufferItem *ret;
+
+  /* XXX: initialize synchronize buffer state */
+
+  if (info->pos != 0)
+    {
+      g_print ("%s must seek\n", G_STRFUNC);
+    }
+
+  info->pos += read (info->fd, &block, sizeof (GeglBufferBlock));
+
+  if (info->got_header)
+    {
+      ret = g_malloc (block.length);
+      memcpy (ret, &block, sizeof (GeglBufferBlock));
+      info->pos+=read (info->fd,  ((gchar*)ret) + sizeof(GeglBufferBlock),
+                       block.length - sizeof(GeglBufferBlock));
+    }
+  else
+    {
+      info->got_header = TRUE;
+      ret = g_malloc (sizeof (GeglBufferHeader));
+      memcpy (ret, &block, sizeof (GeglBufferBlock));
+      info->pos+=read (info->fd,  ((gchar*)ret) + sizeof(GeglBufferBlock),
+                       sizeof(GeglBufferHeader) - sizeof(GeglBufferBlock));
+    }
+  info->next_block = ret->block.next;
+  return ret;
+}
+
+
+static GeglBufferItem *read_block (LoadInfo *info)
+{
+  GeglBufferBlock block;
+  GeglBufferItem *ret;
+
+  if (info->pos != info->next_block)
+    {
+      g_print ("must seek\n");
+    }
+
+  info->pos+=read (info->fd, &block, sizeof (GeglBufferBlock));
+  if (info->got_header)
+    {
+      ret = g_malloc (block.length);
+      memcpy (ret, &block, sizeof (GeglBufferBlock));
+      info->pos+=read (info->fd,  ((gchar*)ret) + sizeof(GeglBufferBlock),
+                       block.length - sizeof(GeglBufferBlock));
+    }
+  else
+    {
+      info->got_header = TRUE;
+      ret = g_malloc (sizeof (GeglBufferHeader));
+      memcpy (ret, &block, sizeof (GeglBufferBlock));
+      info->pos+=read (info->fd,  ((gchar*)ret) + sizeof(GeglBufferBlock),
+                       sizeof(GeglBufferHeader) - sizeof(GeglBufferBlock));
+    }
+  info->next_block = ret->block.next;
+  return ret;
+}
 
 static void
 load_info_destroy (LoadInfo *info)
@@ -79,7 +144,7 @@
       GList *iter;
       for (iter = info->tiles; iter; iter = iter->next)
         {
-          g_slice_free (GeglTileEntry, iter->data);
+          g_free (iter->data);
         }
       g_list_free (info->tiles);
       info->tiles = NULL;
@@ -87,22 +152,14 @@
   g_slice_free (LoadInfo, info);
 }
 
+
 void
 gegl_buffer_load (GeglBuffer  *buffer,
                   const gchar *path)
 {
   LoadInfo *info = g_slice_new0 (LoadInfo);
 
-  if (sizeof (GeglBufferFileHeader) != 256)
-    {
-      g_warning ("GeglBufferFileHeader is %i bytes, should be 256 padding is off by: %i bytes %i ints", (int) sizeof (GeglBufferFileHeader), (int) sizeof (GeglBufferFileHeader) - 256, (int) (sizeof (GeglBufferFileHeader) - 256) / 4);
-      return;
-    }
-
-  if (!strcmp (info->header.magic, "_G_E_G_L"))
-    {
-      g_warning ("Magic is wrong!");
-    }
+  GEGL_BUFFER_SANITY;
 
   info->path = g_strdup (path);
   info->fd   = g_open (info->path, O_RDONLY, 0);
@@ -118,23 +175,35 @@
       return;
     }
 
-  read (info->fd, &(info->header), sizeof (GeglBufferFileHeader));
+  {
+    GeglBufferItem *header= read_header (info);
+    g_assert (header);
+    memcpy (&(info->header), header, sizeof (GeglBufferHeader));
+    /*g_free (header);*/  /* is there a pointer to a string or something we're missing? */
+  }
+
+
+  if (!(info->header.magic[0]=='G' &&
+       info->header.magic[1]=='E' &&
+       info->header.magic[2]=='G' &&
+       info->header.magic[3]=='L'))
+    {
+      g_warning ("Magic is wrong! %s", info->header.magic);
+    }
 
-  info->tile_size    = info->header.tile_width * info->header.tile_height * info->header.bpp;
-  info->format       = babl_format (info->header.format);
-  info->x_tile_shift = buffer->shift_x / info->header.tile_width;
-  info->y_tile_shift = buffer->shift_y / info->header.tile_height;
+  info->tile_size    = info->header.tile_width *
+                       info->header.tile_height *
+                       info->header.bytes_per_pixel;
+  info->format       = babl_format (info->header.description);
 
   /* load the index */
   {
     gint i;
-    for (i = 0; i < info->header.tile_count; i++)
+    for (i = 0; i < info->header.entry_count; i++)
       {
-        GeglTileEntry *entry = g_slice_new0 (GeglTileEntry);
-
-        read (info->fd, entry, sizeof (GeglTileEntry));
-
-        info->tiles = g_list_prepend (info->tiles, entry);
+        GeglBufferItem *item = read_block (info);
+        g_assert (item);
+        info->tiles = g_list_prepend (info->tiles, item);
       }
     info->tiles = g_list_reverse (info->tiles);
   }
@@ -145,32 +214,38 @@
     gint   i = 0;
     for (iter = info->tiles; iter; iter = iter->next)
       {
-        GeglTileEntry *entry = iter->data;
-        guchar        *data;
-        GeglTile      *tile;
-        gint           factor = 1 << entry->z;
+        GeglBufferTile *entry = iter->data;
+        guchar         *data;
+        GeglTile       *tile;
 
 
         tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (buffer),
-                                     entry->x + info->x_tile_shift / factor,
-                                     entry->y + info->y_tile_shift / factor,
-                                     entry->z);
+                                          entry->x,
+                                          entry->y,
+                                          entry->z);
         g_assert (tile);
         gegl_tile_lock (tile);
 
         data = gegl_tile_get_data (tile);
         g_assert (data);
 
-        read (info->fd, data, info->tile_size);
+        if (info->pos != entry->offset)
+          {
+            g_warning ("%s must seek", G_STRFUNC);
+          }
+
+        info->pos += read (info->fd, data, info->tile_size);
+        /*g_print ("%i %i\n", i, data[0]);
+        g_print ("%i %i %i   %i %i %i\n", entry->x, entry->y, entry->z, tile->x, tile->y, tile->z);*/
 
         gegl_tile_unlock (tile);
         g_object_unref (G_OBJECT (tile));
-        /*fprintf (stderr, "\r%f  %i %i %i  ", (1.0*i)/info->header.tile_count, entry->x - info->x_tile_shift, entry->y, entry->z);*/
         i++;
 
         if (GEGL_IS_CACHE (buffer) && entry->z == 0)
           {
             GeglRectangle rect;
+
             gegl_rectangle_set (&rect, entry->x * info->header.tile_width,
                                 entry->y * info->header.tile_height,
                                 info->header.tile_width,
@@ -181,6 +256,5 @@
     /*fprintf (stderr, "done      \n");*/
   }
 
-
   load_info_destroy (info);
 }

Modified: trunk/gegl/buffer/gegl-buffer-private.h
==============================================================================
--- trunk/gegl/buffer/gegl-buffer-private.h	(original)
+++ trunk/gegl/buffer/gegl-buffer-private.h	Sat Apr 19 17:07:03 2008
@@ -1,4 +1,5 @@
 /* This file is part of GEGL.
+ * ck
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public

Modified: trunk/gegl/buffer/gegl-buffer-save.c
==============================================================================
--- trunk/gegl/buffer/gegl-buffer-save.c	(original)
+++ trunk/gegl/buffer/gegl-buffer-save.c	Sat Apr 19 17:07:03 2008
@@ -54,26 +54,27 @@
 #include "gegl-types.h"
 #include "gegl-utils.h"
 #include "gegl-buffer-save.h"
+#include "gegl-buffer-index.h"
 
 typedef struct
 {
-  GeglBufferFileHeader header;
-  GList               *tiles;
-  gchar               *path;
-  gint                 fd;
-  gint                 tile_size;
-  gint                 x_tile_shift;
-  gint                 y_tile_shift;
-  gint                 offset;
+  GeglBufferHeader header;
+  GList           *tiles;
+  gchar           *path;
+  gint             fd;
+  gint             tile_size;
+  gint             x_tile_shift;
+  gint             y_tile_shift;
+  gint             offset;
 } SaveInfo;
 
 
-static GeglTileEntry *
+static GeglBufferTile *
 tile_entry_new (gint x,
                 gint y,
                 gint z)
 {
-  GeglTileEntry *entry = g_slice_new0 (GeglTileEntry);
+  GeglBufferTile *entry = g_slice_new0 (GeglBufferTile);
 
   entry->x = x;
   entry->y = y;
@@ -82,9 +83,9 @@
 }
 
 static void
-tile_entry_destroy (GeglTileEntry *entry)
+tile_entry_destroy (GeglBufferTile *entry)
 {
-  g_slice_free (GeglTileEntry, entry);
+  g_slice_free (GeglBufferTile, entry);
 }
 
 static void
@@ -110,7 +111,7 @@
 
 
 
-static glong z_order (const GeglTileEntry *entry)
+static glong z_order (const GeglBufferTile *entry)
 {
   glong value;
 
@@ -140,8 +141,8 @@
 static gint z_order_compare (gconstpointer a,
                              gconstpointer b)
 {
-  const GeglTileEntry *entryA = a;
-  const GeglTileEntry *entryB = b;
+  const GeglBufferTile *entryA = a;
+  const GeglBufferTile *entryB = b;
 
   return z_order (entryB) - z_order (entryA);
 }
@@ -153,16 +154,19 @@
 {
   SaveInfo *info = g_slice_new0 (SaveInfo);
 
-  if (sizeof (GeglBufferFileHeader) != 256)
-    {
-      g_warning ("GeglBufferFileHeader is %i bytes, should be 256 padding is off by: %i bytes %i ints",
-         (int) sizeof (GeglBufferFileHeader),
-         (int) sizeof (GeglBufferFileHeader) - 256,
-         (int)(sizeof (GeglBufferFileHeader) - 256) / 4);
-      return;
-    }
+  glong prediction = 0; 
+
+  GEGL_BUFFER_SANITY;
+
+  strcpy (info->header.magic, "GEGL");
+
+  /* a header should follow the same structure as a blockdef with
+   * respect to the flags and next offsets, thus this is a valid
+   * cast shortcut.
+   */
+  info->header.flags = GEGL_FLAG_HEADER;
+  info->header.next = (prediction += sizeof (GeglBufferHeader));
 
-  strcpy (info->header.magic, "_G_E_G_L");
   info->path = g_strdup (path);
   info->fd   = g_open (info->path,
                        O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
@@ -178,18 +182,29 @@
       return;
     }
 
-  info->header.width       = buffer->extent.width;
-  info->header.height      = buffer->extent.height;
-  info->header.x           = buffer->extent.x;
-  info->header.y           = buffer->extent.y;
   info->header.tile_width  = buffer->tile_storage->tile_width;
   info->header.tile_height = buffer->tile_storage->tile_height;
+  g_object_get (buffer, "px-size", &(info->header.bytes_per_pixel), NULL);
+  {
+    gchar buf[64];
+    g_snprintf (buf, 64, "%s%c\n%iÃ%i %ibpp\n\n\n\n\n\n\n\n\n\n", 
+          ((Babl *) (buffer->tile_storage->format))->instance.name, 0,
+          info->header.tile_width,
+          info->header.tile_height,
+          info->header.bytes_per_pixel);
+    memcpy (info->header.description, buf, 64);
+  }
 
-  g_object_get (buffer, "px-size", &(info->header.bpp), NULL);
-/*  = gegl_buffer_px_size (buffer);*/
+  info->header.x           = buffer->extent.x;
+  info->header.y           = buffer->extent.y;
+  info->header.width       = buffer->extent.width;
+  info->header.height      = buffer->extent.height;
+
+  info->tile_size = info->header.tile_width  *
+                    info->header.tile_height *
+                    info->header.bytes_per_pixel;
 
-  info->tile_size = info->header.tile_width * info->header.tile_height * info->header.bpp;
-  strcpy (info->header.format, ((Babl *) (buffer->tile_storage->format))->instance.name);
+  g_assert (info->tile_size % 16 == 0);
 
   /* collect list of tiles to be written */
   {
@@ -213,22 +228,21 @@
     info->x_tile_shift = -buffer->shift_x / tile_width;
     info->y_tile_shift = -buffer->shift_y / tile_height;
 
-
     {
       gint z;
       gint factor = 1;
-      for (z = 0; z < 10; z++)
+      for (z = 0; z < 1; z++)
         {
           bufy = y;
           while (bufy < buffer->extent.y + height)
             {
-              gint tiledy  = buffer->extent.y + buffer->shift_y + bufy;
+              gint tiledy  = buffer->extent.y + bufy;
               gint offsety = gegl_tile_offset (tiledy, tile_height);
               gint bufx    = x;
 
               while (bufx < buffer->extent.x + width)
                 {
-                  gint tiledx  = buffer->extent.x + bufx + buffer->shift_x;
+                  gint tiledx  = buffer->extent.x + bufx;
                   gint offsetx = gegl_tile_offset (tiledx, tile_width);
 
                   gint tx = gegl_tile_indice (tiledx / factor, tile_width);
@@ -236,12 +250,13 @@
 
                   if (gegl_tile_source_exist (GEGL_TILE_SOURCE (buffer), tx, ty, z))
                     {
-                      tx += info->x_tile_shift / factor;
-                      ty += info->y_tile_shift / factor;
+                      GeglBufferTile *entry;
 
-                      info->tiles = g_list_prepend (info->tiles,
-                                                    tile_entry_new (tx, ty, z));
-                      info->header.tile_count++;
+                      entry = tile_entry_new (tx, ty, z);
+                      entry->blockdef.length = sizeof (GeglBufferTile);
+                      entry->blockdef.flags = GEGL_FLAG_TILE;
+                      info->tiles = g_list_prepend (info->tiles, entry);
+                      info->header.entry_count++;
                     }
                   bufx += (tile_width - offsetx) * factor;
                 }
@@ -251,7 +266,10 @@
         }
     }
 
-    info->tiles = g_list_reverse (info->tiles);
+
+  /* XXX:why was the list reversed here when it is just about to be sorted?
+   */
+/*    info->tiles = g_list_reverse (info->tiles);*/
   }
 
   /* sort the list of tiles into zorder */
@@ -260,27 +278,36 @@
   /* set the offset in the file each tile will be stored on */
   {
     GList *iter;
-    gint   offset = sizeof (GeglBufferFileHeader) + sizeof (GeglTileEntry) * info->header.tile_count;
+    gint   predicted_offset = sizeof (GeglBufferHeader) + sizeof (GeglBufferTile) * (info->header.entry_count);
+    GeglBufferTile *last_entry = NULL;
 
     for (iter = info->tiles; iter; iter = iter->next)
       {
-        GeglTileEntry *entry = iter->data;
-        entry->offset = offset;
-        offset       += info->tile_size;
+        GeglBufferTile *entry = iter->data;
+        entry->blockdef.next = iter->next?
+                                (prediction += sizeof (GeglBufferTile)):0;
+        entry->offset = predicted_offset;
+        predicted_offset += info->tile_size;
+        last_entry = entry;
       }
+    last_entry->blockdef.next=0; /* terminate */
   }
 
   /* save the header */
-  info->offset += write (info->fd, &info->header, sizeof (GeglBufferFileHeader));
+  info->offset += write (info->fd, &info->header, sizeof (GeglBufferHeader));
+  g_assert (info->offset == info->header.next);
 
   /* save the index */
-
   {
     GList *iter;
     for (iter = info->tiles; iter; iter = iter->next)
       {
-        GeglTileEntry *entry = iter->data;
-        info->offset += write (info->fd, entry, sizeof (GeglTileEntry));
+        GeglBufferTile *entry = iter->data;
+        info->offset += write (info->fd, entry, sizeof (GeglBufferTile));
+        if (entry->blockdef.next)
+          {
+            g_assert (info->offset == entry->blockdef.next);
+          }
       }
   }
 
@@ -290,28 +317,24 @@
     gint   i = 0;
     for (iter = info->tiles; iter; iter = iter->next)
       {
-        GeglTileEntry *entry = iter->data;
-        guchar        *data;
-        GeglTile      *tile;
-        gint           factor = 1 << entry->z;
+        GeglBufferTile *entry = iter->data;
+        guchar          *data;
+        GeglTile        *tile;
 
         tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (buffer),
-                                     entry->x - info->x_tile_shift / factor,
-                                     entry->y - info->y_tile_shift / factor,
-                                     entry->z);
+                                          entry->x,
+                                          entry->y,
+                                          entry->z);
         g_assert (tile);
         data = gegl_tile_get_data (tile);
         g_assert (data);
 
+        g_assert (info->offset == entry->offset);
         info->offset += write (info->fd, data, info->tile_size);
         g_object_unref (G_OBJECT (tile));
-        /*fprintf (stderr, "\r%f%% (%ikb)", (1.0*i)/info->header.tile_count, info->offset /1024);*/
         i++;
       }
-    /*fprintf (stderr, "done      \n");*/
+    g_assert (i == info->header.entry_count);
   }
-
-
   save_info_destroy (info);
 }
-

Modified: trunk/gegl/buffer/gegl-buffer-save.h
==============================================================================
--- trunk/gegl/buffer/gegl-buffer-save.h	(original)
+++ trunk/gegl/buffer/gegl-buffer-save.h	Sat Apr 19 17:07:03 2008
@@ -23,27 +23,6 @@
 
 #include "gegl-buffer.h"
 
-typedef struct {
-  gchar magic[16];
-  gint  width, height, x, y;
-  gchar format[32];
-  guint tile_width, tile_height;
-  guint bpp;
-  gint  tile_count;
-
-  guint padding1[12];
-  guint padding[32];
-} GeglBufferFileHeader;
-
-typedef struct {
-  gint  x;
-  gint  y;
-  gint  z;
-  guint offset;  /* offset into file */
-  guint flags;   /* flags? not used? */
-
-  guint padding1[8];
-} GeglTileEntry;
 
 void gegl_buffer_save (GeglBuffer          *buffer,
                        const gchar         *path,



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