Author: jannis
Date: 2007-01-10 23:04:24 +0000 (Wed, 10 Jan 2007)
New Revision: 24350

Modified:
   libfrap/trunk/libfrap/menu/ChangeLog
   libfrap/trunk/libfrap/menu/STATUS
   libfrap/trunk/libfrap/menu/frap-menu-item-cache.c
   libfrap/trunk/libfrap/menu/frap-menu-item-pool.c
   libfrap/trunk/libfrap/menu/frap-menu-item.c
   libfrap/trunk/libfrap/menu/frap-menu-item.h
   libfrap/trunk/libfrap/menu/frap-menu.c
Log:
        * frap-menu-item.{c,h}: Remove "allocated" property and replace it
          with a kind of reference counter. Add frap_menu_item_ref/unref 
          methods to be used instead of frap_menu_item_set_allocated() which
          has been removed. Use "guint ... : 1" notation for boolean values
          in the structs belonging to FrapMenuItem. 
        * frap-menu-item-pool.c: Call frap_menu_item_ref when adding an item
          to the pool of a menu (instead of setting the allocated value 
          directly).
        * frap-menu.c: Use "guint ... : 1" notation for boolean values in
          structs. Fix frap_menu_set_filename to make free'ing the filename
          possible. Implement recursive (bottom -> top) collecting of 
          directory and legacy dirs (might be wrong for legacy dirs, I need 
          to verify this during the next days). Implement two-pass mechanism 
          to resolve menu items (in order to be able to handle 
          <OnlyUnallocated> elements). Only set menu parse state to 
          _STATE_ROOT if there are no other menus left on the stack.
        * STATUS: Update implementation STATUS.

Modified: libfrap/trunk/libfrap/menu/ChangeLog
===================================================================
--- libfrap/trunk/libfrap/menu/ChangeLog        2007-01-10 22:58:45 UTC (rev 
24349)
+++ libfrap/trunk/libfrap/menu/ChangeLog        2007-01-10 23:04:24 UTC (rev 
24350)
@@ -1,3 +1,23 @@
+2007-01-11     Jannis Pohlmann <[EMAIL PROTECTED]>
+
+       * frap-menu-item.{c,h}: Remove "allocated" property and replace it
+         with a kind of reference counter. Add frap_menu_item_ref/unref 
+         methods to be used instead of frap_menu_item_set_allocated() which
+         has been removed. Use "guint ... : 1" notation for boolean values
+         in the structs belonging to FrapMenuItem. 
+       * frap-menu-item-pool.c: Call frap_menu_item_ref when adding an item
+         to the pool of a menu (instead of setting the allocated value 
+         directly).
+       * frap-menu.c: Use "guint ... : 1" notation for boolean values in
+         structs. Fix frap_menu_set_filename to make free'ing the filename
+         possible. Implement recursive (bottom -> top) collecting of 
+         directory and legacy dirs (might be wrong for legacy dirs, I need 
+         to verify this during the next days). Implement two-pass mechanism 
+         to resolve menu items (in order to be able to handle 
+         <OnlyUnallocated> elements). Only set menu parse state to 
+         _STATE_ROOT if there are no other menus left on the stack.
+       * STATUS: Update implementation STATUS.
+
 2006-11-07     Jannis Pohlmann <[EMAIL PROTECTED]>
 
        * frap-menu-item-pool.c: Fix backwards compatibility by passing 

Modified: libfrap/trunk/libfrap/menu/STATUS
===================================================================
--- libfrap/trunk/libfrap/menu/STATUS   2007-01-10 22:58:45 UTC (rev 24349)
+++ libfrap/trunk/libfrap/menu/STATUS   2007-01-10 23:04:24 UTC (rev 24350)
@@ -25,6 +25,9 @@
   [x] <Directory>
 
   [x] <OnlyUnallocated> and <NotOnlyUnallocated>
+
+        Supported by using a two-pass resolving mechanism as stated
+        in the spec ("Generating the menus").
   
   [x] <Deleted> and <NotDeleted>
 
@@ -61,8 +64,10 @@
 
   [-] <LegacyDir>
       
