[Xfce4-commits] <thunar-vcs-plugin:thunarx-2> * thunar-vcs-plugin/tvp-git-action.c tvp-git-helper/main.c tvp-git-helper/tgh-common.[ch] tvp-git-helper/tgh-stash{, -dialog}.[ch]: Added stash action.

Peter de Ridder noreply at xfce.org
Sun Nov 29 19:04:28 CET 2009


Updating branch refs/heads/thunarx-2
         to 8f4ba0b888e20c4045f1d252c531c093e8a7b690 (commit)
       from 3aa180a79c07d4855f6c779ac951d047dc164b10 (commit)

commit 8f4ba0b888e20c4045f1d252c531c093e8a7b690
Author: Peter de Ridder <peter at xfce.org>
Date:   Sun Oct 25 00:45:40 2009 +0200

    * thunar-vcs-plugin/tvp-git-action.c tvp-git-helper/main.c
      tvp-git-helper/tgh-common.[ch]
      tvp-git-helper/tgh-stash{,-dialog}.[ch]: Added stash action.

 thunar-vcs-plugin/tvp-git-action.c        |    2 +
 tvp-git-helper/Makefile.am                |    4 +
 tvp-git-helper/main.c                     |   17 +
 tvp-git-helper/tgh-common.c               |   78 ++++
 tvp-git-helper/tgh-common.h               |   13 +-
 tvp-git-helper/tgh-stash-dialog.c         |  618 +++++++++++++++++++++++++++++
 tvp-git-helper/tgh-stash-dialog.h         |   55 +++
 tvp-git-helper/tgh-stash.c                |  377 ++++++++++++++++++
 tvp-git-helper/{tgh-log.h => tgh-stash.h} |    8 +-
 9 files changed, 1163 insertions(+), 9 deletions(-)

diff --git a/thunar-vcs-plugin/tvp-git-action.c b/thunar-vcs-plugin/tvp-git-action.c
index 792e545..c0d6022 100644
--- a/thunar-vcs-plugin/tvp-git-action.c
+++ b/thunar-vcs-plugin/tvp-git-action.c
@@ -265,6 +265,8 @@ tvp_git_action_create_menu_item (GtkAction *action)
     add_subaction_u(GTK_MENU_SHELL(menu), "tvp::remove", Q_("Menu|Remove"), _("Remove"), GTK_STOCK_DELETE, _("Remove"));
     add_subaction_u(GTK_MENU_SHELL(menu), "tvp::show", Q_("Menu|Show"), _("Show"), NULL, _("Show"));
   if(tvp_action->property.is_parent)
+    add_subaction (action, GTK_MENU_SHELL(menu), "tvp::stash", Q_("Menu|Stash"), _("Stash"), GTK_STOCK_SAVE, "--stash");
+  if(tvp_action->property.is_parent)
     add_subaction (action, GTK_MENU_SHELL(menu), "tvp::status", Q_("Menu|Status"), _("Status"), GTK_STOCK_DIALOG_INFO, "--status");
     add_subaction_u(GTK_MENU_SHELL(menu), "tvp::tag", Q_("Menu|Tag"), _("Tag"), NULL, _("Tag"));
 
diff --git a/tvp-git-helper/Makefile.am b/tvp-git-helper/Makefile.am
index b3b56a9..ada3794 100644
--- a/tvp-git-helper/Makefile.am
+++ b/tvp-git-helper/Makefile.am
@@ -26,6 +26,8 @@ tvp_git_helper_SOURCES =						\
 	tgh-log.c							\
 	tgh-reset.h							\
 	tgh-reset.c							\
+	tgh-stash.h							\
+	tgh-stash.c							\
 	tgh-status.h							\
 	tgh-status.c							\
 	tgh-dialog-common.h						\
@@ -38,6 +40,8 @@ tvp_git_helper_SOURCES =						\
 	tgh-log-dialog.c						\
 	tgh-notify-dialog.h						\
 	tgh-notify-dialog.c						\
+	tgh-stash-dialog.h						\
+	tgh-stash-dialog.c						\
 	tgh-status-dialog.h						\
 	tgh-status-dialog.c						\
 	tgh-transfer-dialog.h						\
diff --git a/tvp-git-helper/main.c b/tvp-git-helper/main.c
index 6824ded..3313699 100644
--- a/tvp-git-helper/main.c
+++ b/tvp-git-helper/main.c
@@ -35,6 +35,7 @@
 #include "tgh-clone.h"
 #include "tgh-log.h"
 #include "tgh-reset.h"
+#include "tgh-stash.h"
 #include "tgh-status.h"
 
 static GPid pid;
@@ -58,6 +59,7 @@ int main (int argc, char *argv[])
   gboolean clone = FALSE;
   gboolean log = FALSE;
   gboolean reset = FALSE;
+  gboolean stash = FALSE;
   gboolean status = FALSE;
   gchar **files = NULL;
   GError *error = NULL;
@@ -102,6 +104,12 @@ int main (int argc, char *argv[])
     { NULL, '\0', 0, 0, NULL, NULL, NULL }
   };
 
+  GOptionEntry stash_options_table[] =
+  {
+    { "stash", '\0', 0, G_OPTION_ARG_NONE, &stash, N_("Execute stash action"), NULL },
+    { NULL, '\0', 0, 0, NULL, NULL, NULL }
+  };
+
   GOptionEntry status_options_table[] =
   {
     { "status", '\0', 0, G_OPTION_ARG_NONE, &status, N_("Execute status action"), NULL },
@@ -136,6 +144,10 @@ int main (int argc, char *argv[])
   g_option_group_add_entries(option_group, reset_options_table);
   g_option_context_add_group(option_context, option_group);
 
+  option_group = g_option_group_new("stash", N_("Stash Related Options:"), N_("Stash"), NULL, NULL);
+  g_option_group_add_entries(option_group, stash_options_table);
+  g_option_context_add_group(option_context, option_group);
+
   option_group = g_option_group_new("status", N_("Status Related Options:"), N_("Status"), NULL, NULL);
   g_option_group_add_entries(option_group, status_options_table);
   g_option_context_add_group(option_context, option_group);
@@ -177,6 +189,11 @@ int main (int argc, char *argv[])
     has_child = tgh_reset(files, &pid);
   }
 
