First go at progress in the entry.
This commit is contained in:
parent
62a46ff92b
commit
3cfa9c40bd
@ -1,6 +1,8 @@
|
||||
import gobject
|
||||
import gtk
|
||||
|
||||
from _sugar import AddressEntry
|
||||
|
||||
class AddressItem(gtk.ToolItem):
|
||||
__gsignals__ = {
|
||||
'open-address': (gobject.SIGNAL_RUN_FIRST,
|
||||
@ -10,12 +12,17 @@ class AddressItem(gtk.ToolItem):
|
||||
def __init__(self):
|
||||
gtk.ToolItem.__init__(self)
|
||||
|
||||
entry = gtk.Entry()
|
||||
entry = AddressEntry()
|
||||
width = int(gtk.gdk.screen_width() / 3 * 2)
|
||||
entry.set_size_request(width, -1)
|
||||
entry.connect("activate", self.__activate_cb)
|
||||
self.add(entry)
|
||||
entry.show()
|
||||
|
||||
self._entry = entry
|
||||
|
||||
def __activate_cb(self, entry):
|
||||
self.emit('open-address', entry.get_text())
|
||||
|
||||
def set_progress(self, progress):
|
||||
self._entry.set_property('progress', progress)
|
||||
|
@ -29,10 +29,10 @@ class NavigationToolbar(gtk.Toolbar):
|
||||
self.insert(separator, -1)
|
||||
separator.show()
|
||||
|
||||
address_item = AddressItem()
|
||||
address_item.connect('open-address', self.__open_address_cb)
|
||||
self.insert(address_item, -1)
|
||||
address_item.show()
|
||||
self._address_item = AddressItem()
|
||||
self._address_item.connect('open-address', self.__open_address_cb)
|
||||
self.insert(self._address_item, -1)
|
||||
self._address_item.show()
|
||||
|
||||
self._insert_spring()
|
||||
|
||||
@ -49,10 +49,15 @@ class NavigationToolbar(gtk.Toolbar):
|
||||
self._embed.connect("location", self.__location_changed)
|
||||
self._update_sensitivity()
|
||||
|
||||
self._embed.connect("notify::progress", self._progress_changed_cb)
|
||||
|
||||
def _update_sensitivity(self):
|
||||
self.back.set_sensitive(self._embed.can_go_back())
|
||||
self.forward.set_sensitive(self._embed.can_go_forward())
|
||||
|
||||
def _progress_changed_cb(self, embed, pspec):
|
||||
self._address_item.set_progress(embed.props.progress)
|
||||
|
||||
def __go_back_cb(self, button):
|
||||
self._embed.go_back()
|
||||
|
||||
|
@ -30,6 +30,9 @@ AC_SUBST(MOZILLA_HOME)
|
||||
GNOMEPYTHONEXTRAS_DEFSDIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0`
|
||||
AC_SUBST(GNOMEPYTHONEXTRAS_DEFSDIR)
|
||||
|
||||
PYGTK_DEFSDIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0`
|
||||
AC_SUBST(PYGTK_DEFSDIR)
|
||||
|
||||
#
|
||||
# Setup GETTEXT
|
||||
#
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 ...
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -22,6 +22,11 @@
|
||||
#include <nsIPrefService.h>
|
||||
#include <nsServiceManagerUtils.h>
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PROGRESS
|
||||
};
|
||||
|
||||
void
|
||||
gecko_browser_startup(void)
|
||||
{
|
||||
@ -47,9 +52,39 @@ gecko_browser_new(void)
|
||||
return GECKO_BROWSER(g_object_new(GECKO_TYPE_BROWSER, NULL));
|
||||
}
|
||||
|
||||
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,7 +94,7 @@ gecko_browser_create_window(GeckoBrowser *browser)
|
||||
}
|
||||
|
||||
static void
|
||||
gecko_browser_new_window_cb(GtkMozEmbed *embed,
|
||||
new_window_cb(GtkMozEmbed *embed,
|
||||
GtkMozEmbed **newEmbed,
|
||||
guint chromemask)
|
||||
{
|
||||
@ -70,9 +105,51 @@ gecko_browser_new_window_cb(GtkMozEmbed *embed,
|
||||
*newEmbed = GTK_MOZ_EMBED(browser);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
548
lib/src/sugar-address-entry.c
Normal file
548
lib/src/sugar-address-entry.c
Normal file
@ -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;
|
||||
}
|
51
lib/src/sugar-address-entry.h
Normal file
51
lib/src/sugar-address-entry.h
Normal file
@ -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__ */
|
27
tests/test-browser.py
Executable file
27
tests/test-browser.py
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/python
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
||||
from sugar.session.UITestSession import UITestSession
|
||||
|
||||
session = UITestSession()
|
||||
session.start()
|
||||
|
||||
import gtk
|
||||
import _sugar
|
||||
|
||||
# Main window
|
||||
window = gtk.Window()
|
||||
window.connect("destroy", lambda w: gtk.main_quit())
|
||||
|
||||
_sugar.startup_browser()
|
||||
|
||||
browser = _sugar.Browser()
|
||||
window.add(browser)
|
||||
browser.show()
|
||||
|
||||
browser.load_url('http://www.google.com')
|
||||
|
||||
window.show()
|
||||
|
||||
gtk.main()
|
Loading…
Reference in New Issue
Block a user