Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <marco@localhost.localdomain>2006-10-12 13:49:11 (GMT)
committer Marco Pesenti Gritti <marco@localhost.localdomain>2006-10-12 13:49:11 (GMT)
commit3cfa9c40bd2d79e740cd511c2f23054a76917bfb (patch)
tree894e6eaf6a686b4f7dccee8c80e480df00926636 /lib
parent62a46ff92b234d07437f9f36efea576996eb84e2 (diff)
First go at progress in the entry.
Diffstat (limited to 'lib')
-rw-r--r--lib/python/Makefile.am1
-rw-r--r--lib/python/_sugar.c72
-rw-r--r--lib/python/_sugar.defs7
-rw-r--r--lib/python/_sugar.override2
-rw-r--r--lib/src/Makefile.am3
-rw-r--r--lib/src/gecko-browser.cpp85
-rw-r--r--lib/src/gecko-browser.h5
-rw-r--r--lib/src/sugar-address-entry.c548
-rw-r--r--lib/src/sugar-address-entry.h51
9 files changed, 766 insertions, 8 deletions
diff --git a/lib/python/Makefile.am b/lib/python/Makefile.am
index eb6b85c..c687e9b 100644
--- a/lib/python/Makefile.am
+++ b/lib/python/Makefile.am
@@ -26,6 +26,7 @@ EXTRA_DIST = _sugar.override _sugar.defs
.defs.c:
(cd $(srcdir)\
&& $(PYGTK_CODEGEN) \
+ --register $(PYGTK_DEFSDIR)/gtk-types.defs \
--register $(GNOMEPYTHONEXTRAS_DEFSDIR)/gtkmozembed.defs \
--override $*.override \
--prefix py$* $*.defs) > gen-$*.c \
diff --git a/lib/python/_sugar.c b/lib/python/_sugar.c
index 1938322..585cd0d 100644
--- a/lib/python/_sugar.c
+++ b/lib/python/_sugar.c
@@ -10,22 +10,26 @@
#include "pygobject.h"
#include "gecko-browser.h"
#include "sugar-key-grabber.h"
+#include "sugar-address-entry.h"
-#line 15 "_sugar.c"
+#line 16 "_sugar.c"
/* ---------- types from other modules ---------- */
static PyTypeObject *_PyGObject_Type;
#define PyGObject_Type (*_PyGObject_Type)
+static PyTypeObject *_PyGtkEntry_Type;
+#define PyGtkEntry_Type (*_PyGtkEntry_Type)
static PyTypeObject *_PyGtkMozEmbed_Type;
#define PyGtkMozEmbed_Type (*_PyGtkMozEmbed_Type)
/* ---------- forward type declarations ---------- */
PyTypeObject G_GNUC_INTERNAL PyGeckoBrowser_Type;
+PyTypeObject G_GNUC_INTERNAL PySugarAddressEntry_Type;
PyTypeObject G_GNUC_INTERNAL PySugarKeyGrabber_Type;
-#line 29 "_sugar.c"
+#line 33 "_sugar.c"
@@ -216,6 +220,55 @@ __GeckoBrowser_class_init(gpointer gclass, PyTypeObject *pyclass)
}
+/* ----------- SugarAddressEntry ----------- */
+
+PyTypeObject G_GNUC_INTERNAL PySugarAddressEntry_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gecko.AddressEntry", /* tp_name */
+ sizeof(PyGObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)0, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+ (cmpfunc)0, /* tp_compare */
+ (reprfunc)0, /* tp_repr */
+ (PyNumberMethods*)0, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ NULL, /* Documentation string */
+ (traverseproc)0, /* tp_traverse */
+ (inquiry)0, /* tp_clear */
+ (richcmpfunc)0, /* tp_richcompare */
+ offsetof(PyGObject, weakreflist), /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)NULL, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ (struct PyGetSetDef*)0, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ offsetof(PyGObject, inst_dict), /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)0, /* tp_alloc */
+ (newfunc)0, /* tp_new */
+ (freefunc)0, /* tp_free */
+ (inquiry)0 /* tp_is_gc */
+};
+
+
+
/* ----------- SugarKeyGrabber ----------- */
static int
@@ -354,12 +407,25 @@ py_sugar_register_classes(PyObject *d)
"could not import gtkmozembed");
return ;
}
+ if ((module = PyImport_ImportModule("gtk")) != NULL) {
+ _PyGtkEntry_Type = (PyTypeObject *)PyObject_GetAttrString(module, "Entry");
+ if (_PyGtkEntry_Type == NULL) {
+ PyErr_SetString(PyExc_ImportError,
+ "cannot import name Entry from gtk");
+ return ;
+ }
+ } else {
+ PyErr_SetString(PyExc_ImportError,
+ "could not import gtk");
+ return ;
+ }
-#line 360 "_sugar.c"
+#line 425 "_sugar.c"
pygobject_register_class(d, "GeckoBrowser", GECKO_TYPE_BROWSER, &PyGeckoBrowser_Type, Py_BuildValue("(O)", &PyGtkMozEmbed_Type));
pyg_set_object_has_new_constructor(GECKO_TYPE_BROWSER);
pyg_register_class_init(GECKO_TYPE_BROWSER, __GeckoBrowser_class_init);
+ pygobject_register_class(d, "SugarAddressEntry", SUGAR_TYPE_ADDRESS_ENTRY, &PySugarAddressEntry_Type, Py_BuildValue("(O)", &PyGtkEntry_Type));
pygobject_register_class(d, "SugarKeyGrabber", SUGAR_TYPE_KEY_GRABBER, &PySugarKeyGrabber_Type, Py_BuildValue("(O)", &PyGObject_Type));
pyg_set_object_has_new_constructor(SUGAR_TYPE_KEY_GRABBER);
}
diff --git a/lib/python/_sugar.defs b/lib/python/_sugar.defs
index 011bf71..bdf51a8 100644
--- a/lib/python/_sugar.defs
+++ b/lib/python/_sugar.defs
@@ -7,6 +7,13 @@
(gtype-id "GECKO_TYPE_BROWSER")
)
+(define-object AddressEntry
+ (in-module "Sugar")
+ (parent "GtkEntry")
+ (c-name "SugarAddressEntry")
+ (gtype-id "SUGAR_TYPE_ADDRESS_ENTRY")
+)
+
;; Enumerations and flags ...
diff --git a/lib/python/_sugar.override b/lib/python/_sugar.override
index e439186..4f9b9d7 100644
--- a/lib/python/_sugar.override
+++ b/lib/python/_sugar.override
@@ -6,11 +6,13 @@ headers
#include "pygobject.h"
#include "gecko-browser.h"
#include "sugar-key-grabber.h"
+#include "sugar-address-entry.h"
%%
modulename gecko
%%
import gobject.GObject as PyGObject_Type
+import gtk.Entry as PyGtkEntry_Type
import gtkmozembed.MozEmbed as PyGtkMozEmbed_Type
%%
ignore-glob
diff --git a/lib/src/Makefile.am b/lib/src/Makefile.am
index 57c6a32..8693ead 100644
--- a/lib/src/Makefile.am
+++ b/lib/src/Makefile.am
@@ -1,4 +1,5 @@
INCLUDES = \
+ $(WARN_CFLAGS) \
$(LIB_CFLAGS)
noinst_LTLIBRARIES = libsugarprivate.la
@@ -10,5 +11,7 @@ libsugarprivate_la_SOURCES = \
eggaccelerators.c \
gecko-browser.h \
gecko-browser.cpp \
+ sugar-address-entry.h \
+ sugar-address-entry.c \
sugar-key-grabber.h \
sugar-key-grabber.c
diff --git a/lib/src/gecko-browser.cpp b/lib/src/gecko-browser.cpp
index cab07f8..bce6c40 100644
--- a/lib/src/gecko-browser.cpp
+++ b/lib/src/gecko-browser.cpp
@@ -22,6 +22,11 @@
#include <nsIPrefService.h>
#include <nsServiceManagerUtils.h>
+enum {
+ PROP_0,
+ PROP_PROGRESS
+};
+
void
gecko_browser_startup(void)
{
@@ -48,8 +53,38 @@ gecko_browser_new(void)
}
static void
+gecko_browser_get_property(GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeckoBrowser *browser = GECKO_BROWSER(object);
+
+ switch (prop_id) {
+ case PROP_PROGRESS:
+ g_value_set_double(value, browser->progress);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static void
gecko_browser_class_init(GeckoBrowserClass *browser_class)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(browser_class);
+
+ gobject_class->get_property = gecko_browser_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_PROGRESS,
+ g_param_spec_double ("progress",
+ "Progress",
+ "Progress",
+ 0.0, 1.0, 0.0,
+ G_PARAM_READABLE));
}
GeckoBrowser *
@@ -59,9 +94,9 @@ gecko_browser_create_window(GeckoBrowser *browser)
}
static void
-gecko_browser_new_window_cb(GtkMozEmbed *embed,
- GtkMozEmbed **newEmbed,
- guint chromemask)
+new_window_cb(GtkMozEmbed *embed,
+ GtkMozEmbed **newEmbed,
+ guint chromemask)
{
GeckoBrowser *browser;
@@ -71,8 +106,50 @@ gecko_browser_new_window_cb(GtkMozEmbed *embed,
}
static void
+gecko_browser_set_progress(GeckoBrowser *browser, float progress)
+{
+ g_return_if_fail(GECKO_IS_BROWSER(browser));
+
+ browser->progress = progress;
+ g_object_notify (G_OBJECT(browser), "progress");
+}
+
+static void
+net_state_cb(GtkMozEmbed *embed, const char *aURI, gint state, guint status)
+{
+ GeckoBrowser *browser = GECKO_BROWSER(embed);
+
+ if (state & GTK_MOZ_EMBED_FLAG_IS_NETWORK) {
+ if (state & GTK_MOZ_EMBED_FLAG_START) {
+ browser->total_requests = 0;
+ browser->current_requests = 0;
+ }
+ }
+
+ if (state & GTK_MOZ_EMBED_FLAG_IS_REQUEST) {
+ float progress;
+
+ if (state & GTK_MOZ_EMBED_FLAG_START) {
+ browser->total_requests++;
+ }
+ else if (state & GTK_MOZ_EMBED_FLAG_STOP)
+ {
+ browser->current_requests++;
+ }
+
+ progress = float(browser->current_requests) /
+ float(browser->total_requests);
+ gecko_browser_set_progress(browser, progress);
+ }
+}
+
+static void
gecko_browser_init(GeckoBrowser *browser)
{
+ browser->progress = 0.0;
+
g_signal_connect(G_OBJECT(browser), "new-window",
- G_CALLBACK(gecko_browser_new_window_cb), NULL);
+ G_CALLBACK(new_window_cb), NULL);
+ g_signal_connect(G_OBJECT(browser), "net-state-all",
+ G_CALLBACK(net_state_cb), NULL);
}
diff --git a/lib/src/gecko-browser.h b/lib/src/gecko-browser.h
index d41d2c5..9a62783 100644
--- a/lib/src/gecko-browser.h
+++ b/lib/src/gecko-browser.h
@@ -25,7 +25,6 @@ G_BEGIN_DECLS
typedef struct _GeckoBrowser GeckoBrowser;
typedef struct _GeckoBrowserClass GeckoBrowserClass;
-typedef struct _GeckoBrowserPrivate GeckoBrowserPrivate;
#define GECKO_TYPE_BROWSER (gecko_browser_get_type())
#define GECKO_BROWSER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), GECKO_TYPE_BROWSER, GeckoBrowser))
@@ -36,6 +35,10 @@ typedef struct _GeckoBrowserPrivate GeckoBrowserPrivate;
struct _GeckoBrowser {
GtkMozEmbed base_instance;
+
+ int total_requests;
+ int current_requests;
+ float progress;
};
struct _GeckoBrowserClass {
diff --git a/lib/src/sugar-address-entry.c b/lib/src/sugar-address-entry.c
new file mode 100644
index 0000000..fe27909
--- /dev/null
+++ b/lib/src/sugar-address-entry.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc
+ *
+ * Sugar 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.
+ *
+ * Sugar 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.
+ */
+
+#include <gtk/gtkentry.h>
+
+#include "sugar-address-entry.h"
+
+enum {
+ PROP_0,
+ PROP_PROGRESS
+};
+
+typedef enum {
+ CURSOR_STANDARD,
+ CURSOR_DND
+} CursorType;
+
+static void _gtk_entry_effective_inner_border (GtkEntry *entry,
+ GtkBorder *border);
+static void get_text_area_size (GtkEntry *entry,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height);
+
+G_DEFINE_TYPE(SugarAddressEntry, sugar_address_entry, GTK_TYPE_ENTRY)
+
+static GQuark quark_inner_border = 0;
+static const GtkBorder default_inner_border = { 2, 2, 2, 2 };
+
+static void
+draw_insertion_cursor (GtkEntry *entry,
+ GdkRectangle *cursor_location,
+ gboolean is_primary,
+ PangoDirection direction,
+ gboolean draw_arrow)
+{
+ GtkWidget *widget = GTK_WIDGET (entry);
+ GtkTextDirection text_dir;
+
+ if (direction == PANGO_DIRECTION_LTR)
+ text_dir = GTK_TEXT_DIR_LTR;
+ else
+ text_dir = GTK_TEXT_DIR_RTL;
+
+ gtk_draw_insertion_cursor (widget, entry->text_area, NULL,
+ cursor_location,
+ is_primary, text_dir, draw_arrow);
+}
+
+static void
+gtk_entry_get_pixel_ranges (GtkEntry *entry,
+ gint **ranges,
+ gint *n_ranges)
+{
+ gint start_char, end_char;
+
+ if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_char, &end_char))
+ {
+ //PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
+ PangoLayout *layout = gtk_entry_get_layout (entry);
+ PangoLayoutLine *line = pango_layout_get_lines (layout)->data;
+ const char *text = pango_layout_get_text (layout);
+ gint start_index = g_utf8_offset_to_pointer (text, start_char) - text;
+ gint end_index = g_utf8_offset_to_pointer (text, end_char) - text;
+ gint real_n_ranges, i;
+
+ pango_layout_line_get_x_ranges (line, start_index, end_index, ranges, &real_n_ranges);
+
+ if (ranges)
+ {
+ gint *r = *ranges;
+
+ for (i = 0; i < real_n_ranges; ++i)
+ {
+ r[2 * i + 1] = (r[2 * i + 1] - r[2 * i]) / PANGO_SCALE;
+ r[2 * i] = r[2 * i] / PANGO_SCALE;
+ }
+ }
+
+ if (n_ranges)
+ *n_ranges = real_n_ranges;
+ }
+ else
+ {
+ if (n_ranges)
+ *n_ranges = 0;
+ if (ranges)
+ *ranges = NULL;
+ }
+}
+
+static void
+gtk_entry_get_cursor_locations (GtkEntry *entry,
+ CursorType type,
+ gint *strong_x,
+ gint *weak_x)
+{
+ if (!entry->visible && !entry->invisible_char)
+ {
+ if (strong_x)
+ *strong_x = 0;
+
+ if (weak_x)
+ *weak_x = 0;
+ }
+ else
+ {
+ //PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
+ PangoLayout *layout = gtk_entry_get_layout (entry);
+ const gchar *text = pango_layout_get_text (layout);
+ PangoRectangle strong_pos, weak_pos;
+ gint index;
+
+ if (type == CURSOR_STANDARD)
+ {
+ index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text;
+ }
+ else /* type == CURSOR_DND */
+ {
+ index = g_utf8_offset_to_pointer (text, entry->dnd_position) - text;
+
+ if (entry->dnd_position > entry->current_pos)
+ {
+ if (entry->visible)
+ index += entry->preedit_length;
+ else
+ {
+ gint preedit_len_chars = g_utf8_strlen (text, -1) - entry->text_length;
+ index += preedit_len_chars * g_unichar_to_utf8 (entry->invisible_char, NULL);
+ }
+ }
+ }
+
+ pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
+
+ if (strong_x)
+ *strong_x = strong_pos.x / PANGO_SCALE;
+
+ if (weak_x)
+ *weak_x = weak_pos.x / PANGO_SCALE;
+ }
+}
+
+static void
+gtk_entry_draw_cursor (GtkEntry *entry,
+ CursorType type)
+{
+ GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
+ PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
+
+ if (GTK_WIDGET_DRAWABLE (entry))
+ {
+ GtkWidget *widget = GTK_WIDGET (entry);
+ GdkRectangle cursor_location;
+ gboolean split_cursor;
+
+ GtkBorder inner_border;
+ gint xoffset;
+ gint strong_x, weak_x;
+ gint text_area_height;
+ PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
+ PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
+ gint x1 = 0;
+ gint x2 = 0;
+
+ _gtk_entry_effective_inner_border (entry, &inner_border);
+
+ xoffset = inner_border.left - entry->scroll_offset;
+
+ gdk_drawable_get_size (entry->text_area, NULL, &text_area_height);
+
+ gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x);
+
+ g_object_get (gtk_widget_get_settings (widget),
+ "gtk-split-cursor", &split_cursor,
+ NULL);
+
+ dir1 = entry->resolved_dir;
+
+ if (split_cursor)
+ {
+ x1 = strong_x;
+
+ if (weak_x != strong_x)
+ {
+ dir2 = (entry->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
+ x2 = weak_x;
+ }
+ }
+ else
+ {
+ if (keymap_direction == entry->resolved_dir)
+ x1 = strong_x;
+ else
+ x1 = weak_x;
+ }
+
+ cursor_location.x = xoffset + x1;
+ cursor_location.y = inner_border.top;
+ cursor_location.width = 0;
+ cursor_location.height = text_area_height - inner_border.top - inner_border.bottom;
+
+ draw_insertion_cursor (entry,
+ &cursor_location, TRUE, dir1,
+ dir2 != PANGO_DIRECTION_NEUTRAL);
+
+ if (dir2 != PANGO_DIRECTION_NEUTRAL)
+ {
+ cursor_location.x = xoffset + x2;
+ draw_insertion_cursor (entry,
+ &cursor_location, FALSE, dir2,
+ TRUE);
+ }
+ }
+}
+
+static void
+get_layout_position (GtkEntry *entry,
+ gint *x,
+ gint *y)
+{
+ PangoLayout *layout;
+ PangoRectangle logical_rect;
+ gint area_width, area_height;
+ GtkBorder inner_border;
+ gint y_pos;
+ PangoLayoutLine *line;
+
+// layout = gtk_entry_ensure_layout (entry, TRUE);
+ layout = gtk_entry_get_layout(entry);
+
+ get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
+ _gtk_entry_effective_inner_border (entry, &inner_border);
+
+ area_height = PANGO_SCALE * (area_height - inner_border.top - inner_border.bottom);
+
+ line = pango_layout_get_lines (layout)->data;
+ pango_layout_line_get_extents (line, NULL, &logical_rect);
+
+ /* Align primarily for locale's ascent/descent */
+ y_pos = ((area_height - entry->ascent - entry->descent) / 2 +
+ entry->ascent + logical_rect.y);
+
+ /* Now see if we need to adjust to fit in actual drawn string */
+ if (logical_rect.height > area_height)
+ y_pos = (area_height - logical_rect.height) / 2;
+ else if (y_pos < 0)
+ y_pos = 0;
+ else if (y_pos + logical_rect.height > area_height)
+ y_pos = area_height - logical_rect.height;
+
+ y_pos = inner_border.top + y_pos / PANGO_SCALE;
+
+ if (x)
+ *x = inner_border.left - entry->scroll_offset;
+
+ if (y)
+ *y = y_pos;
+}
+
+static void
+_gtk_entry_effective_inner_border (GtkEntry *entry,
+ GtkBorder *border)
+{
+ GtkBorder *tmp_border;
+
+ tmp_border = g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
+
+ if (tmp_border)
+ {
+ *border = *tmp_border;
+ return;
+ }
+
+ gtk_widget_style_get (GTK_WIDGET (entry), "inner-border", &tmp_border, NULL);
+
+ if (tmp_border)
+ {
+ *border = *tmp_border;
+ g_free (tmp_border);
+ return;
+ }
+
+ *border = default_inner_border;
+}
+
+static void
+gtk_entry_draw_text (GtkEntry *entry)
+{
+ GtkWidget *widget;
+
+ if (!entry->visible && entry->invisible_char == 0)
+ return;
+
+ if (GTK_WIDGET_DRAWABLE (entry))
+ {
+ //PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
+ PangoLayout *layout = gtk_entry_get_layout (entry);
+ cairo_t *cr;
+ gint x, y;
+ gint start_pos, end_pos;
+
+ widget = GTK_WIDGET (entry);
+
+ get_layout_position (entry, &x, &y);
+
+ cr = gdk_cairo_create (entry->text_area);
+
+ cairo_move_to (cr, x, y);
+ gdk_cairo_set_source_color (cr, &widget->style->text [widget->state]);
+ pango_cairo_show_layout (cr, layout);
+
+ if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos))
+ {
+ gint *ranges;
+ gint n_ranges, i;
+ PangoRectangle logical_rect;
+ GdkColor *selection_color, *text_color;
+ GtkBorder inner_border;
+
+ pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+ gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
+
+ if (GTK_WIDGET_HAS_FOCUS (entry))
+ {
+ selection_color = &widget->style->base [GTK_STATE_SELECTED];
+ text_color = &widget->style->text [GTK_STATE_SELECTED];
+ }
+ else
+ {
+ selection_color = &widget->style->base [GTK_STATE_ACTIVE];
+ text_color = &widget->style->text [GTK_STATE_ACTIVE];
+ }
+
+ _gtk_entry_effective_inner_border (entry, &inner_border);
+
+ for (i = 0; i < n_ranges; ++i)
+ cairo_rectangle (cr,
+ inner_border.left - entry->scroll_offset + ranges[2 * i],
+ y,
+ ranges[2 * i + 1],
+ logical_rect.height);
+
+ cairo_clip (cr);
+
+ gdk_cairo_set_source_color (cr, selection_color);
+ cairo_paint (cr);
+
+ cairo_move_to (cr, x, y);
+ gdk_cairo_set_source_color (cr, text_color);
+ pango_cairo_show_layout (cr, layout);
+
+ g_free (ranges);
+ }
+
+ cairo_destroy (cr);
+ }
+}
+
+static void
+_gtk_entry_get_borders (GtkEntry *entry,
+ gint *xborder,
+ gint *yborder)
+{
+ GtkWidget *widget = GTK_WIDGET (entry);
+ gint focus_width;
+ gboolean interior_focus;
+
+ gtk_widget_style_get (widget,
+ "interior-focus", &interior_focus,
+ "focus-line-width", &focus_width,
+ NULL);
+
+ if (entry->has_frame)
+ {
+ *xborder = widget->style->xthickness;
+ *yborder = widget->style->ythickness;
+ }
+ else
+ {
+ *xborder = 0;
+ *yborder = 0;
+ }
+
+ if (!interior_focus)
+ {
+ *xborder += focus_width;
+ *yborder += focus_width;
+ }
+}
+
+static void
+get_text_area_size (GtkEntry *entry,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height)
+{
+ gint xborder, yborder;
+ GtkRequisition requisition;
+ GtkWidget *widget = GTK_WIDGET (entry);
+
+ gtk_widget_get_child_requisition (widget, &requisition);
+
+ _gtk_entry_get_borders (entry, &xborder, &yborder);
+
+ if (x)
+ *x = xborder;
+
+ if (y)
+ *y = yborder;
+
+ if (width)
+ *width = GTK_WIDGET (entry)->allocation.width - xborder * 2;
+
+ if (height)
+ *height = requisition.height - yborder * 2;
+}
+
+static gint
+sugar_address_entry_expose(GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GtkEntry *entry = GTK_ENTRY (widget);
+ SugarAddressEntry *address_entry = SUGAR_ADDRESS_ENTRY(widget);
+ cairo_t *cr;
+
+ if (entry->text_area == event->window) {
+ gint area_width, area_height;
+
+ get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
+
+/* gtk_paint_flat_box (widget->style, entry->text_area,
+ GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
+ NULL, widget, "entry_bg",
+ 0, 0, area_width, area_height);
+*/
+
+ if (address_entry->progress != 0.0 && address_entry->progress != 1.0) {
+ int bar_width = area_width * address_entry->progress;
+
+ cr = gdk_cairo_create(entry->text_area);
+ cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+ cairo_rectangle(cr, 0, 0, bar_width, area_height);
+ cairo_fill(cr);
+ cairo_destroy (cr);
+ }
+
+
+ if ((entry->visible || entry->invisible_char != 0) &&
+ GTK_WIDGET_HAS_FOCUS (widget) &&
+ entry->selection_bound == entry->current_pos && entry->cursor_visible)
+ gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD);
+
+ if (entry->dnd_position != -1)
+ gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND);
+
+ gtk_entry_draw_text (GTK_ENTRY (widget));
+ } else {
+ GtkWidgetClass *parent_class;
+ parent_class = GTK_WIDGET_CLASS(sugar_address_entry_parent_class);
+ parent_class->expose_event(widget, event);
+ }
+
+ return FALSE;
+}
+
+static void
+sugar_address_entry_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SugarAddressEntry *entry = SUGAR_ADDRESS_ENTRY(object);
+
+ switch (prop_id) {
+ case PROP_PROGRESS:
+ entry->progress = g_value_get_double (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+sugar_address_entry_get_property(GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SugarAddressEntry *entry = SUGAR_ADDRESS_ENTRY(object);
+
+ switch (prop_id) {
+ case PROP_PROGRESS:
+ g_value_set_double(value, entry->progress);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+sugar_address_entry_class_init(SugarAddressEntryClass *klass)
+{
+ GtkWidgetClass *widget_class = (GtkWidgetClass*)klass;
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ widget_class->expose_event = sugar_address_entry_expose;
+
+ gobject_class->set_property = sugar_address_entry_set_property;
+ gobject_class->get_property = sugar_address_entry_get_property;
+
+ quark_inner_border = g_quark_from_static_string ("gtk-entry-inner-border");
+
+ g_object_class_install_property (gobject_class, PROP_PROGRESS,
+ g_param_spec_double ("progress",
+ "Progress",
+ "Progress",
+ 0.0, 1.0, 0.0,
+ G_PARAM_READWRITE));
+
+}
+
+static void
+sugar_address_entry_init(SugarAddressEntry *entry)
+{
+ entry->progress = 0.0;
+}
diff --git a/lib/src/sugar-address-entry.h b/lib/src/sugar-address-entry.h
new file mode 100644
index 0000000..479e677
--- /dev/null
+++ b/lib/src/sugar-address-entry.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc
+ *
+ * Sugar 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.
+ *
+ * Sugar 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 __SUGAR_ADDRESS_ENTRY_H__
+#define __SUGAR_ADDRESS_ENTRY_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SugarAddressEntry SugarAddressEntry;
+typedef struct _SugarAddressEntryClass SugarAddressEntryClass;
+typedef struct _SugarAddressEntryPrivate SugarAddressEntryPrivate;
+
+#define SUGAR_TYPE_ADDRESS_ENTRY (sugar_address_entry_get_type())
+#define SUGAR_ADDRESS_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_ADDRESS_ENTRY, SugarAddressEntry))
+#define SUGAR_ADDRESS_ENTRY_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), SUGAR_TYPE_ADDRESS_ENTRY, SugarAddressEntryClass))
+#define SUGAR_IS_ADDRESS_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_ADDRESS_ENTRY))
+#define SUGAR_IS_ADDRESS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_ADDRESS_ENTRY))
+#define SUGAR_ADDRESS_ENTRY_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_ADDRESS_ENTRY, SugarAddressEntryClass))
+
+struct _SugarAddressEntry {
+ GtkEntry base_instance;
+
+ float progress;
+};
+
+struct _SugarAddressEntryClass {
+ GtkEntryClass base_class;
+};
+
+GType sugar_address_entry_get_type (void);
+
+G_END_DECLS
+
+#endif /* __SUGAR_ADDRESS_ENTRY_H__ */