+  if(stash)
+  {
+    has_child = tgh_stash(files, &pid);
+  }
+
   if(status)
   {
     has_child = tgh_status(files, &pid);
diff --git a/tvp-git-helper/tgh-common.c b/tvp-git-helper/tgh-common.c
index f4fc10d..a7b7d1d 100644
--- a/tvp-git-helper/tgh-common.c
+++ b/tvp-git-helper/tgh-common.c
@@ -40,6 +40,7 @@
 #include "tgh-status-dialog.h"
 #include "tgh-log-dialog.h"
 #include "tgh-branch-dialog.h"
+#include "tgh-stash-dialog.h"
 
 #include "tgh-common.h"
 
@@ -352,6 +353,83 @@ tgh_branch_parser_new (GtkWidget *dialog)
   return TGH_OUTPUT_PARSER(parser);
 }
 
+typedef struct {
+  TghOutputParser parent;
+  GtkWidget *dialog;
+} TghStashListParser;
+
+static void
+stash_list_parser_func (TghStashListParser *parser, gchar *line)
+{
+  TghStashDialog *dialog = TGH_STASH_DIALOG (parser->dialog);
+  if (line)
+  {
+    gchar *stash, *branch, *desc;
+    branch = strchr (line, ':');
+    *branch++ = '\0';
+    stash = g_strstrip (line);
+    desc = strchr (branch, ':');
+    *desc++ = '\0';
+    branch = g_strstrip (branch);
+    desc = g_strstrip (desc);
+    tgh_stash_dialog_add (dialog, stash, branch, desc);
+  }
+  else
+  {
+    tgh_stash_dialog_done (dialog);
+    g_free (parser);
+  }
+}
+
+TghOutputParser*
+tgh_stash_list_parser_new (GtkWidget *dialog)
+{
+  TghStashListParser *parser = g_new (TghStashListParser,1);
+
+  TGH_OUTPUT_PARSER (parser)->parse = TGH_OUTPUT_PARSER_FUNC (stash_list_parser_func);
+
+  parser->dialog = dialog;
+
+  return TGH_OUTPUT_PARSER (parser);
+}
+
+typedef struct {
+  TghOutputParser parent;
+  GtkWidget *dialog;
+} TghStashShowParser;
+
+static void
+stash_show_parser_func (TghStashShowParser *parser, gchar *line)
+{
+  TghStashDialog *dialog = TGH_STASH_DIALOG (parser->dialog);
+  if (line)
+  {
+    gchar *ptr, *file;
+    guint insertions = strtoul (line, &ptr, 10);
+    guint deletions = strtoul (ptr, &file, 10);
+    file++;
+    file = g_strndup (file, strlen(file)-1);
+    tgh_stash_dialog_add_file (dialog, insertions, deletions, file);
+  }
+  else
+  {
+    tgh_stash_dialog_done (dialog);
+    g_free (parser);
+  }
+}
+
+TghOutputParser*
+tgh_stash_show_parser_new (GtkWidget *dialog)
+{
+  TghStashShowParser *parser = g_new (TghStashShowParser,1);
+
+  TGH_OUTPUT_PARSER (parser)->parse = TGH_OUTPUT_PARSER_FUNC (stash_show_parser_func);
+
+  parser->dialog = dialog;
+
+  return TGH_OUTPUT_PARSER (parser);
+}
+
 gboolean
 tgh_parse_output_func(GIOChannel *source, GIOCondition condition, gpointer data)
 {
diff --git a/tvp-git-helper/tgh-common.h b/tvp-git-helper/tgh-common.h
index 72d7522..ecdd6b2 100644
--- a/tvp-git-helper/tgh-common.h
+++ b/tvp-git-helper/tgh-common.h
@@ -34,15 +34,18 @@ struct _TghOutputParser {
   TghOutputParserFunc parse;
 };
 
-TghOutputParser* tgh_error_parser_new  (GtkWidget *);
+TghOutputParser* tgh_error_parser_new      (GtkWidget *);
 
-TghOutputParser* tgh_notify_parser_new (GtkWidget *);
+TghOutputParser* tgh_notify_parser_new     (GtkWidget *);
 
-TghOutputParser* tgh_status_parser_new (GtkWidget *);
+TghOutputParser* tgh_status_parser_new     (GtkWidget *);
 
-TghOutputParser* tgh_log_parser_new    (GtkWidget *);
+TghOutputParser* tgh_log_parser_new        (GtkWidget *);
 
-TghOutputParser* tgh_branch_parser_new (GtkWidget *);
+TghOutputParser* tgh_branch_parser_new     (GtkWidget *);
+
+TghOutputParser* tgh_stash_list_parser_new (GtkWidget *);
+TghOutputParser* tgh_stash_show_parser_new (GtkWidget *);
 
 gboolean tgh_parse_output_func  (GIOChannel *, GIOCondition, gpointer);
 
diff --git a/tvp-git-helper/tgh-stash-dialog.c b/tvp-git-helper/tgh-stash-dialog.c
new file mode 100644
index 0000000..d51a804
--- /dev/null
+++ b/tvp-git-helper/tgh-stash-dialog.c
@@ -0,0 +1,618 @@
+/*-
+ * Copyright (c) 2006 Peter de Ridder <peter at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library 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 <thunar-vfs/thunar-vfs.h>
+#include <gtk/gtk.h>
+
+#include "tgh-common.h"
+#include "tgh-stash-dialog.h"
+
+static void selection_changed (GtkTreeView*, gpointer);
+static void cancel_clicked (GtkButton*, gpointer);
+static void save_clicked (GtkButton*, gpointer);
+static void apply_clicked (GtkButton*, gpointer);
+static void pop_clicked (GtkButton*, gpointer);
+static void drop_clicked (GtkButton*, gpointer);
+static void clear_clicked (GtkButton*, gpointer);
+static void tgh_make_homogeneous (GtkWidget *, ...) G_GNUC_NULL_TERMINATED;
+
+struct _TghStashDialog
+{
+  GtkDialog dialog;
+
+  GtkWidget *tree_view;
+  GtkWidget *file_view;
+  GtkWidget *save;
+  GtkWidget *apply;
+  GtkWidget *pop;
+  GtkWidget *drop;
+  GtkWidget *close;
+  GtkWidget *clear;
+  GtkWidget *cancel;
+};
+
+struct _TghStashDialogClass
+{
+	GtkDialogClass dialog_class;
+};
+
+G_DEFINE_TYPE (TghStashDialog, tgh_stash_dialog, GTK_TYPE_DIALOG)
+
+enum {
+  SIGNAL_CANCEL = 0,
+  SIGNAL_SAVE,
+  SIGNAL_APPLY,
+  SIGNAL_POP,
+  SIGNAL_DROP,
+  SIGNAL_CLEAR,
+  SIGNAL_SHOW,
+  SIGNAL_COUNT
+};
+
+static guint signals[SIGNAL_COUNT];
+
+static void
+tgh_stash_dialog_class_init (TghStashDialogClass *klass)
+{
+  signals[SIGNAL_CANCEL] = g_signal_new("cancel-clicked",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+      0, NULL, NULL,
+      g_cclosure_marshal_VOID__VOID,
+      G_TYPE_NONE, 0);
+
+  signals[SIGNAL_SAVE] = g_signal_new("save-clicked",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+      0, NULL, NULL,
+      g_cclosure_marshal_VOID__STRING,
+      G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  signals[SIGNAL_APPLY] = g_signal_new("apply-clicked",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+      0, NULL, NULL,
+      g_cclosure_marshal_VOID__STRING,
+      G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  signals[SIGNAL_POP] = g_signal_new("pop-clicked",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+      0, NULL, NULL,
+      g_cclosure_marshal_VOID__STRING,
+      G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  signals[SIGNAL_DROP] = g_signal_new("drop-clicked",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+      0, NULL, NULL,
+      g_cclosure_marshal_VOID__STRING,
+      G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  signals[SIGNAL_CLEAR] = g_signal_new("clear-clicked",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+      0, NULL, NULL,
+      g_cclosure_marshal_VOID__VOID,
+      G_TYPE_NONE, 0);
+
+  signals[SIGNAL_SHOW] = g_signal_new("selection-changed",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+      0, NULL, NULL,
+      g_cclosure_marshal_VOID__STRING,
+      G_TYPE_NONE, 1, G_TYPE_STRING);
+}
+
+enum {
+  COLUMN_NAME = 0,
+  COLUMN_BRANCH,
+  COLUMN_DESCRIPTION,
+  COLUMN_COUNT
+};
+
+enum {
+  FILE_COLUMN_FILE = 0,
+  FILE_COLUMN_PERCENTAGE,
+  FILE_COLUMN_CHANGES,
+  FILE_COLUMN_COUNT
+};
+
+static void
+tgh_stash_dialog_init (TghStashDialog *dialog)
+{
+  GtkWidget *button;
+  GtkWidget *tree_view;
+  GtkWidget *file_view;
+  GtkWidget *scroll_window;
+  GtkWidget *vpane;
+  GtkWidget *box;
+  GtkCellRenderer *renderer;
+  GtkTreeModel *model;
+
+  vpane = gtk_vpaned_new ();
+
+  scroll_window = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+  dialog->tree_view = tree_view = gtk_tree_view_new ();
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
+      -1, _("Name"), renderer,
+      "text", COLUMN_NAME,
+      NULL);
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
+      -1, _("Branch"), renderer,
+      "text", COLUMN_BRANCH,
+      NULL);
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
+      -1, _("Description"), renderer,
+      "text", COLUMN_DESCRIPTION,
+      NULL);
+
+  model = GTK_TREE_MODEL (gtk_list_store_new (COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING));
+
+  gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
+
+  g_object_unref (model);
+
+  g_signal_connect (G_OBJECT (tree_view), "cursor-changed", G_CALLBACK (selection_changed), dialog); 
+
+  gtk_container_add (GTK_CONTAINER (scroll_window), tree_view);
+  gtk_paned_pack1 (GTK_PANED(vpane), scroll_window, TRUE, FALSE);
+  gtk_widget_show (tree_view);
+  gtk_widget_show (scroll_window);
+
+  scroll_window = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
+  dialog->file_view = file_view = gtk_tree_view_new ();
+
+  renderer = gtk_cell_renderer_progress_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (file_view),
+      -1, _("Changes"), renderer,
+      "value", FILE_COLUMN_PERCENTAGE,
+      "text", FILE_COLUMN_CHANGES,
+      NULL);
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (file_view),
+      -1, _("File"),
+      renderer, "text",
+      FILE_COLUMN_FILE, NULL);
+
+  model = GTK_TREE_MODEL (gtk_list_store_new (FILE_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING));
+
+  gtk_tree_view_set_model (GTK_TREE_VIEW (file_view), model);
+
+  g_object_unref (model);
+
+  gtk_container_add (GTK_CONTAINER (scroll_window), file_view);
+  gtk_paned_pack2 (GTK_PANED(vpane), scroll_window, TRUE, FALSE);
+  gtk_widget_show (file_view);
+  gtk_widget_show (scroll_window);
+
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vpane, TRUE, TRUE, 0);
+  gtk_widget_show (vpane);
+
+  //gtk_button_box_set_layout(GTK_BUTTON_BOX (GTK_DIALOG (dialog)->action_area), GTK_BUTTONBOX_EDGE);
+  gtk_container_remove (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), GTK_DIALOG (dialog)->action_area);
+
+  GTK_DIALOG (dialog)->action_area = box = gtk_hbox_new (FALSE, 0);
+
+  gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox), box,
+      FALSE, TRUE, 0);
+  gtk_widget_show (box);
+
+  gtk_box_reorder_child (GTK_BOX (GTK_DIALOG (dialog)->vbox), box, 0);
+
+  //box = gtk_hbox_new (FALSE, 12);
+
+  dialog->save = button = gtk_button_new_from_stock(GTK_STOCK_SAVE);
+  gtk_box_pack_start (GTK_BOX (box), button, FALSE, TRUE, 0);
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (save_clicked), dialog);
+  gtk_widget_show (button);
+
+  dialog->apply = button = gtk_button_new_from_stock(GTK_STOCK_APPLY);
+  gtk_box_pack_start (GTK_BOX (box), button, FALSE, TRUE, 0);
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (apply_clicked), dialog);
+  gtk_widget_show (button);
+
+  dialog->pop = button = gtk_button_new_from_stock(GTK_STOCK_OK);
+  gtk_box_pack_start (GTK_BOX (box), button, FALSE, TRUE, 0);
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (pop_clicked), dialog);
+  gtk_widget_show (button);
+
+  dialog->drop = button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
+  gtk_box_pack_start (GTK_BOX (box), button, FALSE, TRUE, 0);
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (drop_clicked), dialog);
+  gtk_widget_show (button);
+
+  dialog->clear = button = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
+  gtk_box_pack_start (GTK_BOX (box), button, FALSE, TRUE, 0);
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (clear_clicked), dialog);
+  gtk_widget_show (button);
+
+  //gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), box, FALSE, TRUE, 0);
+  //gtk_widget_show (box);
+
+  gtk_window_set_title (GTK_WINDOW (dialog), _("Stash"));
+
+  dialog->close = button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+  gtk_widget_hide (button);
+
+  dialog->cancel = button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+  gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, FALSE, TRUE, 0);
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (cancel_clicked), dialog);
+  gtk_widget_show (button);
+
+  tgh_make_homogeneous (dialog->save, dialog->apply, dialog->pop, dialog->drop, dialog->close, dialog->cancel, NULL);
+
+  gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 400);
+}
+
+GtkWidget*
+tgh_stash_dialog_new (const gchar *title, GtkWindow *parent, GtkDialogFlags flags)
+{
+  TghStashDialog *dialog = g_object_new (TGH_TYPE_STASH_DIALOG, NULL);
+
+  if(title)
+    gtk_window_set_title (GTK_WINDOW(dialog), title);
+
+  if(parent)
+    gtk_window_set_transient_for (GTK_WINDOW(dialog), parent);
+
+  if(flags & GTK_DIALOG_MODAL)
+    gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
+
+  if(flags & GTK_DIALOG_DESTROY_WITH_PARENT)
+    gtk_window_set_destroy_with_parent (GTK_WINDOW(dialog), TRUE);
+
+  if(flags & GTK_DIALOG_NO_SEPARATOR)
+    gtk_dialog_set_has_separator (GTK_DIALOG(dialog), FALSE);
+
+  return GTK_WIDGET(dialog);
+}
+
+static void
+tgh_make_homogeneous (GtkWidget *first, ...)
+{
+  GtkWidget *iter;
+  GtkRequisition request;
+  gint max_width = 0;
+  gint max_height = 0;
+  va_list ap;
+
+  va_start (ap, first);
+  iter = first;
+  while (iter)
+  {
+    gtk_widget_size_request(iter, &request);
+    if (request.width > max_width)
+      max_width = request.width;
+    if (request.height > max_height)
+      max_height = request.height;
+    iter = va_arg (ap, GtkWidget *);
+  }
+  va_end (ap);
+
+  va_start (ap, first);
+  iter = first;
+  while (iter)
+  {
+    gtk_widget_set_size_request (iter, max_width, max_height);
+    iter = va_arg (ap, GtkWidget *);
+  }
+  va_end (ap);
+}
+
+void       
+tgh_stash_dialog_add (TghStashDialog *dialog, const gchar *name, const gchar *branch, const gchar *description)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+
+  g_return_if_fail (TGH_IS_STASH_DIALOG (dialog));
+
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tree_view));
+
+  gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+      COLUMN_NAME, name,
+      COLUMN_BRANCH, branch,
+      COLUMN_DESCRIPTION, description,
+      -1);
+}
+
+void       
+tgh_stash_dialog_add_file (TghStashDialog *dialog, guint insertions, guint deletions, const gchar *file)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gchar *changes;
+  guint sum;
+
+  g_return_if_fail (TGH_IS_STASH_DIALOG (dialog));
+
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->file_view));
+
+  changes = g_strdup_printf ("+%u -%u", insertions, deletions);
+  sum = insertions + deletions;
+  gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+      FILE_COLUMN_FILE, file,
+      FILE_COLUMN_PERCENTAGE, sum?insertions * 100 / sum:0,
+      FILE_COLUMN_CHANGES, changes,
+      -1);
+  g_free (changes);
+}
+
+void
+tgh_stash_dialog_done (TghStashDialog *dialog)
+{
+  g_return_if_fail (TGH_IS_STASH_DIALOG (dialog));
+
+  gtk_widget_hide (dialog->cancel);
+  gtk_widget_show (dialog->close);
+}
+
+static void
+selection_changed (GtkTreeView *tree_view, gpointer user_data)
+{
+  GtkTreeIter iter;
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  gchar *name;
+
+  TghStashDialog *dialog = TGH_STASH_DIALOG (user_data);
+
+  selection = gtk_tree_view_get_selection (tree_view);
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+  {
+    gtk_tree_model_get (model, &iter, COLUMN_NAME, &name, -1);
+
+    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->file_view));
+    gtk_list_store_clear (GTK_LIST_STORE (model));
+
+    gtk_widget_hide (dialog->cancel);
+    gtk_widget_show (dialog->close);
+
+    g_signal_emit (dialog, signals[SIGNAL_SHOW], 0, name);
+
+    g_free (name);
+  }
+}
+
+static void
+cancel_clicked (GtkButton *button, gpointer user_data)
+{
+  TghStashDialog *dialog = TGH_STASH_DIALOG (user_data);
+
+  gtk_widget_hide (dialog->cancel);
+  gtk_widget_show (dialog->close);
+
+  g_signal_emit (dialog, signals[SIGNAL_CANCEL], 0);
+}
+
+static void
+save_clicked (GtkButton *button, gpointer user_data)
+{
+  GtkTreeModel *model;
+  TghStashDialog *dialog = TGH_STASH_DIALOG (user_data);
+  GtkWidget *name_dialog;
+  GtkWidget *label, *image, *hbox, *vbox, *desc_entry;
+  gchar *name;
+  gint result;
+
+  name_dialog = gtk_dialog_new_with_buttons (NULL, GTK_WINDOW (dialog), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1);
+  gtk_window_set_resizable (GTK_WINDOW (name_dialog), FALSE);
+  gtk_window_set_skip_taskbar_hint (GTK_WINDOW (name_dialog), TRUE);
+
+  label = gtk_label_new (_("Stash description:"));
+  image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
+  gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+  
+  gtk_misc_set_alignment   (GTK_MISC  (label), 0.0, 0.0);
+
+  desc_entry = gtk_entry_new ();
+  
+  hbox = gtk_hbox_new (FALSE, 12);
+  vbox = gtk_vbox_new (FALSE, 12);
+
+  gtk_box_pack_start (GTK_BOX (vbox), label,
+                      FALSE, FALSE, 0);
+
+  gtk_box_pack_start (GTK_BOX (vbox), desc_entry,
+                      TRUE, TRUE, 0);
+
+  gtk_box_pack_start (GTK_BOX (hbox), image,
+                      FALSE, FALSE, 0);
+
+  gtk_box_pack_start (GTK_BOX (hbox), vbox,
+                      TRUE, TRUE, 0);
+
+  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (name_dialog))),
+                      hbox,
+                      FALSE, FALSE, 0);
+
+  gtk_container_set_border_width (GTK_CONTAINER (name_dialog), 5);
+  gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+  gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (name_dialog)->vbox), 14); /* 14 + 2 * 5 = 24 */
+  gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (name_dialog))), 5);
+  gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (name_dialog))), 6);
+
+  gtk_widget_show_all (hbox);
+
+  result = gtk_dialog_run (GTK_DIALOG (name_dialog));
+  if (result != GTK_RESPONSE_ACCEPT)
+  {
+    gtk_widget_destroy (name_dialog);
+    return;
+  }
+
+  name = g_strdup (gtk_entry_get_text (GTK_ENTRY (desc_entry)));
+
+  gtk_widget_destroy (name_dialog);
+
+  gtk_widget_hide (dialog->close);
+  gtk_widget_show (dialog->cancel);
+
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tree_view));
+  gtk_list_store_clear (GTK_LIST_STORE (model));
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->file_view));
+  gtk_list_store_clear (GTK_LIST_STORE (model));
+
+  g_signal_emit (dialog, signals[SIGNAL_SAVE], 0, name);
+
+  g_free (name);
+}
+
+static void
+apply_clicked (GtkButton *button, gpointer user_data)
+{
+  GtkTreeIter iter;
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  gchar *name;
+
+  TghStashDialog *dialog = TGH_STASH_DIALOG (user_data);
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tree_view));
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+  {
+    gtk_tree_model_get (model, &iter, COLUMN_NAME, &name, -1);
+
+    gtk_widget_hide (dialog->close);
+    gtk_widget_show (dialog->cancel);
+
+    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tree_view));
+    gtk_list_store_clear (GTK_LIST_STORE (model));
+    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->file_view));
+    gtk_list_store_clear (GTK_LIST_STORE (model));
+
+    g_signal_emit (dialog, signals[SIGNAL_APPLY], 0, name);
+
+    g_free (name);
+  }
+}
+
+static void
+pop_clicked (GtkButton *button, gpointer user_data)
+{
+  GtkTreeIter iter;
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  gchar *name;
+
+  TghStashDialog *dialog = TGH_STASH_DIALOG (user_data);
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tree_view));
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+  {
+    gtk_tree_model_get (model, &iter, COLUMN_NAME, &name, -1);
+
+    gtk_widget_hide (dialog->close);
+    gtk_widget_show (dialog->cancel);
+
+    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tree_view));
+    gtk_list_store_clear (GTK_LIST_STORE (model));
+    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->file_view));
+    gtk_list_store_clear (GTK_LIST_STORE (model));
+
+    g_signal_emit (dialog, signals[SIGNAL_POP], 0, name);
+
+    g_free (name);
+  }
+}
+
+static void
+drop_clicked (GtkButton *button, gpointer user_data)
+{
+  GtkTreeIter iter;
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  gchar *name;
+  TghStashDialog *dialog = TGH_STASH_DIALOG (user_data);
+  GtkWidget *sure_dialog;
+  gint result;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tree_view));
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+  {
+    gtk_tree_model_get (model, &iter, COLUMN_NAME, &name, -1);
+
+    sure_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Are you sure you want to drop %s?"), name);
+    result = gtk_dialog_run (GTK_DIALOG (sure_dialog));
+    gtk_widget_destroy (sure_dialog);
+    if (result != GTK_RESPONSE_YES)
+      return;
+
+    gtk_widget_hide (dialog->close);
+    gtk_widget_show (dialog->cancel);
+
+    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tree_view));
+    gtk_list_store_clear (GTK_LIST_STORE (model));
+    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->file_view));
+    gtk_list_store_clear (GTK_LIST_STORE (model));
+
+    g_signal_emit (dialog, signals[SIGNAL_DROP], 0, name);
+
+    g_free (name);
+  }
+}
+
+static void
+clear_clicked (GtkButton *button, gpointer user_data)
+{
+  GtkTreeModel *model;
+  TghStashDialog *dialog = TGH_STASH_DIALOG (user_data);
+  GtkWidget *sure_dialog;
+  gint result;
+
+  sure_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Are you sure you want to clear all stash?"));
+  result = gtk_dialog_run (GTK_DIALOG (sure_dialog));
+  gtk_widget_destroy (sure_dialog);
+  if (result != GTK_RESPONSE_YES)
+    return;
+
+  gtk_widget_hide (dialog->close);
+  gtk_widget_show (dialog->cancel);
+
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tree_view));
+  gtk_list_store_clear (GTK_LIST_STORE (model));
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->file_view));
+  gtk_list_store_clear (GTK_LIST_STORE (model));
+
+  g_signal_emit (dialog, signals[SIGNAL_CLEAR], 0);
+}
+
diff --git a/tvp-git-helper/tgh-stash-dialog.h b/tvp-git-helper/tgh-stash-dialog.h
new file mode 100644
index 0000000..567297e
--- /dev/null
+++ b/tvp-git-helper/tgh-stash-dialog.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2006 Peter de Ridder <peter at xfce.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library 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.
+ */
+
+#ifndef __TGH_STASH_DIALOG_H__
+#define __TGH_STASH_DIALOG_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS;
+
+typedef struct _TghStashDialogClass TghStashDialogClass;
+typedef struct _TghStashDialog      TghStashDialog;
+
+#define TGH_TYPE_STASH_DIALOG             (tgh_stash_dialog_get_type ())
+#define TGH_STASH_DIALOG(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), TGH_TYPE_STASH_DIALOG, TghStashDialog))
+#define TGH_STASH_DIALOG_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), TGH_TYPE_STASH_DIALOG, TghStashDialogClass))
+#define TGH_IS_STASH_DIALOG(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TGH_TYPE_STASH_DIALOG))
+#define TGH_IS_STASH_DIALOG_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), TGH_TYPE_STASH_DIALOG))
+#define TGH_STASH_DIALOG_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), TGH_TYPE_STASH_DIALOG, TghStashDialogClass))
+
+GType       tgh_stash_dialog_get_type (void) G_GNUC_CONST G_GNUC_INTERNAL;
+
+GtkWidget*  tgh_stash_dialog_new      (const gchar *title,
+                                       GtkWindow *parent,
+                                       GtkDialogFlags flags) G_GNUC_MALLOC G_GNUC_INTERNAL;
+
+void        tgh_stash_dialog_add      (TghStashDialog *dialog,
+                                       const gchar *name,
+                                       const gchar *branch,
+                                       const gchar *description);
+void        tgh_stash_dialog_add_file (TghStashDialog *dialog,
+                                       guint insertions,
+                                       guint deletions,
+                                       const gchar *file);
+void        tgh_stash_dialog_done     (TghStashDialog *dialog);
+
+G_END_DECLS;
+
+#endif /* !__TGH_STASH_DIALOG_H__ */
diff --git a/tvp-git-helper/tgh-stash.c b/tvp-git-helper/tgh-stash.c
new file mode 100644
index 0000000..ee87cd9
--- /dev/null
+++ b/tvp-git-helper/tgh-stash.c
@@ -0,0 +1,377 @@
+/*-
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <thunar-vfs/thunar-vfs.h>
+
+#include "tgh-common.h"
+#include "tgh-dialog-common.h"
+#include "tgh-stash-dialog.h"
+
+#include "tgh-stash.h"
+
+struct exit_args
+{
+  TghOutputParser *parser;
+  TghStashDialog *dialog;
+};
+
+static gboolean stash_list_spawn (TghStashDialog *dialog, GPid *pid);
+
+static void child_exit (GPid pid, gint status, gpointer user_data)
+{
+  struct exit_args *args = user_data;
+
+  tgh_child_exit (pid, status, args->parser);
+
+  if (stash_list_spawn (args->dialog, &pid))
+    tgh_replace_child (TRUE, pid);
+  else
+    tgh_stash_dialog_done (args->dialog);
+
+  g_free (args);
+}
+
+static gchar *argv_list[] = {"git", "stash", "list", NULL};
+static gchar *argv_clear[] = {"git", "stash", "clear", NULL};
+
+static gboolean stash_list_spawn (TghStashDialog *dialog, GPid *pid)
+{
+  GError *error = NULL;
+  gint fd_out, fd_err;
+  GIOChannel *chan_out, *chan_err;
+  TghOutputParser *parser;
+
+  if(!g_spawn_async_with_pipes(NULL, argv_list, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, pid, NULL, &fd_out, &fd_err, &error))
+  {
+    return FALSE;
+  }
+
+  parser = tgh_error_parser_new(GTK_WIDGET(dialog));
+
+  g_child_watch_add(*pid, (GChildWatchFunc)tgh_child_exit, parser);
+
+  chan_out = g_io_channel_unix_new(fd_out);
+  chan_err = g_io_channel_unix_new(fd_err);
+  g_io_add_watch(chan_out, G_IO_IN|G_IO_HUP, (GIOFunc)tgh_parse_output_func, tgh_stash_list_parser_new(GTK_WIDGET(dialog)));
+  g_io_add_watch(chan_err, G_IO_IN|G_IO_HUP, (GIOFunc)tgh_parse_output_func, parser);
+
+  return TRUE;
+}
+
+static gboolean stash_show_spawn (TghStashDialog *dialog, const gchar *name, GPid *pid)
+{
+  GError *error = NULL;
+  gint fd_out, fd_err;
+  GIOChannel *chan_out, *chan_err;
+  TghOutputParser *parser;
+  gchar **argv;
+
+  argv = g_new (gchar*, 6);
+
+  argv[0] = "git";
+  argv[1] = "stash";
+  argv[2] = "show";
+  argv[3] = "--numstat";
+  argv[4] = (gchar*)name;
+  argv[5] = NULL;
+
+  if (!g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, pid, NULL, &fd_out, &fd_err, &error))
+  {
+    g_free (argv);
+    return FALSE;
+  }
+  g_free (argv);
+
+  parser = tgh_error_parser_new (GTK_WIDGET (dialog));
+
+  g_child_watch_add (*pid, (GChildWatchFunc)tgh_child_exit, parser);
+
+  chan_out = g_io_channel_unix_new (fd_out);
+  chan_err = g_io_channel_unix_new (fd_err);
+  g_io_add_watch (chan_out, G_IO_IN|G_IO_HUP, (GIOFunc)tgh_parse_output_func, tgh_stash_show_parser_new (GTK_WIDGET (dialog)));
+  g_io_add_watch (chan_err, G_IO_IN|G_IO_HUP, (GIOFunc)tgh_parse_output_func, parser);
+
+  return TRUE;
+}
+
+static gboolean stash_save_spawn (TghStashDialog *dialog, const gchar *name, GPid *pid)
+{
+  GError *error = NULL;
+  gint fd_err;
+  GIOChannel *chan_err;
+  TghOutputParser *parser;
+  gchar **argv;
+  struct exit_args *args;
+
+  argv = g_new (gchar*, 6);
+
+  argv[0] = "git";
+  argv[1] = "stash";
+  argv[2] = "save";
+  argv[3] = "-q";
+  argv[4] = (gchar*)name;
+  argv[5] = NULL;
+
+  if (!g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, pid, NULL, NULL, &fd_err, &error))
+  {
+    g_free (argv);
+    return FALSE;
+  }
+  g_free (argv);
+
+  parser = tgh_error_parser_new (GTK_WIDGET (dialog));
+
+  args = g_new (struct exit_args, 1);
+  args->parser = parser;
+  args->dialog = dialog;
+
+  g_child_watch_add(*pid, (GChildWatchFunc)child_exit, args);
+
+  chan_err = g_io_channel_unix_new (fd_err);
+  g_io_add_watch (chan_err, G_IO_IN|G_IO_HUP, (GIOFunc)tgh_parse_output_func, parser);
+
+  return TRUE;
+}
+
+static gboolean stash_apply_spawn (TghStashDialog *dialog, const gchar *name, GPid *pid)
+{
+  GError *error = NULL;
+  gint fd_err;
+  GIOChannel *chan_err;
+  TghOutputParser *parser;
+  gchar **argv;
+  struct exit_args *args;
+
+  argv = g_new (gchar*, 6);
+
+  argv[0] = "git";
+  argv[1] = "stash";
+  argv[2] = "apply";
+  argv[3] = "-q";
+  argv[4] = (gchar*)name;
+  argv[5] = NULL;
+
+  if (!g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, pid, NULL, NULL, &fd_err, &error))
+  {
+    g_free (argv);
+    return FALSE;
+  }
+  g_free (argv);
+
+  parser = tgh_error_parser_new (GTK_WIDGET (dialog));
+
+  args = g_new (struct exit_args, 1);
+  args->parser = parser;
+  args->dialog = dialog;
+
+  g_child_watch_add(*pid, (GChildWatchFunc)child_exit, args);
+
+  chan_err = g_io_channel_unix_new (fd_err);
+  g_io_add_watch (chan_err, G_IO_IN|G_IO_HUP, (GIOFunc)tgh_parse_output_func, parser);
+
+  return TRUE;
+}
+
+static gboolean stash_pop_spawn (TghStashDialog *dialog, const gchar *name, GPid *pid)
+{
+  GError *error = NULL;
+  gint fd_err;
+  GIOChannel *chan_err;
+  TghOutputParser *parser;
+  gchar **argv;
+  struct exit_args *args;
+
+  argv = g_new (gchar*, 6);
+
+  argv[0] = "git";
+  argv[1] = "stash";
+  argv[2] = "pop";
+  argv[3] = "-q";
+  argv[4] = (gchar*)name;
+  argv[5] = NULL;
+
+  if (!g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, pid, NULL, NULL, &fd_err, &error))
+  {
+    g_free (argv);
+    return FALSE;
+  }
+  g_free (argv);
+
+  parser = tgh_error_parser_new (GTK_WIDGET (dialog));
+
+  args = g_new (struct exit_args, 1);
+  args->parser = parser;
+  args->dialog = dialog;
+
+  g_child_watch_add(*pid, (GChildWatchFunc)child_exit, args);
+
+  chan_err = g_io_channel_unix_new (fd_err);
+  g_io_add_watch (chan_err, G_IO_IN|G_IO_HUP, (GIOFunc)tgh_parse_output_func, parser);
+
+  return TRUE;
+}
+
+static gboolean stash_drop_spawn (TghStashDialog *dialog, const gchar *name, GPid *pid)
+{
+  GError *error = NULL;
+  gint fd_err;
+  GIOChannel *chan_err;
+  TghOutputParser *parser;
+  gchar **argv;
+  struct exit_args *args;
+
+  argv = g_new (gchar*, 6);
+
+  argv[0] = "git";
+  argv[1] = "stash";
+  argv[2] = "drop";
+  argv[3] = "-q";
+  argv[4] = (gchar*)name;
+  argv[5] = NULL;
+
+  if (!g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, pid, NULL, NULL, &fd_err, &error))
+  {
+    g_free (argv);
+    return FALSE;
+  }
+  g_free (argv);
+
+  parser = tgh_error_parser_new (GTK_WIDGET (dialog));
+
+  args = g_new (struct exit_args, 1);
+  args->parser = parser;
+  args->dialog = dialog;
+
+  g_child_watch_add(*pid, (GChildWatchFunc)child_exit, args);
+
+  chan_err = g_io_channel_unix_new (fd_err);
+  g_io_add_watch (chan_err, G_IO_IN|G_IO_HUP, (GIOFunc)tgh_parse_output_func, parser);
+
+  return TRUE;
+}
+
+static gboolean stash_clear_spawn (TghStashDialog *dialog, GPid *pid)
+{
+  GError *error = NULL;
+  gint fd_err;
+  GIOChannel *chan_err;
+  TghOutputParser *parser;
+  struct exit_args *args;
+
+  if (!g_spawn_async_with_pipes (NULL, argv_clear, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, pid, NULL, NULL, &fd_err, &error))
+    return FALSE;
+
+  parser = tgh_error_parser_new (GTK_WIDGET (dialog));
+
+  args = g_new (struct exit_args, 1);
+  args->parser = parser;
+  args->dialog = dialog;
+
+  g_child_watch_add(*pid, (GChildWatchFunc)child_exit, args);
+
+  chan_err = g_io_channel_unix_new (fd_err);
+  g_io_add_watch (chan_err, G_IO_IN|G_IO_HUP, (GIOFunc)tgh_parse_output_func, parser);
+
+  return TRUE;
+}
+
+static void show_stash (TghStashDialog *dialog, const gchar *name, gpointer user_data)
+{
+  GPid pid;
+  if (stash_show_spawn(dialog, name, &pid))
+    tgh_replace_child(TRUE, pid);
+  else
+    tgh_stash_dialog_done(dialog);
+}
+
+static void save_stash (TghStashDialog *dialog, const gchar *name, gpointer user_data)
+{
+  GPid pid;
+  if (stash_save_spawn(dialog, name, &pid))
+    tgh_replace_child(TRUE, pid);
+  else
+    tgh_stash_dialog_done(dialog);
+}
+
+static void apply_stash (TghStashDialog *dialog, const gchar *name, gpointer user_data)
+{
+  GPid pid;
+  if (stash_apply_spawn(dialog, name, &pid))
+    tgh_replace_child(TRUE, pid);
+  else
+    tgh_stash_dialog_done(dialog);
+}
+
+static void pop_stash (TghStashDialog *dialog, const gchar *name, gpointer user_data)
+{
+  GPid pid;
+  if (stash_pop_spawn(dialog, name, &pid))
+    tgh_replace_child(TRUE, pid);
+  else
+    tgh_stash_dialog_done(dialog);
+}
+
+static void drop_stash (TghStashDialog *dialog, const gchar *name, gpointer user_data)
+{
+  GPid pid;
+  if (stash_drop_spawn(dialog, name, &pid))
+    tgh_replace_child(TRUE, pid);
+  else
+    tgh_stash_dialog_done(dialog);
+}
+
+static void clear_stash (TghStashDialog *dialog, gpointer user_data)
+{
+  GPid pid;
+  if (stash_clear_spawn(dialog, &pid))
+    tgh_replace_child(TRUE, pid);
+  else
+    tgh_stash_dialog_done(dialog);
+}
+
+gboolean tgh_stash (gchar **files, GPid *pid)
+{
+  GtkWidget *dialog;
+
+  dialog = tgh_stash_dialog_new (NULL, NULL, 0);
+  g_signal_connect(dialog, "cancel-clicked", tgh_cancel, NULL);
+  tgh_dialog_start (GTK_DIALOG (dialog), TRUE);
+
+  if (files)
+    if (chdir(files[0]))
+      return FALSE;
+
+  g_signal_connect(dialog, "selection-changed", G_CALLBACK (show_stash), NULL);
+  g_signal_connect(dialog, "save-clicked", G_CALLBACK (save_stash), NULL);
+  g_signal_connect(dialog, "apply-clicked", G_CALLBACK (apply_stash), NULL);
+  g_signal_connect(dialog, "pop-clicked", G_CALLBACK (pop_stash), NULL);
+  g_signal_connect(dialog, "drop-clicked", G_CALLBACK (drop_stash), NULL);
+  g_signal_connect(dialog, "clear-clicked", G_CALLBACK (clear_stash), NULL);
+
+  return stash_list_spawn(TGH_STASH_DIALOG(dialog), pid);
+}
+
diff --git a/tvp-git-helper/tgh-log.h b/tvp-git-helper/tgh-stash.h
similarity index 87%
copy from tvp-git-helper/tgh-log.h
copy to tvp-git-helper/tgh-stash.h
index 4dc7265..7df453c 100644
--- a/tvp-git-helper/tgh-log.h
+++ b/tvp-git-helper/tgh-stash.h
@@ -14,14 +14,14 @@
  * Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#ifndef __TGH_LOG_H__
-#define __TGH_LOG_H__
+#ifndef __TGH_STASH_H__
+#define __TGH_STASH_H__
 
 G_BEGIN_DECLS
 
-gboolean tgh_log (gchar**, GPid*);
+gboolean tgh_stash (gchar**, GPid*);
 
 G_END_DECLS
 
-#endif /*__TGH_LOG_H__*/
+#endif /*__TGH_STASH_H__*/
 



More information about the Xfce4-commits mailing list