-        <LegacyDir> elements are parsed into a string list, but there is
-        no further parsing or merging performed afterwards - not yet.
+        <LegacyDir> elements are parsed and added to the menus 
+        which contain them in the menu file. Legacy menus are created
+        for legacy dirs with a .directory file. However, their desktop
+        files are not parsed yet.
 
   [-] <DefaultLegacyDirs>
     

Modified: libfrap/trunk/libfrap/menu/frap-menu-item-cache.c
===================================================================
--- libfrap/trunk/libfrap/menu/frap-menu-item-cache.c   2007-01-10 22:58:45 UTC 
(rev 24349)
+++ libfrap/trunk/libfrap/menu/frap-menu-item-cache.c   2007-01-10 23:04:24 UTC 
(rev 24350)
@@ -277,7 +277,8 @@
           /* Add item to the hash table */
           g_hash_table_replace (cache->priv->items, g_strdup (filename), item);
 
-          /* Grab a reference on the item */
+          /* Grab a reference on the item, but don't increase the allocation
+           * counter */
           g_object_ref (G_OBJECT (item));
 
           return item;
@@ -298,7 +299,7 @@
       /* The file has been loaded, add the item to the hash table */
       g_hash_table_replace (cache->priv->items, g_strdup (filename), item);
 
-      /* Grab a reference on it */
+      /* Grab a reference on it but don't increase the allocation counter */
       g_object_ref (G_OBJECT (item));
     }
 

Modified: libfrap/trunk/libfrap/menu/frap-menu-item-pool.c
===================================================================
--- libfrap/trunk/libfrap/menu/frap-menu-item-pool.c    2007-01-10 22:58:45 UTC 
(rev 24349)
+++ libfrap/trunk/libfrap/menu/frap-menu-item-pool.c    2007-01-10 23:04:24 UTC 
(rev 24350)
@@ -158,11 +158,8 @@
   /* Insert into the hash table and remove old item (if any) */
   g_hash_table_replace (pool->priv->items, g_strdup 
(frap_menu_item_get_desktop_id (item)), item);
 
-  /* Set allocation state of the item */
-  frap_menu_item_set_allocated (item, TRUE);
-
   /* Grab a reference on the item */
-  g_object_ref (G_OBJECT (item));
+  frap_menu_item_ref (item);
 }
 
 

Modified: libfrap/trunk/libfrap/menu/frap-menu-item.c
===================================================================
--- libfrap/trunk/libfrap/menu/frap-menu-item.c 2007-01-10 22:58:45 UTC (rev 
24349)
+++ libfrap/trunk/libfrap/menu/frap-menu-item.c 2007-01-10 23:04:24 UTC (rev 
24350)
@@ -46,7 +46,6 @@
   PROP_NAME,
   PROP_ICON_NAME,
   PROP_COMMAND,
-  PROP_ALLOCATED,
 };
 
 
@@ -83,13 +82,13 @@
   GList    *categories;
 
   /* Whether this application requires a terminal to be started in */
-  gboolean  requires_terminal;
+  guint     requires_terminal : 1;
 
   /* Whether this menu item should be hidden */
-  gboolean  hidden;
+  guint     hidden : 1;
 
   /* Whether this application supports startup notification */
-  gboolean  supports_startup_notification;
+  guint     supports_startup_notification : 1;
 
   /* Name to be displayed for the menu item */
   gchar    *name;
@@ -100,8 +99,10 @@
   /* Menu item icon name */
   gchar    *icon_name;
 
-  /* Whether this menu item is allocated by a menu */
-  gboolean  allocated;
+  /* Counter keeping the number of menus which use this item. This works
+   * like a reference counter and should be increased / decreased by FrapMenu
+   * items whenever the item is added to or removed from the menu. */
+  guint     num_allocated;
 };
 
 struct _FrapMenuItem
@@ -267,19 +268,6 @@
                                                         _("Name of the 
application icon"),
                                                         NULL,
                                                         G_PARAM_READWRITE));
-
-  /**
-   * FrapMenuItem:allocated:
-   *
-   * Whether this item is allocated by a menu.
-   **/
-  g_object_class_install_property (gobject_class,
-                                   PROP_ICON_NAME,
-                                   g_param_spec_boolean ("allocated",
-                                                         _("Allocated"),
-                                                         _("Allocation state 
of the item"),
-                                                         FALSE,
-                                                         G_PARAM_READWRITE));
 }
 
 
