1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 * @file libsexy/sexy-icon-entry.c Entry widget
5 * @Copyright (C) 2004-2006 Christian Hammond.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
22 #include <sexy-icon-entry.h>
26 #include "anjuta-marshal.h"
31 #define IS_VALID_ICON_ENTRY_POSITION(pos) \
32 ((pos) == SEXY_ICON_ENTRY_PRIMARY || \
33 (pos) == SEXY_ICON_ENTRY_SECONDARY)
44 struct _SexyIconEntryPriv
46 SexyIconInfo icons
[MAX_ICONS
];
48 gulong icon_released_id
;
58 static void sexy_icon_entry_class_init(SexyIconEntryClass
*klass
);
59 static void sexy_icon_entry_editable_init(GtkEditableClass
*iface
);
60 static void sexy_icon_entry_init(SexyIconEntry
*entry
);
61 static void sexy_icon_entry_finalize(GObject
*obj
);
62 static void sexy_icon_entry_destroy(GtkObject
*obj
);
63 static void sexy_icon_entry_map(GtkWidget
*widget
);
64 static void sexy_icon_entry_unmap(GtkWidget
*widget
);
65 static void sexy_icon_entry_realize(GtkWidget
*widget
);
66 static void sexy_icon_entry_unrealize(GtkWidget
*widget
);
67 static void sexy_icon_entry_size_request(GtkWidget
*widget
,
68 GtkRequisition
*requisition
);
69 static void sexy_icon_entry_size_allocate(GtkWidget
*widget
,
70 GtkAllocation
*allocation
);
71 static gint
sexy_icon_entry_expose(GtkWidget
*widget
, GdkEventExpose
*event
);
72 static gint
sexy_icon_entry_enter_notify(GtkWidget
*widget
,
73 GdkEventCrossing
*event
);
74 static gint
sexy_icon_entry_leave_notify(GtkWidget
*widget
,
75 GdkEventCrossing
*event
);
76 static gint
sexy_icon_entry_button_press(GtkWidget
*widget
,
77 GdkEventButton
*event
);
78 static gint
sexy_icon_entry_button_release(GtkWidget
*widget
,
79 GdkEventButton
*event
);
81 static GtkEntryClass
*parent_class
= NULL
;
82 static guint signals
[LAST_SIGNAL
] = {0};
84 G_DEFINE_TYPE_EXTENDED(SexyIconEntry
, sexy_icon_entry
, GTK_TYPE_ENTRY
,
86 G_IMPLEMENT_INTERFACE(GTK_TYPE_EDITABLE
,
87 sexy_icon_entry_editable_init
));
90 sexy_icon_entry_class_init(SexyIconEntryClass
*klass
)
92 GObjectClass
*gobject_class
;
93 GtkObjectClass
*object_class
;
94 GtkWidgetClass
*widget_class
;
95 GtkEntryClass
*entry_class
;
97 parent_class
= g_type_class_peek_parent(klass
);
99 gobject_class
= G_OBJECT_CLASS(klass
);
100 object_class
= GTK_OBJECT_CLASS(klass
);
101 widget_class
= GTK_WIDGET_CLASS(klass
);
102 entry_class
= GTK_ENTRY_CLASS(klass
);
104 gobject_class
->finalize
= sexy_icon_entry_finalize
;
106 object_class
->destroy
= sexy_icon_entry_destroy
;
108 widget_class
->map
= sexy_icon_entry_map
;
109 widget_class
->unmap
= sexy_icon_entry_unmap
;
110 widget_class
->realize
= sexy_icon_entry_realize
;
111 widget_class
->unrealize
= sexy_icon_entry_unrealize
;
112 widget_class
->size_request
= sexy_icon_entry_size_request
;
113 widget_class
->size_allocate
= sexy_icon_entry_size_allocate
;
114 widget_class
->expose_event
= sexy_icon_entry_expose
;
115 widget_class
->enter_notify_event
= sexy_icon_entry_enter_notify
;
116 widget_class
->leave_notify_event
= sexy_icon_entry_leave_notify
;
117 widget_class
->button_press_event
= sexy_icon_entry_button_press
;
118 widget_class
->button_release_event
= sexy_icon_entry_button_release
;
121 * SexyIconEntry::icon-pressed:
122 * @entry: The entry on which the signal is emitted.
123 * @icon_pos: The position of the clicked icon.
124 * @button: The mouse button clicked.
126 * The ::icon-pressed signal is emitted when an icon is clicked.
128 signals
[ICON_PRESSED
] =
129 g_signal_new("icon_pressed",
130 G_TYPE_FROM_CLASS(gobject_class
),
131 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
132 G_STRUCT_OFFSET(SexyIconEntryClass
, icon_pressed
),
134 anjuta_marshal_VOID__INT_INT
,
140 * SexyIconEntry::icon-released:
141 * @entry: The entry on which the signal is emitted.
142 * @icon_pos: The position of the clicked icon.
143 * @button: The mouse button clicked.
145 * The ::icon-released signal is emitted on the button release from a
148 signals
[ICON_RELEASED
] =
149 g_signal_new("icon_released",
150 G_TYPE_FROM_CLASS(gobject_class
),
151 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
152 G_STRUCT_OFFSET(SexyIconEntryClass
, icon_released
),
154 anjuta_marshal_VOID__INT_INT
,
161 sexy_icon_entry_editable_init(GtkEditableClass
*iface
)
166 sexy_icon_entry_init(SexyIconEntry
*entry
)
168 entry
->priv
= g_new0(SexyIconEntryPriv
, 1);
172 sexy_icon_entry_finalize(GObject
*obj
)
174 SexyIconEntry
*entry
;
176 g_return_if_fail(obj
!= NULL
);
177 g_return_if_fail(SEXY_IS_ICON_ENTRY(obj
));
179 entry
= SEXY_ICON_ENTRY(obj
);
183 if (G_OBJECT_CLASS(parent_class
)->finalize
)
184 G_OBJECT_CLASS(parent_class
)->finalize(obj
);
188 sexy_icon_entry_destroy(GtkObject
*obj
)
190 SexyIconEntry
*entry
;
192 entry
= SEXY_ICON_ENTRY(obj
);
194 sexy_icon_entry_set_icon(entry
, SEXY_ICON_ENTRY_PRIMARY
, NULL
);
195 sexy_icon_entry_set_icon(entry
, SEXY_ICON_ENTRY_SECONDARY
, NULL
);
197 if (GTK_OBJECT_CLASS(parent_class
)->destroy
)
198 GTK_OBJECT_CLASS(parent_class
)->destroy(obj
);
202 sexy_icon_entry_map(GtkWidget
*widget
)
204 if (GTK_WIDGET_REALIZED(widget
) && !GTK_WIDGET_MAPPED(widget
))
206 SexyIconEntry
*entry
= SEXY_ICON_ENTRY(widget
);
209 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
211 for (i
= 0; i
< MAX_ICONS
; i
++)
213 if (entry
->priv
->icons
[i
].icon
!= NULL
)
214 gdk_window_show(entry
->priv
->icons
[i
].window
);
220 sexy_icon_entry_unmap(GtkWidget
*widget
)
222 if (GTK_WIDGET_MAPPED(widget
))
224 SexyIconEntry
*entry
= SEXY_ICON_ENTRY(widget
);
227 for (i
= 0; i
< MAX_ICONS
; i
++)
229 if (entry
->priv
->icons
[i
].icon
!= NULL
)
230 gdk_window_hide(entry
->priv
->icons
[i
].window
);
233 GTK_WIDGET_CLASS(parent_class
)->unmap(widget
);
238 get_icon_width(SexyIconEntry
*entry
, SexyIconEntryPosition icon_pos
)
240 GtkRequisition requisition
;
241 gint menu_icon_width
;
243 SexyIconInfo
*icon_info
= &entry
->priv
->icons
[icon_pos
];
245 if (icon_info
->icon
== NULL
)
248 gtk_widget_size_request(GTK_WIDGET(icon_info
->icon
), &requisition
);
249 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU
, &menu_icon_width
, NULL
);
251 width
= MAX(requisition
.width
, menu_icon_width
);
257 get_borders(SexyIconEntry
*entry
, gint
*xborder
, gint
*yborder
)
259 GtkWidget
*widget
= GTK_WIDGET(entry
);
261 gboolean interior_focus
;
263 gtk_widget_style_get(widget
,
264 "interior-focus", &interior_focus
,
265 "focus-line-width", &focus_width
,
268 if (gtk_entry_get_has_frame(GTK_ENTRY(entry
)))
270 *xborder
= widget
->style
->xthickness
;
271 *yborder
= widget
->style
->ythickness
;
281 *xborder
+= focus_width
;
282 *yborder
+= focus_width
;
287 get_text_area_size(SexyIconEntry
*entry
, GtkAllocation
*alloc
)
289 GtkWidget
*widget
= GTK_WIDGET(entry
);
290 GtkRequisition requisition
;
291 gint xborder
, yborder
;
293 gtk_widget_get_child_requisition(widget
, &requisition
);
294 get_borders(entry
, &xborder
, &yborder
);
298 alloc
->width
= widget
->allocation
.width
- xborder
* 2;
299 alloc
->height
= requisition
.height
- yborder
* 2;
303 get_icon_allocation(SexyIconEntry
*icon_entry
,
305 GtkAllocation
*widget_alloc
,
306 GtkAllocation
*text_area_alloc
,
307 GtkAllocation
*allocation
,
308 SexyIconEntryPosition
*icon_pos
)
312 rtl
= (gtk_widget_get_direction(GTK_WIDGET(icon_entry
)) ==
316 *icon_pos
= (rtl
? SEXY_ICON_ENTRY_SECONDARY
: SEXY_ICON_ENTRY_PRIMARY
);
318 *icon_pos
= (rtl
? SEXY_ICON_ENTRY_PRIMARY
: SEXY_ICON_ENTRY_SECONDARY
);
320 allocation
->y
= text_area_alloc
->y
;
321 allocation
->width
= get_icon_width(icon_entry
, *icon_pos
);
322 allocation
->height
= text_area_alloc
->height
;
325 allocation
->x
= text_area_alloc
->x
+ ICON_MARGIN
;
328 allocation
->x
= text_area_alloc
->x
+ text_area_alloc
->width
-
329 allocation
->width
- ICON_MARGIN
;
334 sexy_icon_entry_realize(GtkWidget
*widget
)
336 SexyIconEntry
*entry
= SEXY_ICON_ENTRY(widget
);
337 GdkWindowAttr attributes
;
338 gint attributes_mask
;
341 GTK_WIDGET_CLASS(parent_class
)->realize(widget
);
345 attributes
.width
= 1;
346 attributes
.height
= 1;
347 attributes
.window_type
= GDK_WINDOW_CHILD
;
348 attributes
.wclass
= GDK_INPUT_OUTPUT
;
349 attributes
.visual
= gtk_widget_get_visual(widget
);
350 attributes
.colormap
= gtk_widget_get_colormap(widget
);
351 attributes
.event_mask
= gtk_widget_get_events(widget
);
352 attributes
.event_mask
|=
354 | GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
355 | GDK_ENTER_NOTIFY_MASK
| GDK_LEAVE_NOTIFY_MASK
);
357 attributes_mask
= GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
;
359 for (i
= 0; i
< MAX_ICONS
; i
++)
361 SexyIconInfo
*icon_info
;
363 icon_info
= &entry
->priv
->icons
[i
];
364 icon_info
->window
= gdk_window_new(widget
->window
, &attributes
,
366 gdk_window_set_user_data(icon_info
->window
, widget
);
368 gdk_window_set_background(icon_info
->window
,
369 &widget
->style
->base
[GTK_WIDGET_STATE(widget
)]);
372 gtk_widget_queue_resize(widget
);
376 sexy_icon_entry_unrealize(GtkWidget
*widget
)
378 SexyIconEntry
*entry
= SEXY_ICON_ENTRY(widget
);
381 GTK_WIDGET_CLASS(parent_class
)->unrealize(widget
);
383 for (i
= 0; i
< MAX_ICONS
; i
++)
385 SexyIconInfo
*icon_info
= &entry
->priv
->icons
[i
];
387 gdk_window_destroy(icon_info
->window
);
388 icon_info
->window
= NULL
;
393 sexy_icon_entry_size_request(GtkWidget
*widget
, GtkRequisition
*requisition
)
396 SexyIconEntry
*entry
;
397 gint icon_widths
= 0;
400 gtkentry
= GTK_ENTRY(widget
);
401 entry
= SEXY_ICON_ENTRY(widget
);
403 for (i
= 0; i
< MAX_ICONS
; i
++)
405 int icon_width
= get_icon_width(entry
, i
);
408 icon_widths
+= icon_width
+ ICON_MARGIN
;
411 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
, requisition
);
413 if (icon_widths
> requisition
->width
)
414 requisition
->width
+= icon_widths
;
418 place_windows(SexyIconEntry
*icon_entry
, GtkAllocation
*widget_alloc
)
420 SexyIconEntryPosition left_icon_pos
;
421 SexyIconEntryPosition right_icon_pos
;
422 GtkAllocation left_icon_alloc
;
423 GtkAllocation right_icon_alloc
;
424 GtkAllocation text_area_alloc
;
426 get_text_area_size(icon_entry
, &text_area_alloc
);
427 get_icon_allocation(icon_entry
, TRUE
, widget_alloc
, &text_area_alloc
,
428 &left_icon_alloc
, &left_icon_pos
);
429 get_icon_allocation(icon_entry
, FALSE
, widget_alloc
, &text_area_alloc
,
430 &right_icon_alloc
, &right_icon_pos
);
432 if (left_icon_alloc
.width
> 0)
434 text_area_alloc
.x
= left_icon_alloc
.x
+ left_icon_alloc
.width
+
438 if (right_icon_alloc
.width
> 0)
439 text_area_alloc
.width
-= right_icon_alloc
.width
+ ICON_MARGIN
;
441 text_area_alloc
.width
-= text_area_alloc
.x
;
443 gdk_window_move_resize(icon_entry
->priv
->icons
[left_icon_pos
].window
,
444 left_icon_alloc
.x
, left_icon_alloc
.y
,
445 left_icon_alloc
.width
, left_icon_alloc
.height
);
447 gdk_window_move_resize(icon_entry
->priv
->icons
[right_icon_pos
].window
,
448 right_icon_alloc
.x
, right_icon_alloc
.y
,
449 right_icon_alloc
.width
, right_icon_alloc
.height
);
451 gdk_window_move_resize(GTK_ENTRY(icon_entry
)->text_area
,
452 text_area_alloc
.x
, text_area_alloc
.y
,
453 text_area_alloc
.width
, text_area_alloc
.height
);
457 sexy_icon_entry_size_allocate(GtkWidget
*widget
, GtkAllocation
*allocation
)
459 g_return_if_fail(SEXY_IS_ICON_ENTRY(widget
));
460 g_return_if_fail(allocation
!= NULL
);
462 widget
->allocation
= *allocation
;
464 GTK_WIDGET_CLASS(parent_class
)->size_allocate(widget
, allocation
);
466 if (GTK_WIDGET_REALIZED(widget
))
467 place_windows(SEXY_ICON_ENTRY(widget
), allocation
);
471 get_pixbuf_from_icon(SexyIconEntry
*entry
, SexyIconEntryPosition icon_pos
)
473 GdkPixbuf
*pixbuf
= NULL
;
474 const gchar
*stock_id
;
475 SexyIconInfo
*icon_info
= &entry
->priv
->icons
[icon_pos
];
479 switch (gtk_image_get_storage_type(GTK_IMAGE(icon_info
->icon
)))
481 case GTK_IMAGE_PIXBUF
:
482 pixbuf
= gtk_image_get_pixbuf(GTK_IMAGE(icon_info
->icon
));
483 g_object_ref(pixbuf
);
486 case GTK_IMAGE_STOCK
:
487 gtk_image_get_stock(GTK_IMAGE(icon_info
->icon
), (char**)&stock_id
, &size
);
488 pixbuf
= gtk_widget_render_icon(GTK_WIDGET(entry
),
489 stock_id
, size
, NULL
);
492 case GTK_IMAGE_ICON_NAME
:
493 gtk_image_get_icon_name (GTK_IMAGE(icon_info
->icon
), &stock_id
, &size
);
494 gtk_icon_size_lookup (size
, &w
, &h
);
495 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), stock_id
, size
, 0, NULL
);
505 /* Kudos to the gnome-panel guys. */
507 colorshift_pixbuf(GdkPixbuf
*dest
, GdkPixbuf
*src
, int shift
)
510 gint width
, height
, has_alpha
, src_rowstride
, dest_rowstride
;
511 guchar
*target_pixels
;
512 guchar
*original_pixels
;
518 has_alpha
= gdk_pixbuf_get_has_alpha(src
);
519 width
= gdk_pixbuf_get_width(src
);
520 height
= gdk_pixbuf_get_height(src
);
521 src_rowstride
= gdk_pixbuf_get_rowstride(src
);
522 dest_rowstride
= gdk_pixbuf_get_rowstride(dest
);
523 original_pixels
= gdk_pixbuf_get_pixels(src
);
524 target_pixels
= gdk_pixbuf_get_pixels(dest
);
526 for (i
= 0; i
< height
; i
++)
528 pix_dest
= target_pixels
+ i
* dest_rowstride
;
529 pix_src
= original_pixels
+ i
* src_rowstride
;
531 for (j
= 0; j
< width
; j
++)
538 *(pix_dest
++) = CLAMP(val
, 0, 255);
541 *(pix_dest
++) = CLAMP(val
, 0, 255);
544 *(pix_dest
++) = CLAMP(val
, 0, 255);
547 *(pix_dest
++) = *(pix_src
++);
553 draw_icon(GtkWidget
*widget
, SexyIconEntryPosition icon_pos
)
555 SexyIconEntry
*entry
= SEXY_ICON_ENTRY(widget
);
556 SexyIconInfo
*icon_info
= &entry
->priv
->icons
[icon_pos
];
558 gint x
, y
, width
, height
;
560 if (icon_info
->icon
== NULL
|| !GTK_WIDGET_REALIZED(widget
))
563 if ((pixbuf
= get_pixbuf_from_icon(entry
, icon_pos
)) == NULL
)
566 gdk_drawable_get_size(icon_info
->window
, &width
, &height
);
568 if (width
== 1 || height
== 1)
571 * size_allocate hasn't been called yet. These are the default values.
576 if (gdk_pixbuf_get_height(pixbuf
) > height
)
578 GdkPixbuf
*temp_pixbuf
;
581 scale
= height
- (2 * ICON_MARGIN
);
583 temp_pixbuf
= gdk_pixbuf_scale_simple(pixbuf
, scale
, scale
,
584 GDK_INTERP_BILINEAR
);
586 g_object_unref(pixbuf
);
588 pixbuf
= temp_pixbuf
;
591 x
= (width
- gdk_pixbuf_get_width(pixbuf
)) / 2;
592 y
= (height
- gdk_pixbuf_get_height(pixbuf
)) / 2;
594 if (icon_info
->hovered
)
596 GdkPixbuf
*temp_pixbuf
;
598 temp_pixbuf
= gdk_pixbuf_copy(pixbuf
);
600 colorshift_pixbuf(temp_pixbuf
, pixbuf
, 30);
602 g_object_unref(pixbuf
);
604 pixbuf
= temp_pixbuf
;
607 gdk_draw_pixbuf(icon_info
->window
, widget
->style
->black_gc
, pixbuf
,
609 GDK_RGB_DITHER_NORMAL
, 0, 0);
611 g_object_unref(pixbuf
);
615 sexy_icon_entry_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
617 SexyIconEntry
*entry
;
619 g_return_val_if_fail(SEXY_IS_ICON_ENTRY(widget
), FALSE
);
620 g_return_val_if_fail(event
!= NULL
, FALSE
);
622 entry
= SEXY_ICON_ENTRY(widget
);
624 if (GTK_WIDGET_DRAWABLE(widget
))
626 gboolean found
= FALSE
;
629 for (i
= 0; i
< MAX_ICONS
&& !found
; i
++)
631 SexyIconInfo
*icon_info
= &entry
->priv
->icons
[i
];
633 if (event
->window
== icon_info
->window
)
636 GtkAllocation text_area_alloc
;
638 get_text_area_size(entry
, &text_area_alloc
);
639 gdk_drawable_get_size(icon_info
->window
, &width
, NULL
);
641 gtk_paint_flat_box(widget
->style
, icon_info
->window
,
642 GTK_WIDGET_STATE(widget
), GTK_SHADOW_NONE
,
643 NULL
, widget
, "entry_bg",
644 0, 0, width
, text_area_alloc
.height
);
646 draw_icon(widget
, i
);
653 GTK_WIDGET_CLASS(parent_class
)->expose_event(widget
, event
);
660 update_icon(GObject
*obj
, GParamSpec
*param
, SexyIconEntry
*entry
)
664 const char *name
= g_param_spec_get_name(param
);
666 if (strcmp(name
, "pixbuf") && strcmp(name
, "stock") &&
667 strcmp(name
, "image") && strcmp(name
, "pixmap") &&
668 strcmp(name
, "icon-set") && strcmp(name
, "pixbuf-animation") &&
669 strcmp(name
, "icon-name"))
675 gtk_widget_queue_resize(GTK_WIDGET(entry
));
679 sexy_icon_entry_enter_notify(GtkWidget
*widget
, GdkEventCrossing
*event
)
681 SexyIconEntry
*entry
= SEXY_ICON_ENTRY(widget
);
684 for (i
= 0; i
< MAX_ICONS
; i
++)
686 if (event
->window
== entry
->priv
->icons
[i
].window
)
688 if (sexy_icon_entry_get_icon_highlight(entry
, i
))
690 entry
->priv
->icons
[i
].hovered
= TRUE
;
692 update_icon(NULL
, NULL
, entry
);
703 sexy_icon_entry_leave_notify(GtkWidget
*widget
, GdkEventCrossing
*event
)
705 SexyIconEntry
*entry
= SEXY_ICON_ENTRY(widget
);
708 for (i
= 0; i
< MAX_ICONS
; i
++)
710 if (event
->window
== entry
->priv
->icons
[i
].window
)
712 if (sexy_icon_entry_get_icon_highlight(entry
, i
))
714 entry
->priv
->icons
[i
].hovered
= FALSE
;
716 update_icon(NULL
, NULL
, entry
);
727 sexy_icon_entry_button_press(GtkWidget
*widget
, GdkEventButton
*event
)
729 SexyIconEntry
*entry
= SEXY_ICON_ENTRY(widget
);
732 for (i
= 0; i
< MAX_ICONS
; i
++)
734 if (event
->window
== entry
->priv
->icons
[i
].window
)
736 if (event
->button
== 1 &&
737 sexy_icon_entry_get_icon_highlight(entry
, i
))
739 entry
->priv
->icons
[i
].hovered
= FALSE
;
741 update_icon(NULL
, NULL
, entry
);
744 g_signal_emit(entry
, signals
[ICON_PRESSED
], 0, i
, event
->button
);
750 if (GTK_WIDGET_CLASS(parent_class
)->button_press_event
)
751 return GTK_WIDGET_CLASS(parent_class
)->button_press_event(widget
,
758 sexy_icon_entry_button_release(GtkWidget
*widget
, GdkEventButton
*event
)
760 SexyIconEntry
*entry
= SEXY_ICON_ENTRY(widget
);
763 for (i
= 0; i
< MAX_ICONS
; i
++)
765 GdkWindow
*icon_window
= entry
->priv
->icons
[i
].window
;
767 if (event
->window
== icon_window
)
770 gdk_drawable_get_size(icon_window
, &width
, &height
);
772 if (event
->button
== 1 &&
773 sexy_icon_entry_get_icon_highlight(entry
, i
) &&
774 event
->x
>= 0 && event
->y
>= 0 &&
775 event
->x
<= width
&& event
->y
<= height
)
777 entry
->priv
->icons
[i
].hovered
= TRUE
;
779 update_icon(NULL
, NULL
, entry
);
782 g_signal_emit(entry
, signals
[ICON_RELEASED
], 0, i
, event
->button
);
788 if (GTK_WIDGET_CLASS(parent_class
)->button_release_event
)
789 return GTK_WIDGET_CLASS(parent_class
)->button_release_event(widget
,
796 * sexy_icon_entry_new
798 * Creates a new SexyIconEntry widget.
800 * Returns a new #SexyIconEntry.
803 sexy_icon_entry_new(void)
805 return GTK_WIDGET(g_object_new(SEXY_TYPE_ICON_ENTRY
, NULL
));
809 * sexy_icon_entry_set_icon
810 * @entry: A #SexyIconEntry.
811 * @position: Icon position.
812 * @icon: A #GtkImage to set as the icon.
814 * Sets the icon shown in the entry
817 sexy_icon_entry_set_icon(SexyIconEntry
*entry
, SexyIconEntryPosition icon_pos
,
820 SexyIconInfo
*icon_info
;
822 g_return_if_fail(entry
!= NULL
);
823 g_return_if_fail(SEXY_IS_ICON_ENTRY(entry
));
824 g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos
));
825 g_return_if_fail(icon
== NULL
|| GTK_IS_IMAGE(icon
));
827 icon_info
= &entry
->priv
->icons
[icon_pos
];
829 if (icon
== icon_info
->icon
)
832 if (icon_pos
== SEXY_ICON_ENTRY_SECONDARY
&&
833 entry
->priv
->icon_released_id
!= 0)
835 g_signal_handler_disconnect(entry
, entry
->priv
->icon_released_id
);
836 entry
->priv
->icon_released_id
= 0;
841 if (icon_info
->icon
!= NULL
)
843 gtk_widget_destroy(GTK_WIDGET(icon_info
->icon
));
844 icon_info
->icon
= NULL
;
847 * Explicitly check, as the pointer may become invalidated
848 * during destruction.
850 if (icon_info
->window
!= NULL
&& GDK_IS_WINDOW(icon_info
->window
))
851 gdk_window_hide(icon_info
->window
);
856 if (icon_info
->window
!= NULL
&& icon_info
->icon
== NULL
)
857 gdk_window_show(icon_info
->window
);
859 g_signal_connect(G_OBJECT(icon
), "notify",
860 G_CALLBACK(update_icon
), entry
);
862 icon_info
->icon
= icon
;
866 update_icon(NULL
, NULL
, entry
);
870 * sexy_icon_entry_set_icon_highlight
871 * @entry: A #SexyIconEntry;
872 * @position: Icon position.
873 * @highlight: TRUE if the icon should highlight on mouse-over
875 * Determines whether the icon will highlight on mouse-over.
878 sexy_icon_entry_set_icon_highlight(SexyIconEntry
*entry
,
879 SexyIconEntryPosition icon_pos
,
882 SexyIconInfo
*icon_info
;
884 g_return_if_fail(entry
!= NULL
);
885 g_return_if_fail(SEXY_IS_ICON_ENTRY(entry
));
886 g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos
));
888 icon_info
= &entry
->priv
->icons
[icon_pos
];
890 if (icon_info
->highlight
== highlight
)
893 icon_info
->highlight
= highlight
;
897 * sexy_icon_entry_get_icon
898 * @entry: A #SexyIconEntry.
899 * @position: Icon position.
901 * Retrieves the image used for the icon
903 * Returns: A #GtkImage.
906 sexy_icon_entry_get_icon(const SexyIconEntry
*entry
,
907 SexyIconEntryPosition icon_pos
)
909 g_return_val_if_fail(entry
!= NULL
, NULL
);
910 g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry
), NULL
);
911 g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos
), NULL
);
913 return entry
->priv
->icons
[icon_pos
].icon
;
917 * sexy_icon_entry_get_icon_highlight
918 * @entry: A #SexyIconEntry.
919 * @position: Icon position.
921 * Retrieves whether entry will highlight the icon on mouseover.
923 * Returns: TRUE if icon highlights.
926 sexy_icon_entry_get_icon_highlight(const SexyIconEntry
*entry
,
927 SexyIconEntryPosition icon_pos
)
929 g_return_val_if_fail(entry
!= NULL
, FALSE
);
930 g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry
), FALSE
);
931 g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos
), FALSE
);
933 return entry
->priv
->icons
[icon_pos
].highlight
;
937 clear_button_clicked_cb(SexyIconEntry
*icon_entry
,
938 SexyIconEntryPosition icon_pos
,
941 if (icon_pos
!= SEXY_ICON_ENTRY_SECONDARY
|| button
!= 1)
944 gtk_entry_set_text(GTK_ENTRY(icon_entry
), "");
948 * sexy_icon_entry_add_clear_button
949 * @icon_entry: A #SexyIconEntry.
951 * A convenience function to add a clear button to the end of the entry.
952 * This is useful for search boxes.
955 sexy_icon_entry_add_clear_button(SexyIconEntry
*icon_entry
)
959 g_return_if_fail(icon_entry
!= NULL
);
960 g_return_if_fail(SEXY_IS_ICON_ENTRY(icon_entry
));
962 icon
= gtk_image_new_from_stock(GTK_STOCK_CLEAR
, GTK_ICON_SIZE_MENU
);
963 gtk_widget_show(icon
);
964 sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(icon_entry
),
965 SEXY_ICON_ENTRY_SECONDARY
,
967 sexy_icon_entry_set_icon_highlight(SEXY_ICON_ENTRY(icon_entry
),
968 SEXY_ICON_ENTRY_SECONDARY
, TRUE
);
970 if (icon_entry
->priv
->icon_released_id
!= 0)
972 g_signal_handler_disconnect(icon_entry
,
973 icon_entry
->priv
->icon_released_id
);
976 icon_entry
->priv
->icon_released_id
=
977 g_signal_connect(G_OBJECT(icon_entry
), "icon_released",
978 G_CALLBACK(clear_button_clicked_cb
), NULL
);