[sound-juicer] Add SjCellRendererText



commit 94e562c9ea4040bc0a46f77991312387c9dc555e
Author: Phillip Wood <phillip wood dunelm org uk>
Date:   Mon Apr 14 10:03:34 2014 +0100

    Add SjCellRendererText
    
    This is a subclass of GtkCellRendererText which accepts changes
    without confirmation and does not stop editing when the toplevel
    loses focus. This means that the user no longer loses their changes
    if they forget to press 'Enter' when they have finished editing.
    
    This raises the required GLib version to 2.38 for
    G_DEFINE_TYPE_WITH_PRIVATE
    
    https://bugzilla.gnome.org/show_bug.cgi?id=151469

 configure.ac                |    2 +-
 src/Makefile.am             |    2 +
 src/sj-cell-renderer-text.c |  248 +++++++++++++++++++++++++++++++++++++++++++
 src/sj-cell-renderer-text.h |   53 +++++++++
 4 files changed, 304 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 99f9cc8..7362d43 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,7 +40,7 @@ AC_CHECK_FUNC(socket,,[AC_CHECK_LIB(socket,socket)])
 YELP_HELP_INIT
 
 # Find GLib and GObject
-PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32 gthread-2.0 gobject-2.0 gio-2.0)
+PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.38 gthread-2.0 gobject-2.0 gio-2.0)
 AC_SUBST(GLIB_CFLAGS)
 AC_SUBST(GLIB_LIBS)
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 44cc194..e9094c5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,6 +2,8 @@ bin_PROGRAMS = sound-juicer
 
 sound_juicer_SOURCES = \
        sound-juicer.h \
+       sj-cell-renderer-text.h \
+       sj-cell-renderer-text.c \
        sj-main.h \
        sj-main.c \
        sj-prefs.h \