@@ -294,6 +282,7 @@
   item->priv->command = NULL;
   item->priv->icon_name = NULL;
   item->priv->categories = NULL;
+  item->priv->num_allocated = 0;
 }
 
 
@@ -352,10 +341,6 @@
     case PROP_ICON_NAME:
       break;
 
-    case PROP_ALLOCATED:
-      g_value_set_boolean (value, frap_menu_item_get_allocated (item));
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -406,10 +391,6 @@
       frap_menu_item_set_icon_name (item, g_value_get_string (value));
       break;
 
-    case PROP_ALLOCATED:
-      frap_menu_item_set_allocated (item, g_value_get_boolean (value));
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -826,8 +807,28 @@
 
 
 void
+frap_menu_item_ref (FrapMenuItem *item)
+{
+  g_return_if_fail (FRAP_IS_MENU_ITEM (item));
+
+  /* Increment the allocation counter */
+  frap_menu_item_increment_allocated (item);
+
+  /* Grab a reference on the object */
+  g_object_ref (G_OBJECT (item));
+}
+
+
+
+void
 frap_menu_item_unref (FrapMenuItem *item)
 {
+  g_return_if_fail (FRAP_IS_MENU_ITEM (item));
+
+  /* Decrement allocation counter */
+  frap_menu_item_decrement_allocated (item);
+
+  /* Decrement the reference counter */
   g_object_unref (G_OBJECT (item));
 }
 
@@ -837,21 +838,25 @@
 frap_menu_item_get_allocated (FrapMenuItem *item)
 {
   g_return_val_if_fail (FRAP_IS_MENU_ITEM (item), FALSE);
-  return item->priv->allocated;
+  return item->priv->num_allocated > 0;
 }
 
 
 
 void
-frap_menu_item_set_allocated (FrapMenuItem *item,
-                              gboolean      allocated)
+frap_menu_item_increment_allocated (FrapMenuItem *item)
 {
   g_return_if_fail (FRAP_IS_MENU_ITEM (item));
+  item->priv->num_allocated++;
+}
 
-  if (item->priv->allocated == allocated)
-    return;
 
-  item->priv->allocated = allocated;
 
-  g_object_notify (G_OBJECT (item), "allocated");
+void
+frap_menu_item_decrement_allocated (FrapMenuItem *item)
+{
+  g_return_if_fail (FRAP_IS_MENU_ITEM (item));
+
+  if (item->priv->num_allocated > 0)
+    item->priv->num_allocated--;
 }

Modified: libfrap/trunk/libfrap/menu/frap-menu-item.h
===================================================================
--- libfrap/trunk/libfrap/menu/frap-menu-item.h 2007-01-10 22:58:45 UTC (rev 
24349)
+++ libfrap/trunk/libfrap/menu/frap-menu-item.h 2007-01-10 23:04:24 UTC (rev 
24350)
@@ -73,10 +73,11 @@
 GList        *frap_menu_item_get_categories                    (FrapMenuItem 
*item);
 void          frap_menu_item_set_categories                    (FrapMenuItem 
*item,
                                                                 GList        
*categories);
+void          frap_menu_item_ref                               (FrapMenuItem 
*item);
 void          frap_menu_item_unref                             (FrapMenuItem 
*item);
 gboolean      frap_menu_item_get_allocated                     (FrapMenuItem 
*item);
-void          frap_menu_item_set_allocated                     (FrapMenuItem 
*item,
-                                                                gboolean      
allocated);
+void          frap_menu_item_increment_allocated               (FrapMenuItem 
*item);
+void          frap_menu_item_decrement_allocated               (FrapMenuItem 
*item);
 
 G_END_DECLS;
 

Modified: libfrap/trunk/libfrap/menu/frap-menu.c
===================================================================
--- libfrap/trunk/libfrap/menu/frap-menu.c      2007-01-10 22:58:45 UTC (rev 
24349)
+++ libfrap/trunk/libfrap/menu/frap-menu.c      2007-01-10 23:04:24 UTC (rev 
24350)
@@ -237,7 +237,8 @@
                                                                             
FrapMenuRules         *rules);
 static void               frap_menu_add_move                               
(FrapMenu              *menu,
                                                                             
FrapMenuMove          *move);
-static void               frap_menu_resolve_items                          
(FrapMenu              *menu);
+static void               frap_menu_resolve_items                          
(FrapMenu              *menu,
+                                                                            
gboolean               only_unallocated);
 static void               frap_menu_resolve_items_from_path                
