[Xfce4-commits] <xfce4-panel:devel> Merge branch 'devel' of ssh://git.xfce.org/git/xfce/xfce4-panel into devel

Nick Schermer noreply at xfce.org
Sun Feb 14 23:06:04 CET 2010


Updating branch refs/heads/devel
         to 802cc67eef69217f2806d41031b4e2abd12df114 (commit)
       from 33cc0f4d45d68610cc2cdaaec362d2822bcd9d38 (commit)

commit 802cc67eef69217f2806d41031b4e2abd12df114
Merge: 33cc0f4d45d68610cc2cdaaec362d2822bcd9d38 cea9874cd4faf7a44b6f06e125ac521ef41191ce
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Feb 14 15:59:24 2010 +0100

    Merge branch 'devel' of ssh://git.xfce.org/git/xfce/xfce4-panel into devel

commit cea9874cd4faf7a44b6f06e125ac521ef41191ce
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Feb 14 14:26:00 2010 +0100

    Sort hidden files above other files.

commit badf715a559ca528ba327fe3c0efb41bd0244abf
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Feb 14 14:18:44 2010 +0100

    Make sure we properly link against gio.

commit 5153b87ee4b80ce18aafc0e8cc7bb86a3402b6bb
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Feb 14 14:13:00 2010 +0100

    We need to name, display name is a gio 2.24 feature.

commit 447389333618d99fe5a0469ada66bcdbebf113b5
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Feb 14 14:04:50 2010 +0100

    Fix segfault because desktop info is not null.

commit 0f249074e9a61777bb0fc137bd40216413e1c808
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Feb 14 13:40:22 2010 +0100

    Plug leak and fix error in directorymenu plugin.

commit 77b5cabf883af7dd440b5082bc96d4d5c845678f
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Feb 13 18:56:44 2010 +0100

    Add new plugin directory menu.
    
    Plugin to walk to a directory tree using a menu. Folders
    are loaded on the fly and desktop files are handled
    like menu items (unix only).
    It is also possible to set a file pattern to allow files
    in the menu (instead of only directories). The files are
    opened in the default handler.

commit 0b7dc9f0180fb888af8e6f2a912ae92d254f7672
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Feb 13 17:26:04 2010 +0100

    Allow launcher creation from add dialog.

 configure.ac.in                                    |    8 +
 panel/panel-application.c                          |    3 +-
 plugins/Makefile.am                                |    1 +
 plugins/{windowmenu => directorymenu}/Makefile.am  |   49 +-
 .../directorymenu-dialog.glade}                    |  154 ++--
 plugins/directorymenu/directorymenu.c              |  881 ++++++++++++++++++++
 plugins/directorymenu/directorymenu.desktop.in     |    8 +
 plugins/directorymenu/directorymenu.h              |   42 +
 .../xfce4-popup-directorymenu.in}                  |    4 +-
 plugins/launcher/Makefile.am                       |    2 +
 plugins/launcher/launcher.c                        |    1 +
 po/POTFILES.in                                     |    3 +
 12 files changed, 1054 insertions(+), 102 deletions(-)

diff --git a/configure.ac.in b/configure.ac.in
index ced5759..e15c55e 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -111,11 +111,18 @@ XDT_CHECK_PACKAGE([XFCONF], [libxfconf-0], [4.7.1])
 XDT_CHECK_PACKAGE([EXO], [exo-1], [0.5.1])
 XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.14.0])
 XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.18.0])
+XDT_CHECK_PACKAGE([GIO], [gio-2.0], [2.18.0])
 XDT_CHECK_PACKAGE([GMODULE], [gmodule-2.0], [2.18.0])
 XDT_CHECK_PACKAGE([DBUS], [dbus-glib-1], [0.73])
 XDT_CHECK_PACKAGE([CAIRO], [cairo], [1.0.0])
 XDT_CHECK_PACKAGE([LIBWNCK], [libwnck-1.0], [2.22])
 
+dnl **********************************
+dnl *** Optional GIO UNIX features ***
+dnl **********************************
+XDT_CHECK_OPTIONAL_PACKAGE([GIO_UNIX], [gio-unix-2.0],
+                           [2.18.0], [gio-unix], [GIO UNIX features])
+
 dnl *************************
 dnl *** Check for gtk-doc ***
 dnl *************************
@@ -199,6 +206,7 @@ wrapper/Makefile
 plugins/Makefile
 plugins/actions/Makefile
 plugins/clock/Makefile
+plugins/directorymenu/Makefile
 plugins/launcher/Makefile
 plugins/pager/Makefile
 plugins/separator/Makefile
diff --git a/panel/panel-application.c b/panel/panel-application.c
index 4112311..b0aa3f2 100644
--- a/panel/panel-application.c
+++ b/panel/panel-application.c
@@ -149,8 +149,7 @@ static const GtkTargetEntry drop_targets[] =
     GTK_TARGET_SAME_APP, TARGET_PLUGIN_NAME },
   { "xfce-panel/plugin-widget",
     GTK_TARGET_SAME_APP, TARGET_PLUGIN_WIDGET },
-  { "text/uri-list",
-    GTK_TARGET_OTHER_APP, TARGET_TEXT_URI_LIST }
+  { "text/uri-list", 0, TARGET_TEXT_URI_LIST }
 };
 
 
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index abd2653..70540b2 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -2,6 +2,7 @@
 SUBDIRS = \
 	actions \
 	clock \
+	directorymenu \
 	launcher \
 	pager \
 	separator \
diff --git a/plugins/windowmenu/Makefile.am b/plugins/directorymenu/Makefile.am
similarity index 60%
copy from plugins/windowmenu/Makefile.am
copy to plugins/directorymenu/Makefile.am
index 78711a2..2bc0762 100644
--- a/plugins/windowmenu/Makefile.am
+++ b/plugins/directorymenu/Makefile.am
@@ -1,72 +1,73 @@
 
 INCLUDES = \
 	-I$(top_srcdir) \
-	-DG_LOG_DOMAIN=\"libwindowmenu\" \
-	-DWNCK_I_KNOW_THIS_IS_UNSTABLE \
+	-DG_LOG_DOMAIN=\"libdirectorymenu\" \
 	$(PLATFORM_CPPFLAGS)
 
 plugindir = $(libdir)/xfce4/panel-plugins
 
 plugin_LTLIBRARIES = \
-	libwindowmenu.la
+	libdirectorymenu.la
 
