Replace our custom entry widget with one based on gtk.Entry
Our custom entry widget, which was based on sexyicon, did support placing an icon in the entry (e.g. the magnifier icon for the search entry) and displaying progress in the case of the url entry in Browse. Both is supported since GTK+ 2.16 in the gtk.Entry. The patch does keep the old API, that is why we can land it in 0.94 no change in the shell needed only a small change in Browse, in a second step I would like to use the upstream API e.g. 's/set_icon_from_name/set_icon_from_icon_name'. Signed-off-by: Simon Schampijer <simon@laptop.org> Reviewed-by: Benjamin Berg <benzea@sugarlabs.org>
This commit is contained in:
parent
d0a493e532
commit
4018265f6c
@ -47,10 +47,6 @@ _sugarext_la_SOURCES = \
|
|||||||
eggsmclient.c \
|
eggsmclient.c \
|
||||||
eggsmclient-private.h \
|
eggsmclient-private.h \
|
||||||
eggsmclient-xsmp.c \
|
eggsmclient-xsmp.c \
|
||||||
sexy-icon-entry.h \
|
|
||||||
sexy-icon-entry.c \
|
|
||||||
sugar-address-entry.c \
|
|
||||||
sugar-address-entry.h \
|
|
||||||
sugar-grid.c \
|
sugar-grid.c \
|
||||||
sugar-grid.h \
|
sugar-grid.h \
|
||||||
sugar-key-grabber.c \
|
sugar-key-grabber.c \
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
;; -*- scheme -*-
|
;; -*- scheme -*-
|
||||||
; object definitions
|
; object definitions
|
||||||
|
|
||||||
(define-object AddressEntry
|
|
||||||
(in-module "Sugar")
|
|
||||||
(parent "GtkEntry")
|
|
||||||
(c-name "SugarAddressEntry")
|
|
||||||
(gtype-id "SUGAR_TYPE_ADDRESS_ENTRY")
|
|
||||||
)
|
|
||||||
|
|
||||||
(define-object KeyGrabber
|
(define-object KeyGrabber
|
||||||
(in-module "Sugar")
|
(in-module "Sugar")
|
||||||
(parent "GObject")
|
(parent "GObject")
|
||||||
@ -29,13 +22,6 @@
|
|||||||
(gtype-id "SUGAR_TYPE_GRID")
|
(gtype-id "SUGAR_TYPE_GRID")
|
||||||
)
|
)
|
||||||
|
|
||||||
(define-object IconEntry
|
|
||||||
(in-module "Sexy")
|
|
||||||
(parent "GtkEntry")
|
|
||||||
(c-name "SexyIconEntry")
|
|
||||||
(gtype-id "SEXY_TYPE_ICON_ENTRY")
|
|
||||||
)
|
|
||||||
|
|
||||||
(define-object SMClientXSMP
|
(define-object SMClientXSMP
|
||||||
(in-module "Egg")
|
(in-module "Egg")
|
||||||
(parent "EggSMClient")
|
(parent "EggSMClient")
|
||||||
@ -71,18 +57,6 @@
|
|||||||
(gtype-id "ACME_TYPE_VOLUME_ALSA")
|
(gtype-id "ACME_TYPE_VOLUME_ALSA")
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Enumerations and flags ...
|
|
||||||
|
|
||||||
(define-enum IconEntryPosition
|
|
||||||
(in-module "Sexy")
|
|
||||||
(c-name "SexyIconEntryPosition")
|
|
||||||
(gtype-id "SEXY_TYPE_ICON_ENTRY_POSITION")
|
|
||||||
(values
|
|
||||||
'("primary" "SEXY_ICON_ENTRY_PRIMARY")
|
|
||||||
'("secondary" "SEXY_ICON_ENTRY_SECONDARY")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
;; From sugar-menu.h
|
;; From sugar-menu.h
|
||||||
|
|
||||||
(define-method set_active
|
(define-method set_active
|
||||||
@ -184,63 +158,6 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
;; From sexy-icon-entry.h
|
|
||||||
|
|
||||||
(define-function sexy_icon_entry_get_type
|
|
||||||
(c-name "sexy_icon_entry_get_type")
|
|
||||||
(return-type "GType")
|
|
||||||
)
|
|
||||||
|
|
||||||
(define-function sexy_icon_entry_new
|
|
||||||
(c-name "sexy_icon_entry_new")
|
|
||||||
(is-constructor-of "SexyIconEntry")
|
|
||||||
(return-type "GtkWidget*")
|
|
||||||
)
|
|
||||||
|
|
||||||
(define-method set_icon
|
|
||||||
(of-object "SexyIconEntry")
|
|
||||||
(c-name "sexy_icon_entry_set_icon")
|
|
||||||
(return-type "none")
|
|
||||||
(parameters
|
|
||||||
'("SexyIconEntryPosition" "position")
|
|
||||||
'("GtkImage*" "icon" (null-ok))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
(define-method set_icon_highlight
|
|
||||||
(of-object "SexyIconEntry")
|
|
||||||
(c-name "sexy_icon_entry_set_icon_highlight")
|
|
||||||
(return-type "none")
|
|
||||||
(parameters
|
|
||||||
'("SexyIconEntryPosition" "position")
|
|
||||||
'("gboolean" "highlight")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
(define-method get_icon
|
|
||||||
(of-object "SexyIconEntry")
|
|
||||||
(c-name "sexy_icon_entry_get_icon")
|
|
||||||
(return-type "GtkImage*")
|
|
||||||
(parameters
|
|
||||||
'("SexyIconEntryPosition" "position")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
(define-method get_icon_highlight
|
|
||||||
(of-object "SexyIconEntry")
|
|
||||||
(c-name "sexy_icon_entry_get_icon_highlight")
|
|
||||||
(return-type "gboolean")
|
|
||||||
(parameters
|
|
||||||
'("SexyIconEntryPosition" "position")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
(define-method add_clear_button
|
|
||||||
(of-object "SexyIconEntry")
|
|
||||||
(c-name "sexy_icon_entry_add_clear_button")
|
|
||||||
(return-type "none")
|
|
||||||
)
|
|
||||||
|
|
||||||
;; From eggsmclient.h
|
;; From eggsmclient.h
|
||||||
|
|
||||||
(define-function egg_sm_client_get_type
|
(define-function egg_sm_client_get_type
|
||||||
|
@ -4,11 +4,9 @@ headers
|
|||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
|
||||||
#include "pygobject.h"
|
#include "pygobject.h"
|
||||||
#include "sugar-address-entry.h"
|
|
||||||
#include "sugar-grid.h"
|
#include "sugar-grid.h"
|
||||||
#include "sugar-key-grabber.h"
|
#include "sugar-key-grabber.h"
|
||||||
#include "sugar-menu.h"
|
#include "sugar-menu.h"
|
||||||
#include "sexy-icon-entry.h"
|
|
||||||
#include "gsm-session.h"
|
#include "gsm-session.h"
|
||||||
#include "gsm-xsmp.h"
|
#include "gsm-xsmp.h"
|
||||||
#include "acme-volume-alsa.h"
|
#include "acme-volume-alsa.h"
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
extern PyMethodDef py_sugarext_functions[];
|
extern PyMethodDef py_sugarext_functions[];
|
||||||
|
|
||||||
void py_sugarext_register_classes (PyObject *d);
|
void py_sugarext_register_classes (PyObject *d);
|
||||||
void py_sugarext_add_constants (PyObject *module, const gchar *strip_prefix);
|
|
||||||
|
|
||||||
DL_EXPORT(void)
|
DL_EXPORT(void)
|
||||||
init_sugarext(void)
|
init_sugarext(void)
|
||||||
@ -42,7 +41,6 @@ init_sugarext(void)
|
|||||||
d = PyModule_GetDict(m);
|
d = PyModule_GetDict(m);
|
||||||
|
|
||||||
py_sugarext_register_classes(d);
|
py_sugarext_register_classes(d);
|
||||||
py_sugarext_add_constants(m, "SEXY_");
|
|
||||||
|
|
||||||
if (PyErr_Occurred ()) {
|
if (PyErr_Occurred ()) {
|
||||||
Py_FatalError ("can't initialise module _sugarext");
|
Py_FatalError ("can't initialise module _sugarext");
|
||||||
|
@ -17,19 +17,17 @@
|
|||||||
|
|
||||||
import gtk
|
import gtk
|
||||||
|
|
||||||
from sugar import _sugarext
|
|
||||||
|
|
||||||
from sugar.graphics import style
|
from sugar.graphics import style
|
||||||
from sugar.graphics.icon import _SVGLoader
|
from sugar.graphics.icon import _SVGLoader
|
||||||
|
|
||||||
ICON_ENTRY_PRIMARY = _sugarext.ICON_ENTRY_PRIMARY
|
ICON_ENTRY_PRIMARY = gtk.ENTRY_ICON_PRIMARY
|
||||||
ICON_ENTRY_SECONDARY = _sugarext.ICON_ENTRY_SECONDARY
|
ICON_ENTRY_SECONDARY = gtk.ENTRY_ICON_SECONDARY
|
||||||
|
|
||||||
|
|
||||||
class IconEntry(_sugarext.IconEntry):
|
class IconEntry(gtk.Entry):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
_sugarext.IconEntry.__init__(self)
|
gtk.Entry.__init__(self)
|
||||||
|
|
||||||
self._clear_icon = None
|
self._clear_icon = None
|
||||||
self._clear_shown = False
|
self._clear_shown = False
|
||||||
@ -51,21 +49,15 @@ class IconEntry(_sugarext.IconEntry):
|
|||||||
else:
|
else:
|
||||||
pixbuf = gtk.gdk.pixbuf_new_from_file(icon_info.get_filename())
|
pixbuf = gtk.gdk.pixbuf_new_from_file(icon_info.get_filename())
|
||||||
del icon_info
|
del icon_info
|
||||||
|
self.set_icon(position, pixbuf)
|
||||||
|
|
||||||
image = gtk.Image()
|
def set_icon(self, position, pixbuf):
|
||||||
image.set_from_pixbuf(pixbuf)
|
if type(pixbuf) is not gtk.gdk.Pixbuf:
|
||||||
image.show()
|
raise ValueError('Argument must be a pixbuf, not %r.' % pixbuf)
|
||||||
|
self.set_icon_from_pixbuf(position, pixbuf)
|
||||||
self.set_icon(position, image)
|
|
||||||
|
|
||||||
def set_icon(self, position, image):
|
|
||||||
if image.get_storage_type() not in [gtk.IMAGE_PIXBUF, gtk.IMAGE_STOCK]:
|
|
||||||
raise ValueError('Image must have a storage type of pixbuf or ' +
|
|
||||||
'stock, not %r.' % image.get_storage_type())
|
|
||||||
_sugarext.IconEntry.set_icon(self, position, image)
|
|
||||||
|
|
||||||
def remove_icon(self, position):
|
def remove_icon(self, position):
|
||||||
_sugarext.IconEntry.set_icon(self, position, None)
|
self.set_icon_from_pixbuf(position, None)
|
||||||
|
|
||||||
def add_clear_button(self):
|
def add_clear_button(self):
|
||||||
if self.props.text != "":
|
if self.props.text != "":
|
||||||
@ -73,13 +65,13 @@ class IconEntry(_sugarext.IconEntry):
|
|||||||
else:
|
else:
|
||||||
self.hide_clear_button()
|
self.hide_clear_button()
|
||||||
|
|
||||||
self.connect('icon-pressed', self._icon_pressed_cb)
|
self.connect('icon-press', self._icon_pressed_cb)
|
||||||
self.connect('changed', self._changed_cb)
|
self.connect('changed', self._changed_cb)
|
||||||
|
|
||||||
def show_clear_button(self):
|
def show_clear_button(self):
|
||||||
if not self._clear_shown:
|
if not self._clear_shown:
|
||||||
self.set_icon_from_name(ICON_ENTRY_SECONDARY,
|
self.set_icon_from_name(ICON_ENTRY_SECONDARY,
|
||||||
'dialog-cancel')
|
'dialog-cancel')
|
||||||
self._clear_shown = True
|
self._clear_shown = True
|
||||||
|
|
||||||
def hide_clear_button(self):
|
def hide_clear_button(self):
|
||||||
|
@ -1,984 +0,0 @@
|
|||||||
/*
|
|
||||||
* @file libsexy/sexy-icon-entry.c Entry widget
|
|
||||||
*
|
|
||||||
* @Copyright (C) 2004-2006 Christian Hammond.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser 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.
|
|
||||||
*/
|
|
||||||
#include <sexy-icon-entry.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
|
|
||||||
#define ICON_MARGIN 2
|
|
||||||
#define MAX_ICONS 2
|
|
||||||
|
|
||||||
#define IS_VALID_ICON_ENTRY_POSITION(pos) \
|
|
||||||
((pos) == SEXY_ICON_ENTRY_PRIMARY || \
|
|
||||||
(pos) == SEXY_ICON_ENTRY_SECONDARY)
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
GtkImage *icon;
|
|
||||||
gboolean highlight;
|
|
||||||
gboolean hovered;
|
|
||||||
GdkWindow *window;
|
|
||||||
|
|
||||||
} SexyIconInfo;
|
|
||||||
|
|
||||||
struct _SexyIconEntryPriv
|
|
||||||
{
|
|
||||||
SexyIconInfo icons[MAX_ICONS];
|
|
||||||
|
|
||||||
gulong icon_released_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ICON_PRESSED,
|
|
||||||
ICON_RELEASED,
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
static void sexy_icon_entry_class_init(SexyIconEntryClass *klass);
|
|
||||||
static void sexy_icon_entry_editable_init(GtkEditableClass *iface);
|
|
||||||
static void sexy_icon_entry_init(SexyIconEntry *entry);
|
|
||||||
static void sexy_icon_entry_finalize(GObject *obj);
|
|
||||||
static void sexy_icon_entry_destroy(GtkObject *obj);
|
|
||||||
static void sexy_icon_entry_map(GtkWidget *widget);
|
|
||||||
static void sexy_icon_entry_unmap(GtkWidget *widget);
|
|
||||||
static void sexy_icon_entry_realize(GtkWidget *widget);
|
|
||||||
static void sexy_icon_entry_unrealize(GtkWidget *widget);
|
|
||||||
static void sexy_icon_entry_size_request(GtkWidget *widget,
|
|
||||||
GtkRequisition *requisition);
|
|
||||||
static void sexy_icon_entry_size_allocate(GtkWidget *widget,
|
|
||||||
GtkAllocation *allocation);
|
|
||||||
static gint sexy_icon_entry_expose(GtkWidget *widget, GdkEventExpose *event);
|
|
||||||
static gint sexy_icon_entry_enter_notify(GtkWidget *widget,
|
|
||||||
GdkEventCrossing *event);
|
|
||||||
static gint sexy_icon_entry_leave_notify(GtkWidget *widget,
|
|
||||||
GdkEventCrossing *event);
|
|
||||||
static gint sexy_icon_entry_button_press(GtkWidget *widget,
|
|
||||||
GdkEventButton *event);
|
|
||||||
static gint sexy_icon_entry_button_release(GtkWidget *widget,
|
|
||||||
GdkEventButton *event);
|
|
||||||
|
|
||||||
static GtkEntryClass *parent_class = NULL;
|
|
||||||
static guint signals[LAST_SIGNAL] = {0};
|
|
||||||
|
|
||||||
G_DEFINE_TYPE_EXTENDED(SexyIconEntry, sexy_icon_entry, GTK_TYPE_ENTRY,
|
|
||||||
0,
|
|
||||||
G_IMPLEMENT_INTERFACE(GTK_TYPE_EDITABLE,
|
|
||||||
sexy_icon_entry_editable_init));
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_class_init(SexyIconEntryClass *klass)
|
|
||||||
{
|
|
||||||
GObjectClass *gobject_class;
|
|
||||||
GtkObjectClass *object_class;
|
|
||||||
GtkWidgetClass *widget_class;
|
|
||||||
GtkEntryClass *entry_class;
|
|
||||||
|
|
||||||
parent_class = g_type_class_peek_parent(klass);
|
|
||||||
|
|
||||||
gobject_class = G_OBJECT_CLASS(klass);
|
|
||||||
object_class = GTK_OBJECT_CLASS(klass);
|
|
||||||
widget_class = GTK_WIDGET_CLASS(klass);
|
|
||||||
entry_class = GTK_ENTRY_CLASS(klass);
|
|
||||||
|
|
||||||
gobject_class->finalize = sexy_icon_entry_finalize;
|
|
||||||
|
|
||||||
object_class->destroy = sexy_icon_entry_destroy;
|
|
||||||
|
|
||||||
widget_class->map = sexy_icon_entry_map;
|
|
||||||
widget_class->unmap = sexy_icon_entry_unmap;
|
|
||||||
widget_class->realize = sexy_icon_entry_realize;
|
|
||||||
widget_class->unrealize = sexy_icon_entry_unrealize;
|
|
||||||
widget_class->size_request = sexy_icon_entry_size_request;
|
|
||||||
widget_class->size_allocate = sexy_icon_entry_size_allocate;
|
|
||||||
widget_class->expose_event = sexy_icon_entry_expose;
|
|
||||||
widget_class->enter_notify_event = sexy_icon_entry_enter_notify;
|
|
||||||
widget_class->leave_notify_event = sexy_icon_entry_leave_notify;
|
|
||||||
widget_class->button_press_event = sexy_icon_entry_button_press;
|
|
||||||
widget_class->button_release_event = sexy_icon_entry_button_release;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SexyIconEntry::icon-pressed:
|
|
||||||
* @entry: The entry on which the signal is emitted.
|
|
||||||
* @icon_pos: The position of the clicked icon.
|
|
||||||
* @button: The mouse button clicked.
|
|
||||||
*
|
|
||||||
* The ::icon-pressed signal is emitted when an icon is clicked.
|
|
||||||
*/
|
|
||||||
signals[ICON_PRESSED] =
|
|
||||||
g_signal_new("icon_pressed",
|
|
||||||
G_TYPE_FROM_CLASS(gobject_class),
|
|
||||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
|
||||||
G_STRUCT_OFFSET(SexyIconEntryClass, icon_pressed),
|
|
||||||
NULL, NULL,
|
|
||||||
gtk_marshal_VOID__INT_INT,
|
|
||||||
G_TYPE_NONE, 2,
|
|
||||||
G_TYPE_INT,
|
|
||||||
G_TYPE_INT);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SexyIconEntry::icon-released:
|
|
||||||
* @entry: The entry on which the signal is emitted.
|
|
||||||
* @icon_pos: The position of the clicked icon.
|
|
||||||
* @button: The mouse button clicked.
|
|
||||||
*
|
|
||||||
* The ::icon-released signal is emitted on the button release from a
|
|
||||||
* mouse click.
|
|
||||||
*/
|
|
||||||
signals[ICON_RELEASED] =
|
|
||||||
g_signal_new("icon_released",
|
|
||||||
G_TYPE_FROM_CLASS(gobject_class),
|
|
||||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
|
||||||
G_STRUCT_OFFSET(SexyIconEntryClass, icon_released),
|
|
||||||
NULL, NULL,
|
|
||||||
gtk_marshal_VOID__INT_INT,
|
|
||||||
G_TYPE_NONE, 2,
|
|
||||||
G_TYPE_INT,
|
|
||||||
G_TYPE_INT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_editable_init(GtkEditableClass *iface)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_init(SexyIconEntry *entry)
|
|
||||||
{
|
|
||||||
entry->priv = g_new0(SexyIconEntryPriv, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_finalize(GObject *obj)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry;
|
|
||||||
|
|
||||||
g_return_if_fail(obj != NULL);
|
|
||||||
g_return_if_fail(SEXY_IS_ICON_ENTRY(obj));
|
|
||||||
|
|
||||||
entry = SEXY_ICON_ENTRY(obj);
|
|
||||||
|
|
||||||
g_free(entry->priv);
|
|
||||||
|
|
||||||
if (G_OBJECT_CLASS(parent_class)->finalize)
|
|
||||||
G_OBJECT_CLASS(parent_class)->finalize(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_destroy(GtkObject *obj)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry;
|
|
||||||
|
|
||||||
entry = SEXY_ICON_ENTRY(obj);
|
|
||||||
|
|
||||||
sexy_icon_entry_set_icon(entry, SEXY_ICON_ENTRY_PRIMARY, NULL);
|
|
||||||
sexy_icon_entry_set_icon(entry, SEXY_ICON_ENTRY_SECONDARY, NULL);
|
|
||||||
|
|
||||||
if (GTK_OBJECT_CLASS(parent_class)->destroy)
|
|
||||||
GTK_OBJECT_CLASS(parent_class)->destroy(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_map(GtkWidget *widget)
|
|
||||||
{
|
|
||||||
if (GTK_WIDGET_REALIZED(widget) && !GTK_WIDGET_MAPPED(widget))
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
GTK_WIDGET_CLASS(parent_class)->map(widget);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS; i++)
|
|
||||||
{
|
|
||||||
if (entry->priv->icons[i].icon != NULL)
|
|
||||||
gdk_window_show(entry->priv->icons[i].window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_unmap(GtkWidget *widget)
|
|
||||||
{
|
|
||||||
if (GTK_WIDGET_MAPPED(widget))
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS; i++)
|
|
||||||
{
|
|
||||||
if (entry->priv->icons[i].icon != NULL)
|
|
||||||
gdk_window_hide(entry->priv->icons[i].window);
|
|
||||||
}
|
|
||||||
|
|
||||||
GTK_WIDGET_CLASS(parent_class)->unmap(widget);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
get_icon_width(SexyIconEntry *entry, SexyIconEntryPosition icon_pos)
|
|
||||||
{
|
|
||||||
GtkRequisition requisition;
|
|
||||||
gint menu_icon_width;
|
|
||||||
gint width;
|
|
||||||
SexyIconInfo *icon_info = &entry->priv->icons[icon_pos];
|
|
||||||
|
|
||||||
if (icon_info->icon == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
gtk_widget_size_request(GTK_WIDGET(icon_info->icon), &requisition);
|
|
||||||
gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &menu_icon_width, NULL);
|
|
||||||
|
|
||||||
width = MAX(requisition.width, menu_icon_width);
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_borders(SexyIconEntry *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 (gtk_entry_get_has_frame(GTK_ENTRY(entry)))
|
|
||||||
{
|
|
||||||
*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(SexyIconEntry *entry, GtkAllocation *alloc)
|
|
||||||
{
|
|
||||||
GtkWidget *widget = GTK_WIDGET(entry);
|
|
||||||
GtkRequisition requisition;
|
|
||||||
gint xborder, yborder;
|
|
||||||
|
|
||||||
gtk_widget_get_child_requisition(widget, &requisition);
|
|
||||||
get_borders(entry, &xborder, &yborder);
|
|
||||||
|
|
||||||
alloc->x = xborder;
|
|
||||||
alloc->y = yborder;
|
|
||||||
alloc->width = widget->allocation.width - xborder * 2;
|
|
||||||
alloc->height = requisition.height - yborder * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_icon_allocation(SexyIconEntry *icon_entry,
|
|
||||||
gboolean left,
|
|
||||||
GtkAllocation *widget_alloc,
|
|
||||||
GtkAllocation *text_area_alloc,
|
|
||||||
GtkAllocation *allocation,
|
|
||||||
SexyIconEntryPosition *icon_pos)
|
|
||||||
{
|
|
||||||
gboolean rtl;
|
|
||||||
|
|
||||||
rtl = (gtk_widget_get_direction(GTK_WIDGET(icon_entry)) ==
|
|
||||||
GTK_TEXT_DIR_RTL);
|
|
||||||
|
|
||||||
if (left)
|
|
||||||
*icon_pos = (rtl ? SEXY_ICON_ENTRY_SECONDARY : SEXY_ICON_ENTRY_PRIMARY);
|
|
||||||
else
|
|
||||||
*icon_pos = (rtl ? SEXY_ICON_ENTRY_PRIMARY : SEXY_ICON_ENTRY_SECONDARY);
|
|
||||||
|
|
||||||
allocation->y = text_area_alloc->y;
|
|
||||||
allocation->width = get_icon_width(icon_entry, *icon_pos);
|
|
||||||
allocation->height = text_area_alloc->height;
|
|
||||||
|
|
||||||
if (left)
|
|
||||||
allocation->x = text_area_alloc->x + ICON_MARGIN;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
allocation->x = text_area_alloc->x + text_area_alloc->width -
|
|
||||||
allocation->width - ICON_MARGIN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_realize(GtkWidget *widget)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
GdkWindowAttr attributes;
|
|
||||||
gint attributes_mask;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
GTK_WIDGET_CLASS(parent_class)->realize(widget);
|
|
||||||
|
|
||||||
attributes.x = 0;
|
|
||||||
attributes.y = 0;
|
|
||||||
attributes.width = 1;
|
|
||||||
attributes.height = 1;
|
|
||||||
attributes.window_type = GDK_WINDOW_CHILD;
|
|
||||||
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
||||||
attributes.visual = gtk_widget_get_visual(widget);
|
|
||||||
attributes.colormap = gtk_widget_get_colormap(widget);
|
|
||||||
attributes.event_mask = gtk_widget_get_events(widget);
|
|
||||||
attributes.event_mask |=
|
|
||||||
(GDK_EXPOSURE_MASK
|
|
||||||
| GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
|
|
||||||
| GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
|
|
||||||
|
|
||||||
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS; i++)
|
|
||||||
{
|
|
||||||
SexyIconInfo *icon_info;
|
|
||||||
|
|
||||||
icon_info = &entry->priv->icons[i];
|
|
||||||
icon_info->window = gdk_window_new(widget->window, &attributes,
|
|
||||||
attributes_mask);
|
|
||||||
gdk_window_set_user_data(icon_info->window, widget);
|
|
||||||
|
|
||||||
gdk_window_set_background(icon_info->window,
|
|
||||||
&widget->style->base[GTK_WIDGET_STATE(widget)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_widget_queue_resize(widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_unrealize(GtkWidget *widget)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS; i++)
|
|
||||||
{
|
|
||||||
SexyIconInfo *icon_info = &entry->priv->icons[i];
|
|
||||||
|
|
||||||
gdk_window_destroy(icon_info->window);
|
|
||||||
icon_info->window = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_size_request(GtkWidget *widget, GtkRequisition *requisition)
|
|
||||||
{
|
|
||||||
GtkEntry *gtkentry;
|
|
||||||
SexyIconEntry *entry;
|
|
||||||
gint icon_widths = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
gtkentry = GTK_ENTRY(widget);
|
|
||||||
entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS; i++)
|
|
||||||
{
|
|
||||||
int icon_width = get_icon_width(entry, i);
|
|
||||||
|
|
||||||
if (icon_width > 0)
|
|
||||||
icon_widths += icon_width + ICON_MARGIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
GTK_WIDGET_CLASS(parent_class)->size_request(widget, requisition);
|
|
||||||
|
|
||||||
if (icon_widths > requisition->width)
|
|
||||||
requisition->width += icon_widths;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
place_windows(SexyIconEntry *icon_entry, GtkAllocation *widget_alloc)
|
|
||||||
{
|
|
||||||
SexyIconEntryPosition left_icon_pos;
|
|
||||||
SexyIconEntryPosition right_icon_pos;
|
|
||||||
GtkAllocation left_icon_alloc;
|
|
||||||
GtkAllocation right_icon_alloc;
|
|
||||||
GtkAllocation text_area_alloc;
|
|
||||||
|
|
||||||
get_text_area_size(icon_entry, &text_area_alloc);
|
|
||||||
get_icon_allocation(icon_entry, TRUE, widget_alloc, &text_area_alloc,
|
|
||||||
&left_icon_alloc, &left_icon_pos);
|
|
||||||
get_icon_allocation(icon_entry, FALSE, widget_alloc, &text_area_alloc,
|
|
||||||
&right_icon_alloc, &right_icon_pos);
|
|
||||||
|
|
||||||
if (left_icon_alloc.width > 0)
|
|
||||||
{
|
|
||||||
text_area_alloc.x = left_icon_alloc.x + left_icon_alloc.width +
|
|
||||||
ICON_MARGIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (right_icon_alloc.width > 0)
|
|
||||||
text_area_alloc.width -= right_icon_alloc.width + ICON_MARGIN;
|
|
||||||
|
|
||||||
text_area_alloc.width -= text_area_alloc.x;
|
|
||||||
|
|
||||||
gdk_window_move_resize(icon_entry->priv->icons[left_icon_pos].window,
|
|
||||||
left_icon_alloc.x, left_icon_alloc.y,
|
|
||||||
left_icon_alloc.width, left_icon_alloc.height);
|
|
||||||
|
|
||||||
gdk_window_move_resize(icon_entry->priv->icons[right_icon_pos].window,
|
|
||||||
right_icon_alloc.x, right_icon_alloc.y,
|
|
||||||
right_icon_alloc.width, right_icon_alloc.height);
|
|
||||||
|
|
||||||
gdk_window_move_resize(GTK_ENTRY(icon_entry)->text_area,
|
|
||||||
text_area_alloc.x, text_area_alloc.y,
|
|
||||||
text_area_alloc.width, text_area_alloc.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sexy_icon_entry_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
|
|
||||||
{
|
|
||||||
g_return_if_fail(SEXY_IS_ICON_ENTRY(widget));
|
|
||||||
g_return_if_fail(allocation != NULL);
|
|
||||||
|
|
||||||
widget->allocation = *allocation;
|
|
||||||
|
|
||||||
GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation);
|
|
||||||
|
|
||||||
if (GTK_WIDGET_REALIZED(widget))
|
|
||||||
place_windows(SEXY_ICON_ENTRY(widget), allocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GdkPixbuf *
|
|
||||||
get_pixbuf_from_icon(SexyIconEntry *entry, SexyIconEntryPosition icon_pos)
|
|
||||||
{
|
|
||||||
GdkPixbuf *pixbuf = NULL;
|
|
||||||
gchar *stock_id;
|
|
||||||
SexyIconInfo *icon_info = &entry->priv->icons[icon_pos];
|
|
||||||
GtkIconSize size;
|
|
||||||
|
|
||||||
switch (gtk_image_get_storage_type(GTK_IMAGE(icon_info->icon)))
|
|
||||||
{
|
|
||||||
case GTK_IMAGE_PIXBUF:
|
|
||||||
pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(icon_info->icon));
|
|
||||||
g_object_ref(pixbuf);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GTK_IMAGE_STOCK:
|
|
||||||
gtk_image_get_stock(GTK_IMAGE(icon_info->icon), &stock_id, &size);
|
|
||||||
pixbuf = gtk_widget_render_icon(GTK_WIDGET(entry),
|
|
||||||
stock_id, size, NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pixbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Kudos to the gnome-panel guys. */
|
|
||||||
static void
|
|
||||||
colorshift_pixbuf(GdkPixbuf *dest, GdkPixbuf *src, int shift)
|
|
||||||
{
|
|
||||||
gint i, j;
|
|
||||||
gint width, height, has_alpha, src_rowstride, dest_rowstride;
|
|
||||||
guchar *target_pixels;
|
|
||||||
guchar *original_pixels;
|
|
||||||
guchar *pix_src;
|
|
||||||
guchar *pix_dest;
|
|
||||||
int val;
|
|
||||||
guchar r, g, b;
|
|
||||||
|
|
||||||
has_alpha = gdk_pixbuf_get_has_alpha(src);
|
|
||||||
width = gdk_pixbuf_get_width(src);
|
|
||||||
height = gdk_pixbuf_get_height(src);
|
|
||||||
src_rowstride = gdk_pixbuf_get_rowstride(src);
|
|
||||||
dest_rowstride = gdk_pixbuf_get_rowstride(dest);
|
|
||||||
original_pixels = gdk_pixbuf_get_pixels(src);
|
|
||||||
target_pixels = gdk_pixbuf_get_pixels(dest);
|
|
||||||
|
|
||||||
for (i = 0; i < height; i++)
|
|
||||||
{
|
|
||||||
pix_dest = target_pixels + i * dest_rowstride;
|
|
||||||
pix_src = original_pixels + i * src_rowstride;
|
|
||||||
|
|
||||||
for (j = 0; j < width; j++)
|
|
||||||
{
|
|
||||||
r = *(pix_src++);
|
|
||||||
g = *(pix_src++);
|
|
||||||
b = *(pix_src++);
|
|
||||||
|
|
||||||
val = r + shift;
|
|
||||||
*(pix_dest++) = CLAMP(val, 0, 255);
|
|
||||||
|
|
||||||
val = g + shift;
|
|
||||||
*(pix_dest++) = CLAMP(val, 0, 255);
|
|
||||||
|
|
||||||
val = b + shift;
|
|
||||||
*(pix_dest++) = CLAMP(val, 0, 255);
|
|
||||||
|
|
||||||
if (has_alpha)
|
|
||||||
*(pix_dest++) = *(pix_src++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
draw_icon(GtkWidget *widget, SexyIconEntryPosition icon_pos)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
SexyIconInfo *icon_info = &entry->priv->icons[icon_pos];
|
|
||||||
GdkPixbuf *pixbuf;
|
|
||||||
gint x, y, width, height;
|
|
||||||
|
|
||||||
if (icon_info->icon == NULL || !GTK_WIDGET_REALIZED(widget))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((pixbuf = get_pixbuf_from_icon(entry, icon_pos)) == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gdk_drawable_get_size(icon_info->window, &width, &height);
|
|
||||||
|
|
||||||
if (width == 1 || height == 1)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* size_allocate hasn't been called yet. These are the default values.
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gdk_pixbuf_get_height(pixbuf) > height)
|
|
||||||
{
|
|
||||||
GdkPixbuf *temp_pixbuf;
|
|
||||||
int scale;
|
|
||||||
|
|
||||||
scale = height - (2 * ICON_MARGIN);
|
|
||||||
|
|
||||||
temp_pixbuf = gdk_pixbuf_scale_simple(pixbuf, scale, scale,
|
|
||||||
GDK_INTERP_BILINEAR);
|
|
||||||
|
|
||||||
g_object_unref(pixbuf);
|
|
||||||
|
|
||||||
pixbuf = temp_pixbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = (width - gdk_pixbuf_get_width(pixbuf)) / 2;
|
|
||||||
y = (height - gdk_pixbuf_get_height(pixbuf)) / 2;
|
|
||||||
|
|
||||||
if (icon_info->hovered)
|
|
||||||
{
|
|
||||||
GdkPixbuf *temp_pixbuf;
|
|
||||||
|
|
||||||
temp_pixbuf = gdk_pixbuf_copy(pixbuf);
|
|
||||||
|
|
||||||
colorshift_pixbuf(temp_pixbuf, pixbuf, 30);
|
|
||||||
|
|
||||||
g_object_unref(pixbuf);
|
|
||||||
|
|
||||||
pixbuf = temp_pixbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
gdk_draw_pixbuf(icon_info->window, widget->style->black_gc, pixbuf,
|
|
||||||
0, 0, x, y, -1, -1,
|
|
||||||
GDK_RGB_DITHER_NORMAL, 0, 0);
|
|
||||||
|
|
||||||
g_object_unref(pixbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
sexy_icon_entry_expose(GtkWidget *widget, GdkEventExpose *event)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry;
|
|
||||||
|
|
||||||
g_return_val_if_fail(SEXY_IS_ICON_ENTRY(widget), FALSE);
|
|
||||||
g_return_val_if_fail(event != NULL, FALSE);
|
|
||||||
|
|
||||||
entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
|
|
||||||
if (GTK_WIDGET_DRAWABLE(widget))
|
|
||||||
{
|
|
||||||
gboolean found = FALSE;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS && !found; i++)
|
|
||||||
{
|
|
||||||
SexyIconInfo *icon_info = &entry->priv->icons[i];
|
|
||||||
|
|
||||||
if (event->window == icon_info->window)
|
|
||||||
{
|
|
||||||
gint width;
|
|
||||||
GtkAllocation text_area_alloc;
|
|
||||||
|
|
||||||
get_text_area_size(entry, &text_area_alloc);
|
|
||||||
gdk_drawable_get_size(icon_info->window, &width, NULL);
|
|
||||||
|
|
||||||
gtk_paint_flat_box(widget->style, icon_info->window,
|
|
||||||
GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
|
|
||||||
NULL, widget, "entry_bg",
|
|
||||||
0, 0, width, text_area_alloc.height);
|
|
||||||
|
|
||||||
draw_icon(widget, i);
|
|
||||||
|
|
||||||
found = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
update_icon(GObject *obj, GParamSpec *param, SexyIconEntry *entry)
|
|
||||||
{
|
|
||||||
if (param != NULL)
|
|
||||||
{
|
|
||||||
const char *name = g_param_spec_get_name(param);
|
|
||||||
|
|
||||||
if (strcmp(name, "pixbuf") && strcmp(name, "stock") &&
|
|
||||||
strcmp(name, "image") && strcmp(name, "pixmap") &&
|
|
||||||
strcmp(name, "icon_set") && strcmp(name, "pixbuf_animation"))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_widget_queue_resize(GTK_WIDGET(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
sexy_icon_entry_enter_notify(GtkWidget *widget, GdkEventCrossing *event)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS; i++)
|
|
||||||
{
|
|
||||||
if (event->window == entry->priv->icons[i].window)
|
|
||||||
{
|
|
||||||
if (sexy_icon_entry_get_icon_highlight(entry, i))
|
|
||||||
{
|
|
||||||
entry->priv->icons[i].hovered = TRUE;
|
|
||||||
|
|
||||||
update_icon(NULL, NULL, entry);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
sexy_icon_entry_leave_notify(GtkWidget *widget, GdkEventCrossing *event)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS; i++)
|
|
||||||
{
|
|
||||||
if (event->window == entry->priv->icons[i].window)
|
|
||||||
{
|
|
||||||
if (sexy_icon_entry_get_icon_highlight(entry, i))
|
|
||||||
{
|
|
||||||
entry->priv->icons[i].hovered = FALSE;
|
|
||||||
|
|
||||||
update_icon(NULL, NULL, entry);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
sexy_icon_entry_button_press(GtkWidget *widget, GdkEventButton *event)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS; i++)
|
|
||||||
{
|
|
||||||
if (event->window == entry->priv->icons[i].window)
|
|
||||||
{
|
|
||||||
if (event->button == 1 &&
|
|
||||||
sexy_icon_entry_get_icon_highlight(entry, i))
|
|
||||||
{
|
|
||||||
entry->priv->icons[i].hovered = FALSE;
|
|
||||||
|
|
||||||
update_icon(NULL, NULL, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_signal_emit(entry, signals[ICON_PRESSED], 0, i, event->button);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GTK_WIDGET_CLASS(parent_class)->button_press_event)
|
|
||||||
return GTK_WIDGET_CLASS(parent_class)->button_press_event(widget,
|
|
||||||
event);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
sexy_icon_entry_button_release(GtkWidget *widget, GdkEventButton *event)
|
|
||||||
{
|
|
||||||
SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ICONS; i++)
|
|
||||||
{
|
|
||||||
GdkWindow *icon_window = entry->priv->icons[i].window;
|
|
||||||
|
|
||||||
if (event->window == icon_window)
|
|
||||||
{
|
|
||||||
int width, height;
|
|
||||||
gdk_drawable_get_size(icon_window, &width, &height);
|
|
||||||
|
|
||||||
if (event->button == 1 &&
|
|
||||||
sexy_icon_entry_get_icon_highlight(entry, i) &&
|
|
||||||
event->x >= 0 && event->y >= 0 &&
|
|
||||||
event->x <= width && event->y <= height)
|
|
||||||
{
|
|
||||||
entry->priv->icons[i].hovered = TRUE;
|
|
||||||
|
|
||||||
update_icon(NULL, NULL, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_signal_emit(entry, signals[ICON_RELEASED], 0, i, event->button);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GTK_WIDGET_CLASS(parent_class)->button_release_event)
|
|
||||||
return GTK_WIDGET_CLASS(parent_class)->button_release_event(widget,
|
|
||||||
event);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sexy_icon_entry_new
|
|
||||||
*
|
|
||||||
* Creates a new SexyIconEntry widget.
|
|
||||||
*
|
|
||||||
* Returns a new #SexyIconEntry.
|
|
||||||
*/
|
|
||||||
GtkWidget *
|
|
||||||
sexy_icon_entry_new(void)
|
|
||||||
{
|
|
||||||
return GTK_WIDGET(g_object_new(SEXY_TYPE_ICON_ENTRY, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sexy_icon_entry_set_icon
|
|
||||||
* @entry: A #SexyIconEntry.
|
|
||||||
* @position: Icon position.
|
|
||||||
* @icon: A #GtkImage to set as the icon.
|
|
||||||
*
|
|
||||||
* Sets the icon shown in the entry
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
sexy_icon_entry_set_icon(SexyIconEntry *entry, SexyIconEntryPosition icon_pos,
|
|
||||||
GtkImage *icon)
|
|
||||||
{
|
|
||||||
SexyIconInfo *icon_info;
|
|
||||||
|
|
||||||
g_return_if_fail(entry != NULL);
|
|
||||||
g_return_if_fail(SEXY_IS_ICON_ENTRY(entry));
|
|
||||||
g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos));
|
|
||||||
g_return_if_fail(icon == NULL || GTK_IS_IMAGE(icon));
|
|
||||||
|
|
||||||
icon_info = &entry->priv->icons[icon_pos];
|
|
||||||
|
|
||||||
if (icon == icon_info->icon)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (icon_pos == SEXY_ICON_ENTRY_SECONDARY &&
|
|
||||||
entry->priv->icon_released_id != 0)
|
|
||||||
{
|
|
||||||
g_signal_handler_disconnect(entry, entry->priv->icon_released_id);
|
|
||||||
entry->priv->icon_released_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (icon == NULL)
|
|
||||||
{
|
|
||||||
if (icon_info->icon != NULL)
|
|
||||||
{
|
|
||||||
gtk_widget_destroy(GTK_WIDGET(icon_info->icon));
|
|
||||||
icon_info->icon = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Explicitly check, as the pointer may become invalidated
|
|
||||||
* during destruction.
|
|
||||||
*/
|
|
||||||
if (icon_info->window != NULL && GDK_IS_WINDOW(icon_info->window))
|
|
||||||
gdk_window_hide(icon_info->window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (icon_info->window != NULL && icon_info->icon == NULL)
|
|
||||||
gdk_window_show(icon_info->window);
|
|
||||||
|
|
||||||
g_signal_connect(G_OBJECT(icon), "notify",
|
|
||||||
G_CALLBACK(update_icon), entry);
|
|
||||||
|
|
||||||
icon_info->icon = icon;
|
|
||||||
g_object_ref(icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
update_icon(NULL, NULL, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sexy_icon_entry_set_icon_highlight
|
|
||||||
* @entry: A #SexyIconEntry;
|
|
||||||
* @position: Icon position.
|
|
||||||
* @highlight: TRUE if the icon should highlight on mouse-over
|
|
||||||
*
|
|
||||||
* Determines whether the icon will highlight on mouse-over.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
sexy_icon_entry_set_icon_highlight(SexyIconEntry *entry,
|
|
||||||
SexyIconEntryPosition icon_pos,
|
|
||||||
gboolean highlight)
|
|
||||||
{
|
|
||||||
SexyIconInfo *icon_info;
|
|
||||||
|
|
||||||
g_return_if_fail(entry != NULL);
|
|
||||||
g_return_if_fail(SEXY_IS_ICON_ENTRY(entry));
|
|
||||||
g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos));
|
|
||||||
|
|
||||||
icon_info = &entry->priv->icons[icon_pos];
|
|
||||||
|
|
||||||
if (icon_info->highlight == highlight)
|
|
||||||
return;
|
|
||||||
|
|
||||||
icon_info->highlight = highlight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sexy_icon_entry_get_icon
|
|
||||||
* @entry: A #SexyIconEntry.
|
|
||||||
* @position: Icon position.
|
|
||||||
*
|
|
||||||
* Retrieves the image used for the icon
|
|
||||||
*
|
|
||||||
* Returns: A #GtkImage.
|
|
||||||
*/
|
|
||||||
GtkImage *
|
|
||||||
sexy_icon_entry_get_icon(const SexyIconEntry *entry,
|
|
||||||
SexyIconEntryPosition icon_pos)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(entry != NULL, NULL);
|
|
||||||
g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry), NULL);
|
|
||||||
g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos), NULL);
|
|
||||||
|
|
||||||
return entry->priv->icons[icon_pos].icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sexy_icon_entry_get_icon_highlight
|
|
||||||
* @entry: A #SexyIconEntry.
|
|
||||||
* @position: Icon position.
|
|
||||||
*
|
|
||||||
* Retrieves whether entry will highlight the icon on mouseover.
|
|
||||||
*
|
|
||||||
* Returns: TRUE if icon highlights.
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
sexy_icon_entry_get_icon_highlight(const SexyIconEntry *entry,
|
|
||||||
SexyIconEntryPosition icon_pos)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(entry != NULL, FALSE);
|
|
||||||
g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry), FALSE);
|
|
||||||
g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos), FALSE);
|
|
||||||
|
|
||||||
return entry->priv->icons[icon_pos].highlight;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
clear_button_clicked_cb(SexyIconEntry *icon_entry,
|
|
||||||
SexyIconEntryPosition icon_pos,
|
|
||||||
int button)
|
|
||||||
{
|
|
||||||
if (icon_pos != SEXY_ICON_ENTRY_SECONDARY || button != 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gtk_entry_set_text(GTK_ENTRY(icon_entry), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sexy_icon_entry_add_clear_button
|
|
||||||
* @icon_entry: A #SexyIconEntry.
|
|
||||||
*
|
|
||||||
* A convenience function to add a clear button to the end of the entry.
|
|
||||||
* This is useful for search boxes.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
sexy_icon_entry_add_clear_button(SexyIconEntry *icon_entry)
|
|
||||||
{
|
|
||||||
GtkWidget *icon;
|
|
||||||
|
|
||||||
g_return_if_fail(icon_entry != NULL);
|
|
||||||
g_return_if_fail(SEXY_IS_ICON_ENTRY(icon_entry));
|
|
||||||
|
|
||||||
icon = gtk_image_new_from_stock(GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU);
|
|
||||||
gtk_widget_show(icon);
|
|
||||||
sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(icon_entry),
|
|
||||||
SEXY_ICON_ENTRY_SECONDARY,
|
|
||||||
GTK_IMAGE(icon));
|
|
||||||
sexy_icon_entry_set_icon_highlight(SEXY_ICON_ENTRY(icon_entry),
|
|
||||||
SEXY_ICON_ENTRY_SECONDARY, TRUE);
|
|
||||||
|
|
||||||
if (icon_entry->priv->icon_released_id != 0)
|
|
||||||
{
|
|
||||||
g_signal_handler_disconnect(icon_entry,
|
|
||||||
icon_entry->priv->icon_released_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
icon_entry->priv->icon_released_id =
|
|
||||||
g_signal_connect(G_OBJECT(icon_entry), "icon_released",
|
|
||||||
G_CALLBACK(clear_button_clicked_cb), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
GType
|
|
||||||
sexy_icon_entry_position_get_type (void)
|
|
||||||
{
|
|
||||||
static GType etype = 0;
|
|
||||||
if (etype == 0) {
|
|
||||||
static const GEnumValue values[] = {
|
|
||||||
{ SEXY_ICON_ENTRY_PRIMARY, "SEXY_ICON_ENTRY_PRIMARY", "primary" },
|
|
||||||
{ SEXY_ICON_ENTRY_SECONDARY, "SEXY_ICON_ENTRY_SECONDARY", "secondary" },
|
|
||||||
{ 0, NULL, NULL }
|
|
||||||
};
|
|
||||||
etype = g_enum_register_static ("SexyIconEntryPosition", values);
|
|
||||||
}
|
|
||||||
return etype;
|
|
||||||
}
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* @file libsexy/sexy-icon-entry.h Entry widget
|
|
||||||
*
|
|
||||||
* @Copyright (C) 2004-2006 Christian Hammond.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser 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 _SEXY_ICON_ENTRY_H_
|
|
||||||
#define _SEXY_ICON_ENTRY_H_
|
|
||||||
|
|
||||||
typedef struct _SexyIconEntry SexyIconEntry;
|
|
||||||
typedef struct _SexyIconEntryClass SexyIconEntryClass;
|
|
||||||
typedef struct _SexyIconEntryPriv SexyIconEntryPriv;
|
|
||||||
|
|
||||||
#include <gtk/gtkentry.h>
|
|
||||||
#include <gtk/gtkimage.h>
|
|
||||||
|
|
||||||
#define SEXY_TYPE_ICON_ENTRY (sexy_icon_entry_get_type())
|
|
||||||
#define SEXY_ICON_ENTRY(obj) \
|
|
||||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), SEXY_TYPE_ICON_ENTRY, SexyIconEntry))
|
|
||||||
#define SEXY_ICON_ENTRY_CLASS(klass) \
|
|
||||||
(G_TYPE_CHECK_CLASS_CAST((klass), SEXY_TYPE_ICON_ENTRY, SexyIconEntryClass))
|
|
||||||
#define SEXY_IS_ICON_ENTRY(obj) \
|
|
||||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj), SEXY_TYPE_ICON_ENTRY))
|
|
||||||
#define SEXY_IS_ICON_ENTRY_CLASS(klass) \
|
|
||||||
(G_TYPE_CHECK_CLASS_TYPE((klass), SEXY_TYPE_ICON_ENTRY))
|
|
||||||
#define SEXY_ICON_ENTRY_GET_CLASS(obj) \
|
|
||||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), SEXY_TYPE_ICON_ENTRY, SexyIconEntryClass))
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
SEXY_ICON_ENTRY_PRIMARY,
|
|
||||||
SEXY_ICON_ENTRY_SECONDARY
|
|
||||||
|
|
||||||
} SexyIconEntryPosition;
|
|
||||||
|
|
||||||
GType sexy_icon_entry_position_get_type(void);
|
|
||||||
#define SEXY_TYPE_ICON_ENTRY_POSITION (sexy_icon_entry_position_get_type())
|
|
||||||
|
|
||||||
struct _SexyIconEntry
|
|
||||||
{
|
|
||||||
GtkEntry parent_object;
|
|
||||||
|
|
||||||
SexyIconEntryPriv *priv;
|
|
||||||
|
|
||||||
void (*gtk_reserved1)(void);
|
|
||||||
void (*gtk_reserved2)(void);
|
|
||||||
void (*gtk_reserved3)(void);
|
|
||||||
void (*gtk_reserved4)(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _SexyIconEntryClass
|
|
||||||
{
|
|
||||||
GtkEntryClass parent_class;
|
|
||||||
|
|
||||||
/* Signals */
|
|
||||||
void (*icon_pressed)(SexyIconEntry *entry, SexyIconEntryPosition icon_pos,
|
|
||||||
int button);
|
|
||||||
void (*icon_released)(SexyIconEntry *entry, SexyIconEntryPosition icon_pos,
|
|
||||||
int button);
|
|
||||||
|
|
||||||
void (*gtk_reserved1)(void);
|
|
||||||
void (*gtk_reserved2)(void);
|
|
||||||
void (*gtk_reserved3)(void);
|
|
||||||
void (*gtk_reserved4)(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
GType sexy_icon_entry_get_type(void);
|
|
||||||
|
|
||||||
GtkWidget *sexy_icon_entry_new(void);
|
|
||||||
|
|
||||||
void sexy_icon_entry_set_icon(SexyIconEntry *entry,
|
|
||||||
SexyIconEntryPosition position,
|
|
||||||
GtkImage *icon);
|
|
||||||
|
|
||||||
void sexy_icon_entry_set_icon_highlight(SexyIconEntry *entry,
|
|
||||||
SexyIconEntryPosition position,
|
|
||||||
gboolean highlight);
|
|
||||||
|
|
||||||
GtkImage *sexy_icon_entry_get_icon(const SexyIconEntry *entry,
|
|
||||||
SexyIconEntryPosition position);
|
|
||||||
|
|
||||||
gboolean sexy_icon_entry_get_icon_highlight(const SexyIconEntry *entry,
|
|
||||||
SexyIconEntryPosition position);
|
|
||||||
void sexy_icon_entry_add_clear_button(SexyIconEntry *icon_entry);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* _SEXY_ICON_ENTRY_H_ */
|
|
@ -1,576 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#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;
|
|
||||||
gtk_border_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
|
|
||||||
sugar_address_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);
|
|
||||||
|
|
||||||
sugar_address_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 &&
|
|
||||||
!GTK_WIDGET_HAS_FOCUS(entry)) {
|
|
||||||
int bar_width = area_width * address_entry->progress;
|
|
||||||
float radius = area_height / 2;
|
|
||||||
|
|
||||||
cr = gdk_cairo_create(entry->text_area);
|
|
||||||
cairo_set_source_rgb(cr, 0xA6 / 255.0, 0xA6 / 255.0, 0xA6 / 255.0);
|
|
||||||
|
|
||||||
cairo_move_to (cr, radius, 0);
|
|
||||||
cairo_arc (cr, bar_width - radius, radius, radius, M_PI * 1.5, M_PI * 2);
|
|
||||||
cairo_arc (cr, bar_width - radius, area_height - radius, radius, 0, M_PI * 0.5);
|
|
||||||
cairo_arc (cr, radius, area_height - radius, radius, M_PI * 0.5, M_PI);
|
|
||||||
cairo_arc (cr, radius, radius, radius, M_PI, M_PI * 1.5);
|
|
||||||
|
|
||||||
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 *address_entry = SUGAR_ADDRESS_ENTRY(object);
|
|
||||||
GtkEntry *entry = GTK_ENTRY(object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_PROGRESS:
|
|
||||||
address_entry->progress = g_value_get_double(value);
|
|
||||||
if (GTK_WIDGET_REALIZED(entry))
|
|
||||||
gdk_window_invalidate_rect(entry->text_area, NULL, FALSE);
|
|
||||||
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 gboolean
|
|
||||||
button_press_event_cb (GtkWidget *widget, GdkEventButton *event)
|
|
||||||
{
|
|
||||||
if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
|
|
||||||
gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
|
|
||||||
gtk_widget_grab_focus(widget);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sugar_address_entry_init(SugarAddressEntry *entry)
|
|
||||||
{
|
|
||||||
entry->progress = 0.0;
|
|
||||||
|
|
||||||
g_signal_connect(entry, "button-press-event",
|
|
||||||
G_CALLBACK(button_press_event_cb), NULL);
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser 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 __SUGAR_ADDRESS_ENTRY_H__
|
|
||||||
#define __SUGAR_ADDRESS_ENTRY_H__
|
|
||||||
|
|
||||||
#include <gtk/gtkentry.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;
|
|
||||||
char *title;
|
|
||||||
char *address;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _SugarAddressEntryClass {
|
|
||||||
GtkEntryClass base_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
GType sugar_address_entry_get_type (void);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __SUGAR_ADDRESS_ENTRY_H__ */
|
|
Loading…
Reference in New Issue
Block a user