(FrapMenu              *menu,
                                                                             
const gchar           *path,
                                                                             
const gchar           *id_prefix);
@@ -273,10 +274,10 @@
   GSList            *app_dirs;
 
   /* Only include desktop entries not used in other menus */
-  gboolean           only_unallocated;
+  guint              only_unallocated : 1;
 
   /* Whether this menu should be ignored or not */
-  gboolean           deleted;
+  guint              deleted : 1;
 
   /* Include/exclude rules */
   GSList            *rules;
@@ -674,12 +675,11 @@
 frap_menu_set_filename (FrapMenu *menu, const gchar *filename)
 {
   g_return_if_fail (FRAP_IS_MENU (menu));
-  g_return_if_fail (filename != NULL);
 
   /* Abort if filenames are equal */
   if (G_UNLIKELY (menu->priv->filename != NULL))
     {
-      if (G_UNLIKELY (g_utf8_collate (filename, menu->priv->filename) == 0))
+      if (G_UNLIKELY (filename != NULL && g_utf8_collate (filename, 
menu->priv->filename) == 0))
         return;
 
       /* Free old filename */
@@ -828,9 +828,39 @@
 GSList*
 frap_menu_get_directory_dirs (FrapMenu *menu)
 {
+  FrapMenu *current_menu;
+  GSList   *directories = NULL;
+  GList    *menus = NULL;
+  GList    *iter;
+  GSList    *iter2;
+  
   g_return_val_if_fail (FRAP_IS_MENU (menu), NULL);
-  /* TODO collect directories from the bottom up to the root menu */
-  return menu->priv->directory_dirs;
+
+  /* Collect all menus from menu -> parent -> ... -> root */
+  for (current_menu = menu; current_menu != NULL; current_menu = 
current_menu->priv->parent)
+    menus = g_list_prepend (menus, current_menu);
+
+  /* Iterate over all menus from root -> parent -> ... -> menu */
+  for (iter = menus; iter != NULL; iter = g_list_next (iter))
+    {
+      /* Fetch current menu */
+      current_menu = FRAP_MENU (iter->data);
+
+      /* Iterate over all directory dirs */
+      for (iter2 = current_menu->priv->directory_dirs; iter2 != NULL; iter2 = 
g_slist_next (iter2))
+        {
+          /* Append directory dir to the list */
+          directories = g_slist_append (directories, iter2->data);
+        }
+
+      /* Free the directory dir list */
+      g_slist_free (iter2);
+    }
+
+  /* Free menu list */
+  g_list_free (menus);
+
+  return directories;
 }
 
 
@@ -838,11 +868,44 @@
 GSList*
 frap_menu_get_legacy_dirs (FrapMenu *menu)
 {
+  /* FIXME: Collecting legacy dirs from the bottom up might be wrong. Perhaps
+   *        only <Menu> items with <LegacyDir> elements are allowed to parse
+   *        legacy menu hierarchies - verify this!
+   */
+
+  FrapMenu *current_menu;
+  GSList   *directories = NULL;
+  GList    *menus = NULL;
+  GList    *iter;
+  GSList    *iter2;
+  
   g_return_val_if_fail (FRAP_IS_MENU (menu), NULL);
-  /* TODO collect directories from the bottom up to the root menu - does the
-   * spec treat legacy dirs differently than app dirs and directory dirs?
-   * */
-  return menu->priv->legacy_dirs;
+
+  /* Collect all menus from menu -> parent -> ... -> root */
+  for (current_menu = menu; current_menu != NULL; current_menu = 
current_menu->priv->parent)
+    menus = g_list_prepend (menus, current_menu);
+
+  /* Iterate over all menus from root -> parent -> ... -> menu */
+  for (iter = menus; iter != NULL; iter = g_list_next (iter))
+    {
+      /* Fetch current menu */
+      current_menu = FRAP_MENU (iter->data);
+
+      /* Iterate over all legacy directories */
+      for (iter2 = current_menu->priv->legacy_dirs; iter2 != NULL; iter2 = 
g_slist_next (iter2))
+        {
+          /* Append legacy dir to the list */
+          directories = g_slist_append (directories, iter2->data);
+        }
+
+      /* Free the legacy dir list */
+      g_slist_free (iter2);
+    }
+
+  /* Free menu list */
+  g_list_free (menus);
+
+  return directories;
 }
 
 
@@ -963,12 +1026,16 @@
   g_list_free (menu_context.menu_stack);
   g_list_free (menu_context.rule_stack);
 
+#if 0
   frap_menu_resolve_legacy_menus (menu);
+#endif
   frap_menu_remove_duplicates (menu);
   frap_menu_resolve_directory (menu);
   frap_menu_resolve_moves (menu);
   frap_menu_resolve_deleted (menu);
-  frap_menu_resolve_items (menu);
+
+  frap_menu_resolve_items (menu, FALSE);
+  frap_menu_resolve_items (menu, TRUE);
 }
 
 
@@ -1068,11 +1135,8 @@
       else if (g_utf8_collate (element_name, "Menu") == 0)
         {
           /* Create new menu */
-          FrapMenu *menu = g_object_new (FRAP_TYPE_MENU, NULL);
+          FrapMenu *menu = g_object_new (FRAP_TYPE_MENU, "filename", 
current_menu->priv->filename, NULL);
 
-          /* Silently copy filename attribute from the current menu */
-          menu->priv->filename = g_strdup (current_menu->priv->filename);
-
           /* Add menu as submenu to the current menu */
           frap_menu_add_menu (current_menu, menu); 
 
@@ -1189,8 +1253,10 @@
           /* Remove current menu from stack */
           menu_context->menu_stack = g_list_delete_link 
(menu_context->menu_stack, g_list_first (menu_context->menu_stack));
 
-          /* Set parse state */
-          menu_context->state = FRAP_MENU_PARSE_STATE_ROOT;
+          /* Set parse state to _STATE_ROOT only if there are no other menus
+           * left on the stack. Otherwise, we're still inside a <Menu> 
element. */
+          if (G_LIKELY (g_list_length (menu_context->menu_stack) == 1))
+            menu_context->state = FRAP_MENU_PARSE_STATE_ROOT;
         }
       break;
 
@@ -1518,7 +1584,7 @@
           gchar *kde_bin_dir = g_build_path (G_DIR_SEPARATOR_S, kde_dir, 
"bin", NULL);
           
           /* Expand PATH to include KDEDIR/bin - if necessary */
-          gchar *occurence = g_strrstr (path, kde_bin_dir);
+          const gchar *occurence = g_strrstr (path, kde_bin_dir);
           if (G_LIKELY (occurence == NULL))
             {
               /* PATH = $PATH:$KDEDIR/bin */
@@ -1530,8 +1596,6 @@
               /* Free expanded PATH value */
               g_free (kde_path);
             }
-          else
-            g_free (occurence);
               
           /* Free KDEDIR/bin */
           g_free (kde_bin_dir);
@@ -1596,11 +1660,35 @@
 {
   int    i;
   gchar *path;
+  gchar *kde_data_dir;
+  const gchar *kde_dir;
 
   const gchar * const *dirs;
 
   g_return_if_fail (FRAP_IS_MENU (menu));
 
+  /* Append $KDEDIR/share/applications as a workaround for distributions 
+   * not installing KDE menu files properly into $XDG_DATA_DIR */
+
+  /* Get KDEDIR environment variable */
+  kde_dir = g_getenv ("KDEDIR");
+
+  /* Check if this variable is set */
+  if (G_UNLIKELY (kde_dir != NULL))
+    {
+      /* Build KDE data dir */
+      kde_data_dir = g_build_filename (kde_dir, "share", "applications", NULL);
+
+      /* Add it as an app dir if it exists */
+      if (G_LIKELY (g_file_test (kde_data_dir, G_FILE_TEST_IS_DIR)))
+        frap_menu_add_app_dir (menu, kde_data_dir);
+
+      /* Free the KDE data dir */
+      g_free (kde_data_dir);
+    }
+
+  /* The $KDEDIR workaround ends here */
+
   /* Append system-wide data dirs */
   dirs = g_get_system_data_dirs ();
   for (i = 0; dirs[i] != NULL; i++)
@@ -1747,10 +1835,14 @@
       /* Build absolute filename for this entry */
       absolute_filename = g_build_filename (path, filename, NULL);
 
-      /* Check if we have a .directory entry */
-      if (G_UNLIKELY (g_utf8_collate (".directory", filename) == 0)) 
+      if (g_file_test (absolute_filename, G_FILE_TEST_IS_DIR))
         {
-          /* Create the directory object for the legacy menu */
+          /* We have a subdir -> create another legacy menu for this 
subdirectory */
+          frap_menu_resolve_legacy_menu (legacy_menu, absolute_filename);
+        }
+      else if (g_utf8_collate (".directory", filename) == 0) 
+        {
+          /* We have a .directory file -> create the directory object for the 
legacy menu */
           directory = g_object_new (FRAP_TYPE_MENU_DIRECTORY, "filename", 
absolute_filename, NULL);
         }
     }
@@ -1765,6 +1857,7 @@
       /* Add legacy menu to its new parent */
       frap_menu_add_menu (menu, legacy_menu);
     }