-libwindowmenu_built_sources = \
-	windowmenu-dialog_ui.h
+libdirectorymenu_built_sources = \
+	directorymenu-dialog_ui.h
 
-libwindowmenu_la_SOURCES = \
-	$(libwindowmenu_built_sources) \
-	windowmenu.c \
-	windowmenu.h
+libdirectorymenu_la_SOURCES = \
+	$(libdirectorymenu_built_sources) \
+	directorymenu.c \
+	directorymenu.h
 
-libwindowmenu_la_CFLAGS = \
+libdirectorymenu_la_CFLAGS = \
 	$(GTK_CFLAGS) \
 	$(EXO_CFLAGS) \
 	$(XFCONF_CFLAGS) \
 	$(LIBXFCE4UTIL_CFLAGS) \
 	$(LIBXFCE4UI_CFLAGS) \
-	$(LIBWNCK_CFLAGS) \
+	$(GIO_CFLAGS) \
+	$(GIO_UNIX_CFLAGS) \
 	$(PLATFORM_CFLAGS)
 
-libwindowmenu_la_LDFLAGS = \
+libdirectorymenu_la_LDFLAGS = \
 	-avoid-version \
 	-module \
 	-no-undefined \
 	-export-symbols-regex '^xfce_panel_module_(preinit|init|construct)' \
 	$(PLATFORM_LDFLAGS)
 
-libwindowmenu_la_LIBADD = \
+libdirectorymenu_la_LIBADD = \
 	$(top_builddir)/libxfce4panel/libxfce4panel-$(LIBXFCE4PANEL_VERSION_API).la \
 	$(top_builddir)/common/libpanel-common.la \
 	$(EXO_LIBS) \
 	$(GTK_LIBS) \
 	$(LIBXFCE4UTIL_LIBS) \
 	$(LIBXFCE4UI_LIBS) \
-	$(LIBWNCK_LIBS) \
+	$(GIO_LIBS) \
+	$(GIO_UNIX_LIBS) \
 	$(XFCONF_LIBS)
 
-libwindowmenu_la_DEPENDENCIES = \
+libdirectorymenu_la_DEPENDENCIES = \
 	$(top_builddir)/libxfce4panel/libxfce4panel-$(LIBXFCE4PANEL_VERSION_API).la \
 	$(top_builddir)/common/libpanel-common.la
 
 #
-# xfce4-popup-windowmenu script
+# xfce4-popup-directorymenu script
 #
 bin_SCRIPTS = \
-	xfce4-popup-windowmenu
+	xfce4-popup-directorymenu
 
-xfce4-popup-windowmenu: xfce4-popup-windowmenu.in Makefile
+xfce4-popup-directorymenu: xfce4-popup-directorymenu.in Makefile
 	$(AM_V_GEN) sed -e "s,\@bindir\@,$(bindir),g" $< >$@
 
 #
 # .desktop file
 #
 desktopdir = $(datadir)/xfce4/panel-plugins
-desktop_in_files = windowmenu.desktop.in
+desktop_in_files = directorymenu.desktop.in
 desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
 @INTLTOOL_DESKTOP_RULE@
 
 EXTRA_DIST = \
-	windowmenu-dialog.glade \
+	directorymenu-dialog.glade \
 	$(desktop_in_files)
 
 DISTCLEANFILES = \
@@ -74,13 +75,13 @@ DISTCLEANFILES = \
 
 if MAINTAINER_MODE
 BUILT_SOURCES = \
-	$(libwindowmenu_built_sources)
+	$(libdirectorymenu_built_sources)
 
 DISTCLEANFILES += \
-	$(libwindowmenu_built_sources)
+	$(libdirectorymenu_built_sources)
 
-windowmenu-dialog_ui.h: windowmenu-dialog.glade
-	$(AM_V_GEN) exo-csource --static --strip-comments --strip-content --name=windowmenu_dialog_ui $< >$@
+directorymenu-dialog_ui.h: directorymenu-dialog.glade
+	$(AM_V_GEN) exo-csource --static --strip-comments --strip-content --name=directorymenu_dialog_ui $< >$@
 endif
 
 # vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/plugins/windowmenu/windowmenu-dialog.glade b/plugins/directorymenu/directorymenu-dialog.glade
similarity index 61%
copy from plugins/windowmenu/windowmenu-dialog.glade
copy to plugins/directorymenu/directorymenu-dialog.glade
index 6b196c7..934a215 100644
--- a/plugins/windowmenu/windowmenu-dialog.glade
+++ b/plugins/directorymenu/directorymenu-dialog.glade
@@ -4,7 +4,7 @@
   <!-- interface-requires libxfce4ui 0.0 -->
   <!-- interface-naming-policy toplevel-contextual -->
   <object class="XfceTitledDialog" id="dialog">
-    <property name="title" translatable="yes">Window Menu</property>
+    <property name="title" translatable="yes">Directory Menu</property>
     <property name="icon_name">gtk-properties</property>
     <property name="type_hint">normal</property>
     <property name="has_separator">False</property>
@@ -29,84 +29,70 @@
                     <property name="visible">True</property>
                     <property name="left_padding">12</property>
                     <child>
-                      <object class="GtkVBox" id="vbox3">
+                      <object class="GtkTable" id="table1">
                         <property name="visible">True</property>
                         <property name="border_width">6</property>
-                        <property name="orientation">vertical</property>
-                        <property name="spacing">6</property>
+                        <property name="n_rows">2</property>
+                        <property name="n_columns">2</property>
+                        <property name="column_spacing">12</property>
+                        <property name="row_spacing">6</property>
                         <child>
-                          <object class="GtkHBox" id="hbox1">
+                          <object class="GtkFileChooserButton" id="base-directory">
                             <property name="visible">True</property>
-                            <property name="spacing">12</property>
-                            <child>
-                              <object class="GtkLabel" id="label5">
-                                <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Button layout:</property>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkComboBox" id="style">
-                                <property name="visible">True</property>
-                                <property name="model">style-model</property>
-                                <child>
-                                  <object class="GtkCellRendererText" id="cellrenderertext1"/>
-                                  <attributes>
-                                    <attribute name="text">0</attribute>
-                                  </attributes>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
+                            <property name="action">select-folder</property>
+                            <property name="local_only">False</property>
+                            <property name="title" translatable="yes">Select A Directory</property>
                           </object>
                           <packing>
-                            <property name="position">0</property>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkCheckButton" id="workspace-actions">
-                            <property name="label" translatable="yes">Show workspace a_ctions</property>
+                          <object class="GtkLabel" id="label2">
                             <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">_Base Directory:</property>
                             <property name="use_underline">True</property>