diff --git a/src/sj-cell-renderer-text.c b/src/sj-cell-renderer-text.c
new file mode 100644
index 0000000..9cde025
--- /dev/null
+++ b/src/sj-cell-renderer-text.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2014 Phillip Wood <phillip wood dunelm org uk>
+ *
+ * Sound Juicer - sj-cell-renderer-text.c
+ *
+ * This is based on gtkcellrenderertext.c from GTK
+ * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb redhat com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sj-cell-renderer-text.h"
+
+#define SJ_CELL_RENDERER_TEXT_PATH "sj-cell-renderer-text-path"
+
+typedef struct _SjCellRendererTextPrivate SjCellRendererTextPrivate;
+
+struct _SjCellRendererTextPrivate
+{
+  GtkWidget *entry;
+  gulong focus_out_id;
+  gulong populate_popup_id;
+  guint entry_menu_popdown_timeout;
+  gboolean in_entry_menu;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (SjCellRendererText, sj_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);
+
+static void
+sj_cell_renderer_text_editing_done (GtkCellEditable *entry,
+                                    gpointer         data)
+{
+  SjCellRendererTextPrivate *priv;
+  const gchar *path;
+  const gchar *new_text;
+  gboolean canceled;
+
+  priv = sj_cell_renderer_text_get_instance_private (data);
+
+  g_clear_object (&priv->entry);
+
+  if (priv->focus_out_id > 0) {
+    g_signal_handler_disconnect (entry, priv->focus_out_id);
+    priv->focus_out_id = 0;
+  }
+
+  if (priv->populate_popup_id > 0) {
+    g_signal_handler_disconnect (entry, priv->populate_popup_id);
+    priv->populate_popup_id = 0;
+  }
+
+  if (priv->entry_menu_popdown_timeout) {
+    g_source_remove (priv->entry_menu_popdown_timeout);
+    priv->entry_menu_popdown_timeout = 0;
+  }
+
+  g_object_get (entry,
+                "editing-canceled", &canceled,
+                NULL);
+  gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data), canceled);
+
+  if (canceled)
+    return;
+
+  path = g_object_get_data (G_OBJECT (entry), SJ_CELL_RENDERER_TEXT_PATH);
+  new_text = gtk_entry_get_text (GTK_ENTRY (entry));
+
+  g_signal_emit_by_name (data, "edited", 0, path, new_text);
+}
+
+static gboolean
+popdown_timeout (gpointer data)
+{
+  SjCellRendererTextPrivate *priv;
+
+  priv = sj_cell_renderer_text_get_instance_private (data);
+
+  priv->entry_menu_popdown_timeout = 0;
+
+  if (!gtk_widget_is_focus (GTK_WIDGET (priv->entry)))
+    sj_cell_renderer_text_editing_done (GTK_CELL_EDITABLE (priv->entry), data);
+
+  return FALSE;
+}
+
+static void
+sj_cell_renderer_text_popup_unmap (GtkMenu  *menu,
+                                   gpointer  data)
+{
+  SjCellRendererTextPrivate *priv;
+
+  priv = sj_cell_renderer_text_get_instance_private (data);
+
+  priv->in_entry_menu = FALSE;
+
+  if (priv->entry_menu_popdown_timeout)
+    return;
+
+  priv->entry_menu_popdown_timeout = g_timeout_add (500, popdown_timeout,
+                                                    data);
+  g_source_set_name_by_id (priv->entry_menu_popdown_timeout,
+                           "[sjcellrendertext] popdown_timeout");
+}
+
+static void
+sj_cell_renderer_text_populate_popup (GtkEntry *entry,
+                                      GtkMenu  *menu,
+                                      gpointer  data)
+{
+  SjCellRendererTextPrivate *priv;
+
+  priv = sj_cell_renderer_text_get_instance_private (data);
+
+  if (priv->entry_menu_popdown_timeout) {
+    g_source_remove (priv->entry_menu_popdown_timeout);
+    priv->entry_menu_popdown_timeout = 0;
+  }
+
+  priv->in_entry_menu = TRUE;
+
+  g_signal_connect (menu, "unmap",
+                    G_CALLBACK (sj_cell_renderer_text_popup_unmap), data);
+}
+
+static gboolean
+sj_cell_renderer_text_focus_out_event (GtkWidget *entry,
+                                       GdkEvent  *event,
+                                       gpointer   data)
+{
+  SjCellRendererTextPrivate *priv;
+
+  priv = sj_cell_renderer_text_get_instance_private (data);
+
+  if (priv->in_entry_menu || gtk_widget_is_focus (entry))
+    return FALSE;
+
+  gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
+  gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
+
+  /* entry needs focus-out-event */
+  return FALSE;
+}
+
+static GtkCellEditable *
+sj_cell_renderer_text_start_editing (GtkCellRenderer      *cell,
+                                     GdkEvent             *event,
+                                     GtkWidget            *widget,
+                                     const gchar          *path,
+                                     const GdkRectangle   *background_area,
+                                     const GdkRectangle   *cell_area,
+                                     GtkCellRendererState  flags)
+{
+  SjCellRendererText *celltext;
+  SjCellRendererTextPrivate *priv;
+  gfloat xalign, yalign;
+  GtkCellRendererMode mode;
+  gchar *text = NULL;
+
+  celltext = SJ_CELL_RENDERER_TEXT (cell);
+  priv = sj_cell_renderer_text_get_instance_private (celltext);
+
+  /* If the cell isn't editable we return NULL. */
+  g_object_get (cell, "mode", &mode, NULL);
+  if (mode != GTK_CELL_RENDERER_MODE_EDITABLE)
+    return NULL;
+
+  gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
+
+  priv->entry = gtk_entry_new ();
+  g_object_ref_sink (G_OBJECT (priv->entry));
+
+  gtk_entry_set_has_frame (GTK_ENTRY (priv->entry), FALSE);
+  gtk_entry_set_alignment (GTK_ENTRY (priv->entry), xalign);
+
+  g_object_get (cell, "text", &text, NULL);
+  gtk_entry_set_text (GTK_ENTRY (priv->entry), text);
+  g_free (text);
+
+  g_object_set_data_full (G_OBJECT (priv->entry), SJ_CELL_RENDERER_TEXT_PATH,
+                          g_strdup (path), g_free);
+
+  gtk_editable_select_region (GTK_EDITABLE (priv->entry), 0, -1);
+
+  priv->in_entry_menu = FALSE;
+  if (priv->entry_menu_popdown_timeout) {
+    g_source_remove (priv->entry_menu_popdown_timeout);
+    priv->entry_menu_popdown_timeout = 0;
+  }
+
+  g_signal_connect (priv->entry,
+                    "editing-done",
+                    G_CALLBACK (sj_cell_renderer_text_editing_done),
+                    celltext);
+  priv->focus_out_id = g_signal_connect_after (priv->entry, "focus-out-event",
+                                               G_CALLBACK (sj_cell_renderer_text_focus_out_event),
+                                               celltext);
+  priv->populate_popup_id = g_signal_connect (priv->entry, "populate-popup",
+                                              G_CALLBACK (sj_cell_renderer_text_populate_popup),
+                                              celltext);
+
+  gtk_widget_show (priv->entry);
+
+  return GTK_CELL_EDITABLE (priv->entry);
+}
+
+static void
+sj_cell_renderer_text_init (SjCellRendererText *sj_cell_renderer_text)
+{
+  /* No Op */
+}
+
+static void
+sj_cell_renderer_text_finalize (GObject *object)
+{
+  SjCellRendererTextPrivate *priv;
+
+  priv = sj_cell_renderer_text_get_instance_private (SJ_CELL_RENDERER_TEXT (object));
+  g_clear_object (&priv->entry);
+  G_OBJECT_CLASS (sj_cell_renderer_text_parent_class)->finalize (object);
+}
+
+static void
+sj_cell_renderer_text_class_init (SjCellRendererTextClass *class)
+{
+  GObjectClass* object_class = G_OBJECT_CLASS (class);
+  GtkCellRendererClass *renderer_class = GTK_CELL_RENDERER_CLASS (class);
+
+  object_class->finalize = sj_cell_renderer_text_finalize;
+  renderer_class->start_editing = sj_cell_renderer_text_start_editing;
+}
+
+
+GtkCellRenderer*
+sj_cell_renderer_text_new (void)
+{
+  return g_object_new (SJ_TYPE_CELL_RENDERER_TEXT, NULL);
+}
diff --git a/src/sj-cell-renderer-text.h b/src/sj-cell-renderer-text.h
new file mode 100644
index 0000000..7bc7dca
--- /dev/null
+++ b/src/sj-cell-renderer-text.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 Phillip Wood <phillip wood dunelm org uk>
+ *
+ * Sound Juicer - sj-cell-renderer-text.h
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SJ_CELL_RENDERER_TEXT_H_
+#define _SJ_CELL_RENDERER_TEXT_H_
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define SJ_TYPE_CELL_RENDERER_TEXT             (sj_cell_renderer_text_get_type ())
+#define SJ_CELL_RENDERER_TEXT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
SJ_TYPE_CELL_RENDERER_TEXT, SjCellRendererText))
+#define SJ_CELL_RENDERER_TEXT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), 
SJ_TYPE_CELL_RENDERER_TEXT, SjCellRendererTextClass))
+#define SJ_IS_CELL_RENDERER_TEXT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
SJ_TYPE_CELL_RENDERER_TEXT))
+#define SJ_IS_CELL_RENDERER_TEXT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
SJ_TYPE_CELL_RENDERER_TEXT))
+#define SJ_CELL_RENDERER_TEXT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), 
SJ_TYPE_CELL_RENDERER_TEXT, SjCellRendererTextClass))
+
+typedef struct _SjCellRendererTextClass SjCellRendererTextClass;
+typedef struct _SjCellRendererText SjCellRendererText;
+
+struct _SjCellRendererTextClass
+{
+  GtkCellRendererTextClass parent_class;
+};
+
+struct _SjCellRendererText
+{
+  GtkCellRendererText parent_instance;
+};
+
+GType sj_cell_renderer_text_get_type (void) G_GNUC_CONST;
+GtkCellRenderer *sj_cell_renderer_text_new (void);
+
+G_END_DECLS
+
+#endif /* _SJ_CELL_RENDERER_TEXT_H_ */


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