file-roller r2098 - in trunk: . src
- From: paobac svn gnome org
- To: svn-commits-list gnome org
- Subject: file-roller r2098 - in trunk: . src
- Date: Wed, 9 Jan 2008 15:56:14 +0000 (GMT)
Author: paobac
Date: Wed Jan 9 15:56:13 2008
New Revision: 2098
URL: http://svn.gnome.org/viewvc/file-roller?rev=2098&view=rev
Log:
2008-01-09 Paolo Bacchilega <paobac svn gnome org>
* src/ui.h:
* src/fr-window.c:
* src/actions.h:
* src/actions.c:
Second batch of changes for the find/filter bar.
2008-01-08 Paolo Bacchilega <paobac svn gnome org>
* src/sexy-icon-entry.h: new file
* src/sexy-icon-entry.c: new file
* src/fr-list-model.c:
* src/fr-window.h:
* src/fr-window.c:
* src/Makefile.am:
Started work an a filter bar.
Added:
trunk/src/sexy-icon-entry.c
trunk/src/sexy-icon-entry.h
Modified:
trunk/ChangeLog
trunk/src/Makefile.am
trunk/src/actions.c
trunk/src/actions.h
trunk/src/fr-list-model.c
trunk/src/fr-window.c
trunk/src/fr-window.h
trunk/src/ui.h
Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am (original)
+++ trunk/src/Makefile.am Wed Jan 9 15:56:13 2008
@@ -127,6 +127,8 @@
open-file.h \
preferences.c \
preferences.h \
+ sexy-icon-entry.c \
+ sexy-icon-entry.h \
typedefs.h \
ui.h \
utf8-fnmatch.c \
Modified: trunk/src/actions.c
==============================================================================
--- trunk/src/actions.c (original)
+++ trunk/src/actions.c Wed Jan 9 15:56:13 2008
@@ -768,6 +768,16 @@
void
+activate_action_find (GtkAction *action,
+ gpointer data)
+{
+ FrWindow *window = data;
+
+ fr_window_find (window);
+}
+
+
+void
activate_action_select_all (GtkAction *action,
gpointer data)
{
Modified: trunk/src/actions.h
==============================================================================
--- trunk/src/actions.h (original)
+++ trunk/src/actions.h Wed Jan 9 15:56:13 2008
@@ -53,6 +53,7 @@
void activate_action_rename_folder_from_sidebar (GtkAction *action, gpointer data);
void activate_action_delete_folder_from_sidebar (GtkAction *action, gpointer data);
+void activate_action_find (GtkAction *action, gpointer data);
void activate_action_select_all (GtkAction *action, gpointer data);
void activate_action_deselect_all (GtkAction *action, gpointer data);
void activate_action_open_with (GtkAction *action, gpointer data);
Modified: trunk/src/fr-list-model.c
==============================================================================
--- trunk/src/fr-list-model.c (original)
+++ trunk/src/fr-list-model.c Wed Jan 9 15:56:13 2008
@@ -40,7 +40,7 @@
window = g_object_get_data (G_OBJECT (drag_source), "FrWindow");
g_return_val_if_fail (window != NULL, FALSE);
- model = GTK_TREE_MODEL (fr_window_get_list_store (window));
+ model = fr_window_get_list_store (window);
for (scan = path_list; scan; scan = scan->next) {
GtkTreeRowReference *reference = scan->data;
Modified: trunk/src/fr-window.c
==============================================================================
--- trunk/src/fr-window.c (original)
+++ trunk/src/fr-window.c Wed Jan 9 15:56:13 2008
@@ -57,6 +57,7 @@
#include "gtk-utils.h"
#include "gconf-utils.h"
#include "open-file.h"
+#include "sexy-icon-entry.h"
#include "typedefs.h"
#include "ui.h"
#include "utf8-fnmatch.h"
@@ -180,7 +181,7 @@
}
-void
+static void
fr_clipboard_data_unref (FrClipboardData *clipboard_data)
{
if (clipboard_data == NULL)
@@ -199,7 +200,7 @@
}
-void
+static void
fr_clipboard_data_set_password (FrClipboardData *clipboard_data,
const char *password)
{
@@ -221,26 +222,29 @@
static guint fr_window_signals[LAST_SIGNAL] = { 0 };
struct _FrWindowPrivateData {
- GtkWidget * list_view;
- GtkListStore * list_store;
- GtkWidget * tree_view;
- GtkTreeStore * tree_store;
- GtkWidget * toolbar;
- GtkWidget * statusbar;
- GtkWidget * progress_bar;
- GtkWidget * location_bar;
- GtkWidget * location_entry;
- GtkWidget * location_label;
- GtkWidget * up_button;
- GtkWidget * home_button;
- GtkWidget * back_button;
- GtkWidget * fwd_button;
- GtkWidget *paned;
- GtkWidget *sidepane;
- GtkTreePath *tree_hover_path;
- GtkTreePath *list_hover_path;
+ GtkWidget *list_view;
+ GtkListStore *list_store;
+ GtkWidget *tree_view;
+ GtkTreeStore *tree_store;
+ GtkWidget *toolbar;
+ GtkWidget *statusbar;
+ GtkWidget *progress_bar;
+ GtkWidget *location_bar;
+ GtkWidget *location_entry;
+ GtkWidget *location_label;
+ GtkWidget *up_button;
+ GtkWidget *home_button;
+ GtkWidget *back_button;
+ GtkWidget *fwd_button;
+ GtkWidget *filter_bar;
+ GtkWidget *filter_entry;
+ GtkWidget *paned;
+ GtkWidget *sidepane;
+ GtkTreePath *tree_hover_path;
+ GtkTreePath *list_hover_path;
GtkTreeViewColumn *filename_column;
+ gboolean filter_mode;
gint current_view_length;
GtkTooltips *tooltips;
@@ -285,6 +289,7 @@
gboolean view_folders;
FRWindowListMode list_mode;
+ FRWindowListMode last_list_mode;
GList * history;
GList * history_current;
char * password;
@@ -582,7 +587,7 @@
preferences_set_sort_method (priv->sort_method);
preferences_set_sort_type (priv->sort_type);
- preferences_set_list_mode (priv->list_mode);
+ preferences_set_list_mode (priv->last_list_mode);
}
@@ -693,7 +698,8 @@
{
window->priv = g_new0 (FrWindowPrivateData, 1);
window->priv->update_dropped_files = FALSE;
-
+ window->priv->filter_mode = FALSE;
+
WindowList = g_list_prepend (WindowList, window);
}
@@ -975,6 +981,23 @@
}
+static gboolean
+file_data_respects_filter (FrWindow *window,
+ FileData *fdata)
+{
+ const char *filter;
+
+ filter = gtk_entry_get_text (GTK_ENTRY (window->priv->filter_entry));
+ if ((fdata == NULL) || (filter == NULL) || (*filter == '\0'))
+ return TRUE;
+
+ if (fdata->dir || (fdata->name == NULL))
+ return FALSE;
+
+ return strncasecmp (fdata->name, filter, strlen (filter)) == 0;
+}
+
+
static void
compute_file_list_name (FrWindow *window,
FileData *fdata,
@@ -988,6 +1011,9 @@
fdata->list_name = NULL;
fdata->list_dir = FALSE;
+ if (! file_data_respects_filter (window, fdata))
+ return;
+
if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) {
fdata->list_name = g_strdup (fdata->name);
if (fdata->dir)
@@ -1609,6 +1635,7 @@
gtk_widget_set_sensitive (window->priv->fwd_button, window->priv->archive_present && (current_dir != NULL) && (window->priv->history_current != NULL) && (window->priv->history_current->prev != NULL));
gtk_widget_set_sensitive (window->priv->location_entry, window->priv->archive_present);
gtk_widget_set_sensitive (window->priv->location_label, window->priv->archive_present);
+ gtk_widget_set_sensitive (window->priv->filter_entry, window->priv->archive_present);
#if 0
fr_window_history_print (window);
@@ -1642,7 +1669,8 @@
if (! window->priv->view_folders
|| ! window->priv->archive_present
- || (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)) {
+ || (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT))
+ {
gtk_widget_set_sensitive (window->priv->tree_view, FALSE);
gtk_widget_hide (window->priv->sidepane);
return;
@@ -1665,6 +1693,11 @@
FileData *fdata = g_ptr_array_index (window->archive->command->files, i);
char *dir;
+ if (gtk_entry_get_text (GTK_ENTRY (window->priv->filter_entry)) != NULL) {
+ if (! file_data_respects_filter (window, fdata))
+ continue;
+ }
+
if (fdata->dir)
dir = remove_ending_separator (fdata->full_path);
else
@@ -1751,6 +1784,19 @@
static void
+fr_window_update_filter_bar_visibility (FrWindow *window)
+{
+ const char *filter;
+
+ filter = gtk_entry_get_text (GTK_ENTRY (window->priv->filter_entry));
+ if ((filter == NULL) || (*filter == '\0'))
+ gtk_widget_hide (window->priv->filter_bar);
+ else
+ gtk_widget_show (window->priv->filter_bar);
+}
+
+
+static void
fr_window_update_file_list (FrWindow *window,
gboolean update_view)
{
@@ -1985,6 +2031,7 @@
set_sensitive (window, "DeselectAll", ! no_archive && sel_not_null);
set_sensitive (window, "Extract", file_op);
set_sensitive (window, "Extract_Toolbar", file_op);
+ set_sensitive (window, "Find", ! no_archive);
set_sensitive (window, "LastOutput", ((window->archive != NULL)
&& (window->archive->process != NULL)
&& (window->archive->process->raw_output != NULL)));
@@ -2017,6 +2064,9 @@
set_sensitive (window, "ViewFolders", (window->priv->list_mode == FR_WINDOW_LIST_MODE_AS_DIR));
+ set_sensitive (window, "ViewAllFiles", ! window->priv->filter_mode);
+ set_sensitive (window, "ViewAsFolder", ! window->priv->filter_mode);
+
/**/
if (! window->priv->closing && (window->priv->check_clipboard == 0))
@@ -2032,8 +2082,10 @@
if ((event->keyval == GDK_Return)
|| (event->keyval == GDK_KP_Enter)
|| (event->keyval == GDK_ISO_Enter))
+ {
fr_window_go_to_location (window, gtk_entry_get_text (GTK_ENTRY (window->priv->location_entry)), FALSE);
-
+ }
+
return FALSE;
}
@@ -3222,7 +3274,8 @@
/* only redraw if the hover row has changed */
if (!(last_hover_path == NULL && window->priv->list_hover_path == NULL) &&
(!(last_hover_path != NULL && window->priv->list_hover_path != NULL) ||
- gtk_tree_path_compare (last_hover_path, window->priv->list_hover_path))) {
+ gtk_tree_path_compare (last_hover_path, window->priv->list_hover_path)))
+ {
if (last_hover_path) {
gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
&iter, last_hover_path);
@@ -3712,6 +3765,24 @@
/* -- window_new -- */
+static void
+fr_window_deactivate_filter (FrWindow *window)
+{
+ window->priv->filter_mode = FALSE;
+ window->priv->list_mode = window->priv->last_list_mode;
+
+ gtk_entry_set_text (GTK_ENTRY (window->priv->filter_entry), "");
+ fr_window_update_filter_bar_visibility (window);
+
+ gtk_list_store_clear (window->priv->list_store);
+
+ fr_window_update_columns_visibility (window);
+ fr_window_update_file_list (window, TRUE);
+ fr_window_update_dir_tree (window);
+ fr_window_update_current_location (window);
+}
+
+
static gboolean
key_press_cb (GtkWidget *widget,
GdkEventKey *event,
@@ -3723,12 +3794,26 @@
if (GTK_WIDGET_HAS_FOCUS (window->priv->location_entry))
return FALSE;
+
+ if (GTK_WIDGET_HAS_FOCUS (window->priv->filter_entry)) {
+ switch (event->keyval) {
+ case GDK_Escape:
+ fr_window_deactivate_filter (window);
+ retval = TRUE;
+ break;
+ default:
+ break;
+ }
+ return retval;
+ }
alt = (event->state & GDK_MOD1_MASK) == GDK_MOD1_MASK;
switch (event->keyval) {
case GDK_Escape:
activate_action_stop (NULL, window);
+ if (window->priv->filter_mode)
+ fr_window_deactivate_filter (window);
retval = TRUE;
break;
@@ -4145,6 +4230,8 @@
window->priv->view_folders = eel_gconf_get_boolean (PREF_UI_FOLDERS, FALSE);
set_active (window, "ViewFolders", window->priv->view_folders);
+ fr_window_update_filter_bar_visibility (window);
+
return TRUE;
}
@@ -4509,7 +4596,7 @@
}
-void
+static void
go_up_one_level_cb (GtkWidget *widget,
void *data)
{
@@ -4517,7 +4604,7 @@
}
-void
+static void
go_home_cb (GtkWidget *widget,
void *data)
{
@@ -4525,7 +4612,7 @@
}
-void
+static void
go_back_cb (GtkWidget *widget,
void *data)
{
@@ -4533,7 +4620,7 @@
}
-void
+static void
go_forward_cb (GtkWidget *widget,
void *data)
{
@@ -4592,12 +4679,54 @@
static void
+fr_window_activate_filter (FrWindow *window)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (window->priv->list_view);
+ GtkTreeViewColumn *column;
+
+ fr_window_update_filter_bar_visibility (window);
+ window->priv->list_mode = FR_WINDOW_LIST_MODE_FLAT;
+
+ gtk_list_store_clear (window->priv->list_store);
+
+ column = gtk_tree_view_get_column (tree_view, 4);
+ gtk_tree_view_column_set_visible (column, TRUE);
+
+ fr_window_update_file_list (window, TRUE);
+ fr_window_update_dir_tree (window);
+ fr_window_update_current_location (window);
+}
+
+
+static void
+filter_entry_activate_cb (GtkEntry *entry,
+ FrWindow *window)
+{
+ fr_window_activate_filter (window);
+}
+
+
+static void
+filter_entry_icon_released_cb (SexyIconEntry *entry,
+ SexyIconEntryPosition icon_pos,
+ int button,
+ gpointer user_data)
+{
+ FrWindow *window = FR_WINDOW (user_data);
+
+ if ((button == 1) && (icon_pos == SEXY_ICON_ENTRY_SECONDARY))
+ fr_window_deactivate_filter (window);
+}
+
+
+static void
fr_window_construct (FrWindow *window)
{
GtkWidget *toolbar;
GtkWidget *list_scrolled_window;
GtkWidget *vbox;
GtkWidget *location_box;
+ GtkWidget *filter_box;
GtkWidget *tree_scrolled_window;
GtkWidget *sidepane_title;
GtkWidget *sidepane_title_box;
@@ -4710,7 +4839,7 @@
window->priv->sort_method = preferences_get_sort_method ();
window->priv->sort_type = preferences_get_sort_type ();
- window->priv->list_mode = preferences_get_list_mode ();
+ window->priv->list_mode = window->priv->last_list_mode = preferences_get_list_mode ();
window->priv->history = NULL;
window->priv->history_current = NULL;
@@ -4778,13 +4907,13 @@
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING);
- g_object_set_data (G_OBJECT (window->priv->list_store), "FrWindow", window);
+ g_object_set_data (G_OBJECT (window->priv->list_store), "FrWindow", window);
window->priv->list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->priv->list_store));
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (window->priv->list_view), TRUE);
add_file_list_columns (window, GTK_TREE_VIEW (window->priv->list_view));
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (window->priv->list_view),
- TRUE);
+ FALSE);
gtk_tree_view_set_search_column (GTK_TREE_VIEW (window->priv->list_view),
COLUMN_NAME);
@@ -4927,7 +5056,11 @@
gtk_box_pack_start (GTK_BOX (location_box),
window->priv->location_label, FALSE, FALSE, 5);
- window->priv->location_entry = gtk_entry_new ();
+ window->priv->location_entry = sexy_icon_entry_new ();
+ sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (window->priv->location_entry),
+ SEXY_ICON_ENTRY_PRIMARY,
+ GTK_IMAGE (gtk_image_new_from_stock (GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU)));
+
gtk_box_pack_start (GTK_BOX (location_box),
window->priv->location_entry, TRUE, TRUE, 5);
@@ -4935,9 +5068,49 @@
"key_press_event",
G_CALLBACK (location_entry_key_press_event_cb),
window);
-
+
gtk_widget_show_all (window->priv->location_bar);
+ /* filter bar */
+
+ filter_box = gtk_hbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (filter_box), 3);
+
+ window->priv->filter_bar = gnome_app_add_docked (GNOME_APP (window),
+ filter_box,
+ "FilterBar",
+ (BONOBO_DOCK_ITEM_BEH_NEVER_VERTICAL
+ | BONOBO_DOCK_ITEM_BEH_EXCLUSIVE
+ | (eel_gconf_get_boolean (PREF_DESKTOP_TOOLBAR_DETACHABLE, TRUE) ? BONOBO_DOCK_ITEM_BEH_NORMAL : BONOBO_DOCK_ITEM_BEH_LOCKED)),
+ BONOBO_DOCK_BOTTOM,
+ 4, 1, 0);
+
+ gtk_box_pack_start (GTK_BOX (filter_box),
+ gtk_label_new (_("Find:")), FALSE, FALSE, 0);
+
+ /* * filter entry */
+
+ window->priv->filter_entry = sexy_icon_entry_new ();
+ /*sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (window->priv->filter_entry),
+ SEXY_ICON_ENTRY_PRIMARY,
+ GTK_IMAGE (gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU)));*/
+ sexy_icon_entry_add_clear_button (SEXY_ICON_ENTRY (window->priv->filter_entry));
+
+ gtk_widget_set_size_request (window->priv->filter_entry, 300, -1);
+ gtk_box_pack_start (GTK_BOX (filter_box),
+ window->priv->filter_entry, FALSE, FALSE, 6);
+
+ g_signal_connect (G_OBJECT (window->priv->filter_entry),
+ "activate",
+ G_CALLBACK (filter_entry_activate_cb),
+ window);
+ g_signal_connect (G_OBJECT (window->priv->filter_entry),
+ "icon_released",
+ G_CALLBACK (filter_entry_icon_released_cb),
+ window);
+
+ gtk_widget_show_all (filter_box);
+
/* tree view */
window->priv->tree_store = gtk_tree_store_new (TREE_NUMBER_OF_COLUMNS,
@@ -5986,13 +6159,13 @@
{
g_return_if_fail (window != NULL);
- window->priv->list_mode = list_mode;
+ window->priv->list_mode = window->priv->last_list_mode = list_mode;
if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) {
fr_window_history_clear (window);
fr_window_history_add (window, "/");
}
- preferences_set_list_mode (window->priv->list_mode);
+ preferences_set_list_mode (window->priv->last_list_mode);
eel_gconf_set_boolean (PREF_LIST_SHOW_PATH, (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT));
fr_window_update_file_list (window, TRUE);
@@ -6229,10 +6402,19 @@
}
-GtkListStore *
+GtkTreeModel *
fr_window_get_list_store (FrWindow *window)
{
- return window->priv->list_store;
+ return GTK_TREE_MODEL (window->priv->list_store);
+}
+
+
+void
+fr_window_find (FrWindow *window)
+{
+ window->priv->filter_mode = TRUE;
+ gtk_widget_show (window->priv->filter_bar);
+ gtk_widget_grab_focus (window->priv->filter_entry);
}
Modified: trunk/src/fr-window.h
==============================================================================
--- trunk/src/fr-window.h (original)
+++ trunk/src/fr-window.h Wed Jan 9 15:56:13 2008
@@ -207,8 +207,9 @@
GList * fr_window_get_selection (FrWindow *window,
gboolean from_sidebar,
char **return_base_dir);
-GtkListStore *
+GtkTreeModel *
fr_window_get_list_store (FrWindow *window);
+void fr_window_find (FrWindow *window);
void fr_window_select_all (FrWindow *window);
void fr_window_unselect_all (FrWindow *window);
void fr_window_set_sort_type (FrWindow *window,
Added: trunk/src/sexy-icon-entry.c
==============================================================================
--- (empty file)
+++ trunk/src/sexy-icon-entry.c Wed Jan 9 15:56:13 2008
@@ -0,0 +1,1045 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * File-Roller
+ *
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+/* Based on libsexy 0.1.11. Original copyright note follows:
+ *
+ * @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 <libsexy/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;
+ gboolean hide_if_empty;
+ GdkWindow *window;
+
+} SexyIconInfo;
+
+struct _SexyIconEntryPriv
+{
+ SexyIconInfo icons[MAX_ICONS];
+
+ gulong icon_released_id;
+ gboolean empty;
+};
+
+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 void sexy_icon_entry_changed (GtkEditable *editable);
+
+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)
+{
+ iface->changed = sexy_icon_entry_changed;
+}
+
+static void
+sexy_icon_entry_init(SexyIconEntry *entry)
+{
+ entry->priv = g_new0(SexyIconEntryPriv, 1);
+ entry->priv->empty = TRUE;
+}
+
+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 (entry->priv->empty && icon_info->hide_if_empty)
+ 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;
+}
+
+
+static void
+sexy_icon_entry_changed (GtkEditable *editable)
+{
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(editable);
+ char *value;
+ gboolean empty;
+
+ value = gtk_editable_get_chars (editable, 0, -1);
+ empty = (value == NULL) || (*value == '\0');
+ if (empty != entry->priv->empty) {
+ entry->priv->empty = empty;
+ gtk_widget_queue_resize (GTK_WIDGET (entry));
+ }
+ g_free (value);
+}
+
+
+/**
+ * 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;
+
+ icon_info->hide_if_empty = FALSE;
+
+ 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_set_hide_if_empty
+ * @entry: A #SexyIconEntry;
+ * @position: Icon position.
+ * @hide: TRUE if the icon should hidden when the entry is empty
+ *
+ * Determines whether the icon will be hidden when the entry is empty.
+ */
+void
+sexy_icon_entry_set_hide_if_empty (SexyIconEntry *entry,
+ SexyIconEntryPosition icon_pos,
+ gboolean hide)
+{
+ 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];
+ icon_info->hide_if_empty = hide;
+}
+
+/**
+ * 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);
+ sexy_icon_entry_set_hide_if_empty(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);
+}
Added: trunk/src/sexy-icon-entry.h
==============================================================================
--- (empty file)
+++ trunk/src/sexy-icon-entry.h Wed Jan 9 15:56:13 2008
@@ -0,0 +1,127 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * File-Roller
+ *
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+/* Based on libsexy 0.1.11. Original copyright note follows:
+ *
+ * @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;
+
+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);
+
+void sexy_icon_entry_set_hide_if_empty(SexyIconEntry *entry,
+ SexyIconEntryPosition position,
+ gboolean hide);
+
+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
Modified: trunk/src/ui.h
==============================================================================
--- trunk/src/ui.h (original)
+++ trunk/src/ui.h Wed Jan 9 15:56:13 2008
@@ -124,6 +124,11 @@
N_("Extract"), NULL,
N_("Extract files from the archive"),
G_CALLBACK (activate_action_extract) },
+ { "Find", GTK_STOCK_FIND,
+ NULL, NULL,
+ NULL,
+ G_CALLBACK (activate_action_find) },
+
{ "LastOutput", NULL,
N_("_Last Output"), NULL,
N_("View the output produced by the last executed command"),
@@ -279,6 +284,8 @@
" <menuitem action='SelectAll'/>"
" <menuitem action='DeselectAll'/>"
" <separator/>"
+" <menuitem action='Find'/>"
+" <separator/>"
" <menuitem action='Password'/>"
" </menu>"
" <menu action='ViewMenu'>"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]