-                            <property name="draw_indicator">True</property>
+                            <property name="mnemonic_widget">base-directory</property>
                           </object>
                           <packing>
-                            <property name="position">1</property>
+                            <property name="x_options">GTK_FILL</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkCheckButton" id="workspace-names">
-                            <property name="label" translatable="yes">Show workspace _names</property>
+                          <object class="GtkLabel" id="label4">
                             <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">_Icon:</property>
                             <property name="use_underline">True</property>
-                            <property name="draw_indicator">True</property>
+                            <property name="mnemonic_widget">icon-button</property>
                           </object>
                           <packing>
-                            <property name="position">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkCheckButton" id="urgentcy-notification">
-                            <property name="label" translatable="yes">Enable _urgency notification</property>
+                          <object class="GtkAlignment" id="alignment2">
                             <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="use_underline">True</property>
-                            <property name="draw_indicator">True</property>
+                            <property name="xalign">0</property>
+                            <property name="xscale">0</property>
+                            <property name="yscale">0</property>
+                            <child>
+                              <object class="GtkButton" id="icon-button">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                              </object>
+                            </child>
                           </object>
                           <packing>
-                            <property name="position">3</property>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
                           </packing>
                         </child>
                       </object>
@@ -138,14 +124,40 @@
                     <property name="visible">True</property>
                     <property name="left_padding">12</property>
                     <child>
-                      <object class="GtkVBox" id="vbox2">
+                      <object class="GtkTable" id="table2">
                         <property name="visible">True</property>
                         <property name="border_width">6</property>
-                        <property name="orientation">vertical</property>
-                        <property name="spacing">6</property>
+                        <property name="n_rows">2</property>
+                        <property name="n_columns">2</property>
+                        <property name="column_spacing">12</property>
+                        <property name="row_spacing">6</property>
+                        <child>
+                          <object class="GtkEntry" id="file-pattern">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="tooltip_text" translatable="yes">Enter a list of patterns that will be used to determine which files are visible in a directory. If you specify more than one pattern here, the list items must be separated with semicolons (e.g. *.txt;*.doc).</property>
+                            <property name="invisible_char">&#x2022;</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                          </packing>
+                        </child>
                         <child>
-                          <object class="GtkCheckButton" id="all-workspaces">
-                            <property name="label" translatable="yes">Show windows from _all workspaces</property>
+                          <object class="GtkLabel" id="label7">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">_File Pattern:</property>
+                            <property name="use_underline">True</property>
+                            <property name="mnemonic_widget">file-pattern</property>
+                          </object>
+                          <packing>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="hidden-files">
+                            <property name="label" translatable="yes">Show _hidden files</property>
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="receives_default">False</property>
@@ -153,7 +165,9 @@
                             <property name="draw_indicator">True</property>
                           </object>
                           <packing>
-                            <property name="position">0</property>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
                           </packing>
                         </child>
                       </object>
@@ -161,7 +175,7 @@
                   </object>
                 </child>
                 <child type="label">
-                  <object class="GtkLabel" id="label3">
+                  <object class="GtkLabel" id="label8">
                     <property name="visible">True</property>
                     <property name="label" translatable="yes">Filtering</property>
                     <attributes>
@@ -177,7 +191,6 @@
             </child>
           </object>
           <packing>
-            <property name="expand">False</property>
             <property name="position">1</property>
           </packing>
         </child>
@@ -212,18 +225,11 @@
       <action-widget response="0">close-button</action-widget>
     </action-widgets>
   </object>
-  <object class="GtkListStore" id="style-model">
-    <columns>
-      <!-- column-name title -->
-      <column type="gchararray"/>
-    </columns>
-    <data>
-      <row>
-        <col id="0" translatable="yes">Icon</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes">Arrow</col>
-      </row>
-    </data>
+  <object class="GtkSizeGroup" id="sizegroup1">
+    <widgets>
+      <widget name="label7"/>
+      <widget name="label2"/>
+      <widget name="label4"/>
+    </widgets>
   </object>
 </interface>