+  else
     {
       /* Destroy the legacy menu again - no .directory file found */
       g_object_unref (legacy_menu);
@@ -1848,6 +1941,8 @@
       g_slist_foreach (submenu->priv->app_dirs, (GFunc) 
frap_menu_merge_app_dir, merged_menu);
       g_slist_foreach (submenu->priv->rules, (GFunc) frap_menu_merge_rule, 
merged_menu);
 
+      /* TODO Merge submenus of submenu and merged_menu! */
+
       /* Add merged menu to the new list of submenus if not included already */
       if (g_slist_find (merged_submenus, merged_menu) == NULL)
         merged_submenus = g_slist_append (merged_submenus, merged_menu);
@@ -2067,7 +2162,8 @@
 
 
 static void
-frap_menu_resolve_items (FrapMenu *menu)
+frap_menu_resolve_items (FrapMenu *menu,
+                         gboolean  only_unallocated)
 {
   GSList      *iter;
   GDir        *dir;
@@ -2077,21 +2173,28 @@
 
   /* TODO Remove all items from the pool if there are no include rules! */
 
-  /* Iterate over all application directories */
-  for (iter = frap_menu_get_app_dirs (menu); iter != NULL; iter = g_slist_next 
(iter))
+  /* Resolve items in this menu (if it matches the only_unallocated argument.
+   * This means that in the first pass, all items of menus without 
+   * <OnlyUnallocated /> are resolved and in the second pass, only items of 
+   * menus with <OnlyUnallocated /> are resolved */
+  if (menu->priv->only_unallocated == only_unallocated)
     {
-      /* Resolve items in the current directory */
-      frap_menu_resolve_items_from_path (menu, iter->data, NULL);
+      /* Iterate over all application directories */
+      for (iter = frap_menu_get_app_dirs (menu); iter != NULL; iter = 
g_slist_next (iter))
+        {
+          /* Resolve items in the current directory */
+          frap_menu_resolve_items_from_path (menu, iter->data, NULL);
+        }
+
+      /* Filter items according to the include/exclude rules */
+      frap_menu_item_pool_apply_rules (menu->priv->pool, menu->priv->rules);
     }
 
-  /* Filter items according to the include/exclude rules */
-  frap_menu_item_pool_apply_rules (menu->priv->pool, menu->priv->rules);
-
   /* Iterate over all submenus */
   for (iter = menu->priv->submenus; iter != NULL; iter = g_slist_next (iter))
     {
       /* Resolve items of the submenu */
-      frap_menu_resolve_items (FRAP_MENU (iter->data));
+      frap_menu_resolve_items (FRAP_MENU (iter->data), only_unallocated);
     }
 }
 
@@ -2264,6 +2367,10 @@
               /* Remove submenu from the submenu list */
               menu->priv->submenus = g_slist_remove (menu->priv->submenus, 
submenu);
 
+              /* TODO Merge submenus of submenu and target_submenu. Perhaps 
even
+               * find a better way for merging menus as the current way is a)
+               * duplicated (see consolidate_child_menus) and b) buggy */
+
               /* TODO Free the submenu - this introduces a strange item pool
                * error ... */
               /* g_object_unref (submenu); */

_______________________________________________
Xfce4-commits mailing list
Xfce4-commits@xfce.org
http://foo-projects.org/mailman/listinfo/xfce4-commits

Reply via email to