ergtkentry.c

Go to the documentation of this file.
00001 /*
00002  * This file is part of libergtk.
00003  *
00004  * libergtk is free software: you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation, either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * libergtk is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 /**
00019  * \file ergtkentry.c
00020  * \brief ereader gtk library - GtkEntry object adapted for ereader system
00021  *
00022  * forces visibility ON during entry (not during editing)
00023  * 
00024  * Copyright (C) 2009 iRex Technologies B.V.
00025  * All rights reserved.
00026  */
00027 
00028 // system include files
00029 #include <string.h>
00030 #include <ctype.h>
00031 #include <gtk/gtk.h>
00032 
00033 // ereader library includes
00034 
00035 // local includes
00036 #include "ergtk_log.h"
00037 #include "ergtkentry.h"
00038 
00039 // simulate overloading gtk_entry_set_text()
00040 #undef gtk_entry_set_text
00041 
00042 
00043 // instance private data
00044 typedef struct
00045         {
00046             gboolean     visible;           // false = protect text entry by displaying '***'
00047             GString      *invisible_text;   // old entry text stored while entry has focus
00048         } erGtkEntryPrivate;
00049 
00050 // local data
00051 static GtkEntryClass* g_parent_class = NULL;
00052 
00053 // class-specific signals for erGtkEntry
00054 
00055 // overloaded methods for base class
00056 
00057 // overloaded signal handlers for base class
00058 static gboolean ergtk_entry_focus_in    (GtkWidget *widget, GdkEventFocus *event);
00059 static gboolean ergtk_entry_focus_out   (GtkWidget *widget, GdkEventFocus *event);
00060 static void     ergtk_entry_changed     (GtkEditable *widget);
00061 
00062 // implementation of virtual methods
00063 
00064 // local functions
00065 static void     ergtk_entry_class_init      (erGtkEntryClass *klass);
00066 static void     ergtk_entry_editable_init   (GtkEditableClass *iface);
00067 static void     ergtk_entry_init            (erGtkEntry *input_entry);
00068 static void     ergtk_entry_finalize        (GObject *obj);
00069 
00070 
00071 GtkWidget* ergtk_entry_new()
00072 {
00073     LOGPRINTF("entry");
00074     erGtkEntry* item = (erGtkEntry *) g_object_new(ERGTK_ENTRY_TYPE, NULL);
00075 
00076     return GTK_WIDGET(item);
00077 }
00078 
00079 GType ergtk_entry_get_type(void)
00080 {
00081     static GType class_type = 0;
00082 
00083     if (class_type == 0)
00084     {
00085         static const GTypeInfo class_info =
00086         {
00087             sizeof(erGtkEntryClass),
00088             NULL,               /* base_init */
00089             NULL,               /* base_finalize */
00090             (GClassInitFunc) ergtk_entry_class_init,
00091             NULL,               /* class_finalize */
00092             NULL,               /* class_data */
00093             sizeof(erGtkEntry),
00094             0,                  /* n_preallocs */
00095             (GInstanceInitFunc) ergtk_entry_init,
00096             NULL                /* *value_table */            
00097         };
00098         class_type = g_type_register_static(GTK_TYPE_ENTRY, "erGtkEntry", &class_info, 0);
00099 
00100         static const GInterfaceInfo editable_info =
00101         {
00102             (GInterfaceInitFunc)ergtk_entry_editable_init, /* interface_init */
00103             NULL, /* interface_finalize */
00104             NULL  /* interface_data */
00105         };
00106         g_type_add_interface_static(class_type, GTK_TYPE_EDITABLE, &editable_info);
00107     }
00108 
00109     return class_type;
00110 }
00111 
00112 // init class
00113 static void ergtk_entry_class_init(erGtkEntryClass *klass)
00114 {
00115     LOGPRINTF("entry");
00116 
00117     GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
00118     GObjectClass   *object_class = (GObjectClass   *) klass;
00119 
00120     // remember parent class struct, needed for chaining up to parent class
00121     g_parent_class = g_type_class_peek_parent(klass);
00122 
00123     // overload some virtual methods
00124     widget_class->focus_in_event  = ergtk_entry_focus_in;
00125     widget_class->focus_out_event = ergtk_entry_focus_out;
00126     object_class->finalize        = ergtk_entry_finalize;
00127 
00128     // reserve space for instance private data
00129     g_type_class_add_private (klass, sizeof(erGtkEntryPrivate));
00130 }
00131 
00132 // init GtkEditable interface
00133 static void ergtk_entry_editable_init(GtkEditableClass *iface)
00134 {
00135     LOGPRINTF("entry");
00136 
00137     iface->changed = ergtk_entry_changed;
00138 }
00139 
00140 // init instance
00141 static void ergtk_entry_init(erGtkEntry *er_entry)
00142 {
00143     LOGPRINTF("entry");
00144     g_return_if_fail(ERGTK_IS_ENTRY(er_entry));
00145 
00146     GtkEntry  *entry  = (GtkEntry  *) er_entry;
00147     GtkWidget *widget = (GtkWidget *) er_entry;
00148     
00149     erGtkEntryPrivate *priv = ERGTK_ENTRY_GET_PRIVATE(er_entry);
00150 
00151     // E-ink display requires a non-blinking cursur
00152     g_object_set(gtk_widget_get_settings(widget), "gtk-cursor-blink", FALSE, NULL);
00153     
00154     // set default attributes
00155     gtk_entry_set_editable(entry, TRUE);
00156     gtk_entry_set_visibility(entry, TRUE);
00157                   
00158     // instance-private data
00159     priv->visible        = TRUE;
00160     priv->invisible_text = g_string_new("");
00161 }
00162 
00163 // finalize instance
00164 static void ergtk_entry_finalize (GObject *obj)
00165 {
00166     LOGPRINTF("entry: obj [%p]", obj);
00167     g_return_if_fail( ERGTK_IS_ENTRY(obj) );
00168 
00169     erGtkEntryPrivate *priv = ERGTK_ENTRY_GET_PRIVATE(obj);
00170 
00171     // destroy instance data
00172     //   private
00173     g_string_free(priv->invisible_text, TRUE);
00174     //   public: none
00175 
00176     // chain to parent class
00177     ((GObjectClass*)g_parent_class)->finalize( obj );
00178 }
00179 
00180 
00181 // public methods
00182 
00183 
00184 // signal handlers
00185 static gboolean ergtk_entry_focus_in(GtkWidget *widget, GdkEventFocus *event)
00186 {
00187     LOGPRINTF("entry");
00188     g_return_val_if_fail(ERGTK_IS_ENTRY(widget), FALSE);
00189 
00190     gboolean    rc = FALSE;
00191     GtkEntry    *entry    = (GtkEntry   *) widget;
00192     erGtkEntry  *er_entry = (erGtkEntry *) widget;
00193 
00194     erGtkEntryPrivate *priv = ERGTK_ENTRY_GET_PRIVATE(er_entry);
00195 
00196     // chain to parent class
00197     if (g_parent_class->parent_class.focus_in_event)
00198     {
00199         rc = g_parent_class->parent_class.focus_in_event(widget, event);
00200     }
00201 
00202     // original code: if protected, show content when empty
00203     // work-around  : if protected, hide content and show empty entry field
00204     priv->visible = gtk_entry_get_visibility(entry);
00205     if (priv->visible == FALSE)
00206     {
00207         const gchar *text = gtk_entry_get_text(entry);
00208 #if 0
00209         // Original code, to be restored when GtkEntry problem fixed
00210         // Seems to be fixed in GTK 2.15.0
00211         if (text[0] == '\0')
00212         {
00213             gtk_entry_set_visibility(entry, TRUE);
00214         }
00215 #else
00216         // Work-around for problem in GtkEntry that hides
00217         // input method (keyboard) when focus is set on GtkEntry with visibility=FALSE
00218         g_string_assign( priv->invisible_text, text );
00219         gtk_entry_set_text( entry, "" );
00220         gtk_entry_set_visibility(entry, TRUE);
00221 #endif
00222     }
00223     
00224     return rc;
00225 }
00226 
00227 static gboolean ergtk_entry_focus_out(GtkWidget *widget, GdkEventFocus *event)
00228 {
00229     LOGPRINTF("entry");
00230     g_return_val_if_fail(ERGTK_IS_ENTRY(widget), FALSE);
00231 
00232     gboolean    rc = FALSE;
00233     GtkEntry    *entry    = GTK_ENTRY(widget);
00234     erGtkEntry  *er_entry = ERGTK_ENTRY(widget);
00235 
00236     erGtkEntryPrivate *priv = ERGTK_ENTRY_GET_PRIVATE(er_entry);
00237 
00238     // chain to parent class
00239     if (g_parent_class->parent_class.focus_out_event)
00240     {
00241         rc = g_parent_class->parent_class.focus_out_event(widget, event);
00242     }
00243 
00244     // de-select characters
00245     gtk_editable_select_region(GTK_EDITABLE(entry), -1, -1);
00246 
00247     // original code: if protected, hide content
00248     // work-around  : if protected, restore original con16tent when no new content, then hide content
00249     if (priv->visible == FALSE)
00250     {
00251 #if 0
00252         // Original code, to be restored when GtkEntry problem fixed
00253         // Seems to be fixed in GTK 2.15.0
00254 #else
00255         // Work-around for problem in GtkEntry that hides
00256         // input method (keyboard) when focus is set on GtkEntry with visibility=FALSE
00257         const gchar *text = gtk_entry_get_text(entry);
00258         if ( text[0] == '\0' )
00259         {
00260             gtk_entry_set_text( entry, priv->invisible_text->str );
00261         }
00262 #endif
00263         gtk_entry_set_visibility(entry, FALSE);
00264     }
00265     
00266     return rc;
00267 }
00268 
00269 static void ergtk_entry_changed(GtkEditable *editable)
00270 {
00271     LOGPRINTF("entry");
00272     g_return_if_fail(ERGTK_IS_ENTRY(editable));
00273 
00274     erGtkEntry *er_entry = (erGtkEntry *) editable;
00275     GtkEntry   *entry    = (GtkEntry   *) editable;
00276     GtkWidget  *widget   = (GtkWidget  *) editable;
00277 
00278     erGtkEntryPrivate *priv = ERGTK_ENTRY_GET_PRIVATE(er_entry);
00279 
00280     // for protected object, show content when empty
00281     if (   priv->visible == FALSE
00282         && gtk_widget_is_focus(widget) )
00283     {
00284         const gchar *text = gtk_entry_get_text(entry);
00285         if (text[0] == '\0')
00286         {
00287             gtk_entry_set_visibility(entry, TRUE);
00288         }
00289     }
00290 }
00291 
Generated by  doxygen 1.6.2-20100208