diff --git a/plugins/directorymenu/directorymenu.c b/plugins/directorymenu/directorymenu.c
new file mode 100644
index 0000000..a22b8a5
--- /dev/null
+++ b/plugins/directorymenu/directorymenu.c
@@ -0,0 +1,881 @@
+/*
+ * Copyright (C) 2010 Nick Schermer <nick at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gio/gio.h>
+#include <exo/exo.h>
+#include <libxfce4ui/libxfce4ui.h>
+#include <libxfce4panel/libxfce4panel.h>
+#include <common/panel-xfconf.h>
+#include <common/panel-builder.h>
+#include <common/panel-private.h>
+
+#ifdef HAVE_GIO_UNIX
+#include <gio/gdesktopappinfo.h>
+#endif
+
+#include "directorymenu.h"
+#include "directorymenu-dialog_ui.h"
+
+#define DEFAULT_ICON_NAME "folder"
+
+
+struct _DirectoryMenuPluginClass
+{
+  XfcePanelPluginClass __parent__;
+};
+
+struct _DirectoryMenuPlugin
+{
+  XfcePanelPlugin __parent__;
+
+  GtkWidget       *button;
+  GtkWidget       *icon;
+
+  GFile           *base_directory;
+  gchar           *icon_name;
+  gchar           *file_pattern;
+  guint            hidden_files : 1;
+
+  GSList          *patterns;
+
+  /* temp item we store here when the
+   * properties dialog is opened */
+  GtkWidget       *dialog_icon;
+};
+
+enum
+{
+  PROP_0,
+  PROP_BASE_DIRECTORY,
+  PROP_ICON_NAME,
+  PROP_FILE_PATTERN,
+  PROP_HIDDEN_FILES
+};
+
+
+
+static void      directory_menu_plugin_get_property         (GObject             *object,
+                                                             guint                prop_id,
+                                                             GValue              *value,
+                                                             GParamSpec          *pspec);
+static void      directory_menu_plugin_set_property         (GObject             *object,
+                                                             guint                prop_id,
+                                                             const GValue        *value,
+                                                             GParamSpec          *pspec);
+static void      directory_menu_plugin_construct            (XfcePanelPlugin     *panel_plugin);
+static void      directory_menu_plugin_free_file_patterns   (DirectoryMenuPlugin *plugin);
+static void      directory_menu_plugin_free_data            (XfcePanelPlugin     *panel_plugin);
+static void      directory_menu_plugin_configure_plugin     (XfcePanelPlugin     *panel_plugin);
+static gboolean  directory_menu_plugin_remote_event         (XfcePanelPlugin     *panel_plugin,
+                                                             const gchar         *name,
+                                                             const GValue        *value);
+static void      directory_menu_plugin_menu                 (GtkWidget           *button,
+                                                             DirectoryMenuPlugin *plugin);
+
+
+
+/* define the plugin */
+XFCE_PANEL_DEFINE_PLUGIN (DirectoryMenuPlugin, directory_menu_plugin)
+
+
+
+static GQuark menu_file = 0;
+
+
+
+static void
+directory_menu_plugin_class_init (DirectoryMenuPluginClass *klass)
+{
+  XfcePanelPluginClass *plugin_class;
+  GObjectClass         *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->get_property = directory_menu_plugin_get_property;
+  gobject_class->set_property = directory_menu_plugin_set_property;
+
+  plugin_class = XFCE_PANEL_PLUGIN_CLASS (klass);
+  plugin_class->construct = directory_menu_plugin_construct;
+  plugin_class->free_data = directory_menu_plugin_free_data;
+  plugin_class->configure_plugin = directory_menu_plugin_configure_plugin;
+  plugin_class->remote_event = directory_menu_plugin_remote_event;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_BASE_DIRECTORY,
+                                   g_param_spec_string ("base-directory",
+                                                        NULL, NULL,
+                                                        NULL,
+                                                        EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_ICON_NAME,
+                                   g_param_spec_string ("icon-name",
+                                                        NULL, NULL,
+                                                        NULL,
+                                                        EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_FILE_PATTERN,
+                                   g_param_spec_string ("file-pattern",
+                                                        NULL, NULL,
+                                                        "",
+                                                        EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_HIDDEN_FILES,
+                                   g_param_spec_boolean ("hidden-files",
+                                                         NULL, NULL,
+                                                         FALSE,
+                                                         EXO_PARAM_READWRITE));
+
+  menu_file = g_quark_from_static_string ("dir-menu-file");
+}
+
+
+
+static void
+directory_menu_plugin_init (DirectoryMenuPlugin *plugin)
+{
+  plugin->button = xfce_panel_create_toggle_button ();
+  xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
+  gtk_container_add (GTK_CONTAINER (plugin), plugin->button);
+  gtk_button_set_relief (GTK_BUTTON (plugin->button), GTK_RELIEF_NONE);
+  g_signal_connect (G_OBJECT (plugin->button), "toggled",
+      G_CALLBACK (directory_menu_plugin_menu), plugin);
+
+  plugin->icon = xfce_panel_image_new_from_source (DEFAULT_ICON_NAME);
+  gtk_container_add (GTK_CONTAINER (plugin->button), plugin->icon);
+  gtk_widget_show (plugin->icon);
+}
+
+
+
+static void
+directory_menu_plugin_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  DirectoryMenuPlugin *plugin = XFCE_DIRECTORY_MENU_PLUGIN (object);
+  gchar               *str;
+
+  switch (prop_id)
+    {
+    case PROP_BASE_DIRECTORY:
+      if (g_file_is_native (plugin->base_directory))
+        str = g_file_get_path (plugin->base_directory);
+      else
+        str = g_file_get_uri (plugin->base_directory);
+      g_value_take_string (value, str);
+      break;
+
+    case PROP_ICON_NAME:
+      g_value_set_string (value, plugin->icon_name);
+      break;
+
+    case PROP_FILE_PATTERN:
+      g_value_set_string (value, exo_str_is_empty (plugin->file_pattern) ?
+          "" : plugin->file_pattern);
+      break;
+
+    case PROP_HIDDEN_FILES:
+      g_value_set_boolean (value, plugin->hidden_files);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
+static void
+directory_menu_plugin_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  DirectoryMenuPlugin  *plugin = XFCE_DIRECTORY_MENU_PLUGIN (object);
+  gchar                *display_name;
+  gchar               **array;
+  guint                 i;
+  GFile                *base_directory;
+  const gchar          *path;
+
+  switch (prop_id)
+    {
+    case PROP_BASE_DIRECTORY:
+      path = g_value_get_string (value);
+      if (exo_str_is_empty (path))
+        path = g_get_home_dir ();
+
+      if (plugin->base_directory != NULL)
+        g_object_unref (G_OBJECT (plugin->base_directory));
+      plugin->base_directory = g_file_new_for_commandline_arg (path);
+
+      base_directory = g_file_new_for_commandline_arg (g_value_get_string (value));
+
+      display_name = g_file_get_parse_name (plugin->base_directory);
+      gtk_widget_set_tooltip_text (plugin->button, display_name);
+      g_free (display_name);
+      break;
+
+    case PROP_ICON_NAME:
+      g_free (plugin->icon_name);
+      plugin->icon_name = g_value_dup_string (value);
+      xfce_panel_image_set_from_source (XFCE_PANEL_IMAGE (plugin->icon),
+          exo_str_is_empty (plugin->icon_name) ? DEFAULT_ICON_NAME : plugin->icon_name);
+      break;
+
+    case PROP_FILE_PATTERN:
+      g_free (plugin->file_pattern);
+      plugin->file_pattern = g_value_dup_string (value);
+
+      directory_menu_plugin_free_file_patterns (plugin);
+
+      array = g_strsplit (plugin->file_pattern, ";", -1);
+      if (G_LIKELY (array != NULL))
+        {
+          for (i = 0; array[i] != NULL; i++)
+            if (!exo_str_is_empty (array[i]))
+                plugin->patterns = g_slist_prepend (plugin->patterns,
+                    g_pattern_spec_new (array[i]));
+
+          g_strfreev (array);
+        }
+      break;
+
+    case PROP_HIDDEN_FILES:
+      plugin->hidden_files = g_value_get_boolean (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
+static void
+directory_menu_plugin_construct (XfcePanelPlugin *panel_plugin)
+{
+  DirectoryMenuPlugin *plugin = XFCE_DIRECTORY_MENU_PLUGIN (panel_plugin);
+  const PanelProperty  properties[] =
+  {
+    { "base-directory", G_TYPE_STRING },
+    { "icon-name", G_TYPE_STRING },
+    { "file-pattern", G_TYPE_STRING },
+    { "hidden-files", G_TYPE_BOOLEAN },
+    { NULL }
+  };
+
+  xfce_panel_plugin_menu_show_configure (XFCE_PANEL_PLUGIN (plugin));
+
+  /* bind all properties */
+  panel_properties_bind (NULL, G_OBJECT (plugin),
+                         xfce_panel_plugin_get_property_base (panel_plugin),
+                         properties, FALSE);
+
+  if (plugin->base_directory == NULL)
+    g_object_set (G_OBJECT (plugin), "base-directory", g_get_home_dir (), NULL);
+
+  gtk_widget_show (plugin->button);
+}
+
+
+
+static void
+directory_menu_plugin_free_file_patterns (DirectoryMenuPlugin *plugin)
+{
+  GSList *li;
+
+  panel_return_if_fail (XFCE_IS_DIRECTORY_MENU_PLUGIN (plugin));
+
+  for (li = plugin->patterns; li != NULL; li = li->next)
+    g_pattern_spec_free (li->data);
+
+  g_slist_free (plugin->patterns);
+  plugin->patterns = NULL;
+}
+
+
+
+static void
+directory_menu_plugin_free_data (XfcePanelPlugin *panel_plugin)
+{
+  DirectoryMenuPlugin *plugin = XFCE_DIRECTORY_MENU_PLUGIN (panel_plugin);
+
+  g_object_unref (G_OBJECT (plugin->base_directory));
+  g_free (plugin->icon_name);
+  g_free (plugin->file_pattern);
+
+  directory_menu_plugin_free_file_patterns (plugin);
+}
+
+
+
+static void
+directory_menu_plugin_configure_plugin_file_set (GtkFileChooserButton *button,
+                                                 DirectoryMenuPlugin  *plugin)
+{
+  gchar *uri;
+
+  panel_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button));
+  panel_return_if_fail (XFCE_IS_DIRECTORY_MENU_PLUGIN (plugin));
+
+  uri = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (button));
+  g_object_set (G_OBJECT (plugin), "base-directory", uri, NULL);
+  g_free (uri);
+}
+
+
+
+static void
+directory_menu_plugin_configure_plugin_icon_chooser (GtkWidget           *button,
+                                                     DirectoryMenuPlugin *plugin)
+{
+  GtkWidget *chooser;
+  gchar     *icon;
+
+  panel_return_if_fail (XFCE_IS_DIRECTORY_MENU_PLUGIN (plugin));
+  panel_return_if_fail (XFCE_IS_PANEL_IMAGE (plugin->dialog_icon));
+
+  chooser = exo_icon_chooser_dialog_new (_("Select An Icon"),
+                                         GTK_WINDOW (gtk_widget_get_toplevel (button)),
+                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                         GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                                         NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT);
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (chooser),
+                                           GTK_RESPONSE_ACCEPT,
+                                           GTK_RESPONSE_CANCEL, -1);
+
+  if (!exo_str_is_empty (plugin->icon_name))
+  exo_icon_chooser_dialog_set_icon (EXO_ICON_CHOOSER_DIALOG (chooser), plugin->icon_name);
+
+  if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
+    {
+      icon = exo_icon_chooser_dialog_get_icon (EXO_ICON_CHOOSER_DIALOG (chooser));
+      g_object_set (G_OBJECT (plugin), "icon-name", icon, NULL);
+      xfce_panel_image_set_from_source (XFCE_PANEL_IMAGE (plugin->dialog_icon), icon);
+      g_free (icon);
+    }
+
+  gtk_widget_destroy (chooser);
+}
+
+
+
+static void
+directory_menu_plugin_configure_plugin (XfcePanelPlugin *panel_plugin)
+{
+  DirectoryMenuPlugin *plugin = XFCE_DIRECTORY_MENU_PLUGIN (panel_plugin);
+  GtkBuilder          *builder;
+  GObject             *dialog, *object;
+  const gchar         *icon_name = plugin->icon_name;
+
+  if (exo_str_is_empty (icon_name))
+    icon_name = DEFAULT_ICON_NAME;
+
+  /* setup the dialog */
+  PANEL_BUILDER_LINK_4UI
+  builder = panel_builder_new (panel_plugin, directorymenu_dialog_ui,
+                               directorymenu_dialog_ui_length, &dialog);
+  if (G_UNLIKELY (builder == NULL))
+    return;
+
+  object = gtk_builder_get_object (builder, "base-directory");
+  panel_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (object));
+  if (!gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (object),
+                                                 plugin->base_directory, NULL))
+    gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (object), g_get_home_dir ());
+  g_signal_connect (G_OBJECT (object), "current-folder-changed",
+     G_CALLBACK (directory_menu_plugin_configure_plugin_file_set), plugin);
+
+  object = gtk_builder_get_object (builder, "icon-button");
+  panel_return_if_fail (GTK_IS_BUTTON (object));
+  g_signal_connect (G_OBJECT (object), "clicked",
+     G_CALLBACK (directory_menu_plugin_configure_plugin_icon_chooser), plugin);
+
+  plugin->dialog_icon = xfce_panel_image_new_from_source (icon_name);
+  g_object_set (G_OBJECT (plugin->dialog_icon), "size", 48, NULL);
+  gtk_container_add (GTK_CONTAINER (object), plugin->dialog_icon);
+  g_object_add_weak_pointer (G_OBJECT (plugin->dialog_icon), (gpointer) &plugin->dialog_icon);
+  gtk_widget_show (plugin->dialog_icon);
+
+  object = gtk_builder_get_object (builder, "file-pattern");
+  panel_return_if_fail (GTK_IS_ENTRY (object));
+  exo_mutual_binding_new (G_OBJECT (plugin), "file-pattern",
+                          G_OBJECT (object), "text");
+
+  object = gtk_builder_get_object (builder, "hidden-files");
+  panel_return_if_fail (GTK_IS_CHECK_BUTTON (object));
+  exo_mutual_binding_new (G_OBJECT (plugin), "hidden-files",
+                          G_OBJECT (object), "active");
+
+  gtk_widget_show (GTK_WIDGET (dialog));
+}
+
+
+
+static gboolean
+directory_menu_plugin_remote_event (XfcePanelPlugin *panel_plugin,
+                                    const gchar     *name,
+                                    const GValue    *value)
+{
+  DirectoryMenuPlugin *plugin = XFCE_DIRECTORY_MENU_PLUGIN (panel_plugin);
+
+  panel_return_val_if_fail (value == NULL || G_IS_VALUE (value), FALSE);
+
+  if (strcmp (name, "popup") == 0
+      && GTK_WIDGET_VISIBLE (panel_plugin)
+      && !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (plugin->button)))
+    {
+      /* show the menu */
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->button), TRUE);
+
+      /* don't popup another menu */
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+
+static void
+directory_menu_plugin_selection_done (GtkWidget *menu,
+                                      GtkWidget *button)
+{
+  panel_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
+  panel_return_if_fail (GTK_IS_MENU (menu));
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
+
+  /* delay destruction so we can handle the activate event first */
+  exo_gtk_object_destroy_later (GTK_OBJECT (menu));
+}
+
+
+
+static gint
+directory_menu_plugin_menu_sort (gconstpointer a,
+                                 gconstpointer b)
+{
+  GFileType type_a = g_file_info_get_file_type (G_FILE_INFO (a));
+  GFileType type_b = g_file_info_get_file_type (G_FILE_INFO (b));
+  gboolean  hidden_a, hidden_b;
+
+  if (type_a != type_b)
+    {
+      /* sort directories before files */
+      if (type_a == G_FILE_TYPE_DIRECTORY)
+        return -1;
+      else if (type_b == G_FILE_TYPE_DIRECTORY)
+        return 1;
+    }
+
+  hidden_a = g_file_info_get_is_hidden (G_FILE_INFO (a));
+  hidden_b = g_file_info_get_is_hidden (G_FILE_INFO (b));
+
+  /* sort hidden files above 'normal' files */
+  if (hidden_a != hidden_b)
+    return hidden_a ? -1 : 1;
+
+  return g_utf8_collate (g_file_info_get_display_name (G_FILE_INFO (a)),
+                         g_file_info_get_display_name (G_FILE_INFO (b)));
+}
+
+
+
+#ifdef HAVE_GIO_UNIX
+static void
+directory_menu_plugin_menu_launch_desktop_file (GtkWidget *mi,
+                                                GAppInfo  *info)
+{
+  GdkAppLaunchContext *context;
+  GIcon               *icon;
+  GError              *error = NULL;
+
+  panel_return_if_fail (G_IS_APP_INFO (info));
+  panel_return_if_fail (GTK_IS_WIDGET (mi));
+
+  context = gdk_app_launch_context_new ();
+  gdk_app_launch_context_set_screen (context, gtk_widget_get_screen (mi));
+  gdk_app_launch_context_set_timestamp (context, gtk_get_current_event_time ());
+  icon = g_app_info_get_icon (info);
+  if (G_LIKELY (icon != NULL))
+    gdk_app_launch_context_set_icon (context, icon);
+
+  if (!g_app_info_launch (info, NULL, G_APP_LAUNCH_CONTEXT (context), &error))
+    {
+      xfce_dialog_show_error (NULL, error, _("Failed to launch application \"%s\""),
+                              g_app_info_get_executable (info));
+      g_error_free (error);
+    }
+
+  g_object_unref (G_OBJECT (context));
+}
+#endif
+
+
+
+static void
+directory_menu_plugin_menu_launch (GtkWidget *mi,
+                                   GFile     *file)
+{
+  GAppInfo            *appinfo;
+  GError              *error = NULL;
+  gchar               *display_name;
+  GList                fake_list = { NULL, };
+  GdkAppLaunchContext *context;
+  GFileInfo           *info;
+  const gchar         *message;
+  gboolean             result;
+
+  panel_return_if_fail (G_IS_FILE (file));
+  panel_return_if_fail (GTK_IS_WIDGET (mi));
+
+  info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                            G_FILE_QUERY_INFO_NONE, NULL, &error);
+  if (G_UNLIKELY (info == NULL))
+    {
+      message = _("Failed to query content type for \"%s\"");
+      goto err;
+    }
+
+  appinfo = g_app_info_get_default_for_type (g_file_info_get_content_type (info),
+                                             !g_file_is_native (file));
+  g_object_unref (G_OBJECT (info));
+  if (G_LIKELY (appinfo == NULL))
+    {
+      message = _("No default application found for \"%s\"");
+      goto err;
+    }
+
+  fake_list.data = file;
+
+  context = gdk_app_launch_context_new ();
+  gdk_app_launch_context_set_screen (context, gtk_widget_get_screen (mi));
+  gdk_app_launch_context_set_timestamp (context, gtk_get_current_event_time ());
+
+  result = g_app_info_launch (appinfo, &fake_list, G_APP_LAUNCH_CONTEXT (context), &error);
+  g_object_unref (G_OBJECT (context));
+  g_object_unref (G_OBJECT (appinfo));
+  if (G_UNLIKELY (!result))
+    {
+      message = _("Failed to launch default application for \"%s\"");
+      goto err;
+    }
+
+  return;
+
+err:
+  display_name = g_file_get_parse_name (file);
+  xfce_dialog_show_error (NULL, error, message, display_name);
+  g_free (display_name);
+  g_error_free (error);
+}
+
+
+
+static void
+directory_menu_plugin_menu_open (GtkWidget   *mi,
+                                 GFile       *dir,
+                                 const gchar *category)
+{
+  GError *error = NULL;
+  gchar  *path;
+
+  path = g_file_get_path (dir);
+  if (!exo_execute_preferred_application_on_screen (category, NULL, path, NULL,
+                                                    gtk_widget_get_screen (mi),
+                                                    &error))
+    {
+      xfce_dialog_show_error (NULL, error,
+          _("Failed to open preferred application category \"%s\""), category);
+      g_error_free (error);
+    }
+  g_free (path);
+}
+
+
+
+static void
+directory_menu_plugin_menu_open_terminal (GtkWidget *mi,
+                                          GFile     *dir)
+{
+  panel_return_if_fail (GTK_IS_WIDGET (mi));
+  panel_return_if_fail (G_IS_FILE (dir));
+
+  directory_menu_plugin_menu_open (mi, dir, "TerminalEmulator");
+}
+
+
+
+static void
+directory_menu_plugin_menu_open_folder (GtkWidget *mi,
+                                        GFile     *dir)
+{
+  panel_return_if_fail (GTK_IS_WIDGET (mi));
+  panel_return_if_fail (G_IS_FILE (dir));
+
+  directory_menu_plugin_menu_open (mi, dir, "FileManager");
+}
+
+
+
+static void
+directory_menu_plugin_menu_unload (GtkWidget *menu)
+{
+  /* delay destruction so we can handle the activate event first */
+  gtk_container_foreach (GTK_CONTAINER (menu),
+     (GtkCallback) exo_gtk_object_destroy_later, NULL);
+}
+
+
+
+static void
+directory_menu_plugin_menu_load (GtkWidget           *menu,
+                                 DirectoryMenuPlugin *plugin)
+{
+  GFileEnumerator *iter;
+  GFileInfo       *info;
+  GtkWidget       *mi;
+  const gchar     *display_name;
+  GSList          *li, *infos = NULL;
+  GIcon           *icon;
+  GtkWidget       *image;
+  GtkWidget       *submenu;
+  GFile           *file;
+  GFile           *dir;
+  gboolean         visible;
+  GFileType        file_type;
+#ifdef HAVE_GIO_UNIX
+  GDesktopAppInfo *desktopinfo;
+  gchar           *path;
+  const gchar     *description;
+#endif
+
+  panel_return_if_fail (XFCE_IS_DIRECTORY_MENU_PLUGIN (plugin));
+  panel_return_if_fail (GTK_IS_MENU (menu));
+
+  dir = g_object_get_qdata (G_OBJECT (menu), menu_file);
+  panel_return_if_fail (G_IS_FILE (dir));
+  if (G_UNLIKELY (dir == NULL))
+    return;
+
+  mi = gtk_image_menu_item_new_with_label (_("Open Folder"));
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+  g_signal_connect_data (G_OBJECT (mi), "activate",
+      G_CALLBACK (directory_menu_plugin_menu_open_folder),
+      g_object_ref (dir), (GClosureNotify) g_object_unref, 0);
+  gtk_widget_show (mi);
+
+  image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), image);
+  gtk_widget_show (image);
+
+  mi = gtk_image_menu_item_new_with_label (_("Open in Terminal"));
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+  g_signal_connect_data (G_OBJECT (mi), "activate",
+      G_CALLBACK (directory_menu_plugin_menu_open_terminal),
+      g_object_ref (dir), (GClosureNotify) g_object_unref, 0);
+  gtk_widget_show (mi);
+
+  image = gtk_image_new_from_icon_name ("terminal", GTK_ICON_SIZE_MENU);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), image);
+  gtk_widget_show (image);
+
+  iter = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME
+                                    "," G_FILE_ATTRIBUTE_STANDARD_NAME
+                                    "," G_FILE_ATTRIBUTE_STANDARD_TYPE
+                                    "," G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN
+                                    "," G_FILE_ATTRIBUTE_STANDARD_ICON,
+                                    G_FILE_QUERY_INFO_NONE, NULL, NULL);
+  if (G_LIKELY (iter != NULL))
+    {
+      for (;;)
+        {
+          info = g_file_enumerator_next_file (iter, NULL, NULL);
+          if (G_UNLIKELY (info == NULL))
+            break;
+
+          /* skip hidden files if disabled by the user */
+          if (!plugin->hidden_files
+              && g_file_info_get_is_hidden (info))
+            {
+              g_object_unref (G_OBJECT (info));
+              continue;
+            }
+
+          /* if the file is not a directory, check the file patterns */
+          if (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY)
+            {
+              if (plugin->patterns == NULL)
+                {
+                  g_object_unref (G_OBJECT (info));
+                  continue;
+                }
+
+              visible = FALSE;
+              display_name = g_file_info_get_display_name (info);
+              if (G_LIKELY (display_name != NULL))
+                for (li = plugin->patterns; !visible && li != NULL; li = li->next)
+                   if (g_pattern_match_string (li->data, display_name))
+                     visible = TRUE;
+
+              if (!visible)
+                {
+                  g_object_unref (G_OBJECT (info));
+                  continue;
+                }
+            }
+
+          infos = g_slist_insert_sorted (infos, info, directory_menu_plugin_menu_sort);
+        }
+
+      g_object_unref (G_OBJECT (iter));
+
+      if (G_LIKELY (infos != NULL))
+        {
+          mi = gtk_separator_menu_item_new ();
+          gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+          gtk_widget_show (mi);
+        }
+
+      for (li = infos; li != NULL; li = li->next)
+        {
+          info = G_FILE_INFO (li->data);
+          file_type = g_file_info_get_file_type (info);
+
+          display_name = g_file_info_get_display_name (info);
+          if (G_UNLIKELY (display_name == NULL))
+            {
+              g_object_unref (G_OBJECT (info));
+              continue;
+            }
+
+          file = g_file_get_child (dir, g_file_info_get_name (info));
+          icon = NULL;
+
+#ifdef HAVE_GIO_UNIX
+          /* for native desktop files we make an exception and try
+           * to load them like a normal menu */
+          desktopinfo = NULL;
+          if (G_UNLIKELY (file_type != G_FILE_TYPE_DIRECTORY
+              && g_file_is_native (file)
+              && g_str_has_suffix (display_name, ".desktop")))
+            {
+              path = g_file_get_path (file);
+              desktopinfo = g_desktop_app_info_new_from_filename (path);
+              g_free (path);
+
+              if (G_LIKELY (desktopinfo != NULL))
+                {
+                  display_name = g_app_info_get_name (G_APP_INFO (desktopinfo));
+                  icon = g_app_info_get_icon (G_APP_INFO (desktopinfo));
+                }
+            }
+#endif
+
+          mi = gtk_image_menu_item_new_with_label (display_name);
+          gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+          gtk_widget_show (mi);
+
+          if (G_LIKELY (icon == NULL))
+            icon = g_file_info_get_icon (info);
+          if (G_LIKELY (icon != NULL))
+            {
+              image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
+              gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), image);
+              gtk_widget_show (image);
+            }
+
+          /* set a submenu for directories */
+          if (G_LIKELY (file_type == G_FILE_TYPE_DIRECTORY))
+            {
+              submenu = gtk_menu_new ();
+              gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), submenu);
+              g_object_set_qdata_full (G_OBJECT (submenu), menu_file, file, g_object_unref);
+
+              g_signal_connect (G_OBJECT (submenu), "show",
+                  G_CALLBACK (directory_menu_plugin_menu_load), plugin);
+              g_signal_connect_after (G_OBJECT (submenu), "hide",
+                  G_CALLBACK (directory_menu_plugin_menu_unload), NULL);
+            }
+#ifdef HAVE_GIO_UNIX
+          else if (G_UNLIKELY (desktopinfo != NULL))
+            {
+              description = g_app_info_get_description (G_APP_INFO (desktopinfo));
+              if (!exo_str_is_empty (description))
+                gtk_widget_set_tooltip_text (mi, description);
+
+              g_signal_connect_data (G_OBJECT (mi), "activate",
+                  G_CALLBACK (directory_menu_plugin_menu_launch_desktop_file),
+                  desktopinfo, (GClosureNotify) g_object_unref, 0);
+
+              g_object_unref (G_OBJECT (file));
+            }
+#endif
+          else
+            {
+              g_signal_connect_data (G_OBJECT (mi), "activate",
+                  G_CALLBACK (directory_menu_plugin_menu_launch), file,
+                  (GClosureNotify) g_object_unref, 0);
+            }
+
+          g_object_unref (G_OBJECT (info));
+        }
+
+      g_slist_free (infos);
+    }
+}
+
+
+
+static void
+directory_menu_plugin_menu (GtkWidget           *button,
+                            DirectoryMenuPlugin *plugin)
+{
+  GtkWidget *menu;
+
+  panel_return_if_fail (XFCE_IS_DIRECTORY_MENU_PLUGIN (plugin));
+  panel_return_if_fail (plugin->button == button);
+
+  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
+    return;
+
+  menu = gtk_menu_new ();
+  g_signal_connect (G_OBJECT (menu), "deactivate",
+      G_CALLBACK (directory_menu_plugin_selection_done), button);
+
+  g_object_set_qdata_full (G_OBJECT (menu), menu_file,
+                           g_object_ref (plugin->base_directory),
+                           g_object_unref);
+  directory_menu_plugin_menu_load (menu, plugin);
+
+  gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+                  xfce_panel_plugin_position_menu, plugin,
+                  1, gtk_get_current_event_time ());
+}
diff --git a/plugins/directorymenu/directorymenu.desktop.in b/plugins/directorymenu/directorymenu.desktop.in
new file mode 100644
index 0000000..4fa450d
--- /dev/null
+++ b/plugins/directorymenu/directorymenu.desktop.in
@@ -0,0 +1,8 @@
+[Xfce Panel]
+Type=X-XFCE-PanelPlugin
+Encoding=UTF-8
+_Name=Directory Menu
+_Comment=Show a directory tree in a menu
+Icon=folder
+X-XFCE-Module=directorymenu
+X-XFCE-Internal=TRUE
diff --git a/plugins/directorymenu/directorymenu.h b/plugins/directorymenu/directorymenu.h
new file mode 100644
index 0000000..1c8c33d
--- /dev/null
+++ b/plugins/directorymenu/directorymenu.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __XFCE_DIRECTORY_MENU_PLUGIN_H__
+#define __XFCE_DIRECTORY_MENU_PLUGIN_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _DirectoryMenuPluginClass DirectoryMenuPluginClass;
+typedef struct _DirectoryMenuPlugin      DirectoryMenuPlugin;
+
+#define XFCE_TYPE_DIRECTORY_MENU_PLUGIN            (directory_menu_plugin_get_type ())
+#define XFCE_DIRECTORY_MENU_PLUGIN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_DIRECTORY_MENU_PLUGIN, DirectoryMenuPlugin))
+#define XFCE_DIRECTORY_MENU_PLUGIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_DIRECTORY_MENU_PLUGIN, DirectoryMenuPluginClass))
+#define XFCE_IS_DIRECTORY_MENU_PLUGIN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_DIRECTORY_MENU_PLUGIN))
+#define XFCE_IS_DIRECTORY_MENU_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_DIRECTORY_MENU_PLUGIN))
+#define XFCE_DIRECTORY_MENU_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_DIRECTORY_MENU_PLUGIN, DirectoryMenuPluginClass))
+
+GType directory_menu_plugin_get_type      (void) G_GNUC_CONST;
+
+void  directory_menu_plugin_register_type (XfcePanelTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* !__XFCE_DIRECTORY_MENU_PLUGIN_H__ */
diff --git a/plugins/windowmenu/xfce4-popup-windowmenu.in b/plugins/directorymenu/xfce4-popup-directorymenu.in
similarity index 87%
copy from plugins/windowmenu/xfce4-popup-windowmenu.in
copy to plugins/directorymenu/xfce4-popup-directorymenu.in
index a477228..e1ab43c 100644
--- a/plugins/windowmenu/xfce4-popup-windowmenu.in
+++ b/plugins/directorymenu/xfce4-popup-directorymenu.in
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# Copyright (C) 2009 Nick Schermer <nick at xfce.org>
+# Copyright (C) 2010 Nick Schermer <nick at xfce.org>
 #
 # This library is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by the Free
@@ -17,6 +17,6 @@
 # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 #
 
-exec @bindir@/xfce4-panel --plugin-event=windowmenu:popup
+exec @bindir@/xfce4-panel --plugin-event=directorymenu:popup
 
 # vim:set ts=2 sw=2 et ai:
diff --git a/plugins/launcher/Makefile.am b/plugins/launcher/Makefile.am
index 1198ee6..0bf2ea5 100644
--- a/plugins/launcher/Makefile.am
+++ b/plugins/launcher/Makefile.am
@@ -26,6 +26,7 @@ liblauncher_la_CFLAGS = \
 	$(LIBXFCE4UI_CFLAGS) \
 	$(GARCON_CFLAGS) \
 	$(EXO_CFLAGS) \
+	$(GIO_CFLAGS) \
 	$(XFCONF_CFLAGS) \
 	$(DBUS_CFLAGS) \
 	$(PLATFORM_CFLAGS)
@@ -46,6 +47,7 @@ liblauncher_la_LIBADD = \
 	$(GARCON_LIBS) \
 	$(EXO_LIBS) \
 	$(DBUS_LIBS) \
+	$(GIO_LIBS) \
 	$(XFCONF_LIBS)
 
 liblauncher_la_DEPENDENCIES = \
diff --git a/plugins/launcher/launcher.c b/plugins/launcher/launcher.c
index 090f57d..232428d 100644
--- a/plugins/launcher/launcher.c
+++ b/plugins/launcher/launcher.c
@@ -24,6 +24,7 @@
 #include <string.h>
 #endif
 
+#include <gio/gio.h>
 #include <exo/exo.h>
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 54374fd..d26ad00 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -72,6 +72,9 @@ plugins/clock/clock.c
 plugins/clock/clock.desktop.in
 plugins/clock/clock.h
 
+plugins/directorymenu/directorymenu.c
+plugins/directorymenu/directorymenu.desktop.in
+
 plugins/launcher/launcher-dialog.c
 plugins/launcher/launcher-dialog.h
 plugins/launcher/launcher-dialog.glade



More information about the Xfce4-commits mailing list