summaryrefslogtreecommitdiff
path: root/gsearchtool/src
diff options
context:
space:
mode:
authormonsta <[email protected]>2015-09-09 12:09:52 +0300
committermonsta <[email protected]>2015-09-09 12:09:52 +0300
commit0d36d61761a1d68839d61f521889dba3db7f514f (patch)
treedcf4188d0a02bdf227fa1abf6d0aedb8218075d8 /gsearchtool/src
parentf95463c41d467b5cd5c1c1d94c1734a8fe1b009d (diff)
downloadmate-utils-0d36d61761a1d68839d61f521889dba3db7f514f.tar.bz2
mate-utils-0d36d61761a1d68839d61f521889dba3db7f514f.tar.xz
gsearchtool: move smclient stuff there, move sources to src/ subdir
Diffstat (limited to 'gsearchtool/src')
-rw-r--r--gsearchtool/src/Makefile.am36
-rw-r--r--gsearchtool/src/gsearchtool-callbacks.c1953
-rw-r--r--gsearchtool/src/gsearchtool-callbacks.h180
-rw-r--r--gsearchtool/src/gsearchtool-support.c1588
-rw-r--r--gsearchtool/src/gsearchtool-support.h114
-rw-r--r--gsearchtool/src/gsearchtool.c3070
-rw-r--r--gsearchtool/src/gsearchtool.h243
7 files changed, 7184 insertions, 0 deletions
diff --git a/gsearchtool/src/Makefile.am b/gsearchtool/src/Makefile.am
new file mode 100644
index 00000000..58a042ec
--- /dev/null
+++ b/gsearchtool/src/Makefile.am
@@ -0,0 +1,36 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/gsearchtool/libeggsmclient \
+ -I$(top_srcdir)/gsearchtool/libmateui-deprecated \
+ $(DISABLE_DEPRECATED) \
+ -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DLOCALEDIR=\"$(datadir)/locale\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DGREP_COMMAND=\""$(GREP_COMMAND)"\"
+
+libeggsmclient_LIB = $(top_builddir)/gsearchtool/libeggsmclient/libeggsmclient.la
+libmateui_deprecated_LIB = $(top_builddir)/gsearchtool/libmateui-deprecated/libmateui-deprecated.la
+
+bin_PROGRAMS = mate-search-tool
+
+mate_search_tool_SOURCES = \
+ gsearchtool-support.c \
+ gsearchtool-support.h \
+ gsearchtool-callbacks.c \
+ gsearchtool-callbacks.h \
+ gsearchtool.c \
+ gsearchtool.h
+
+mate_search_tool_CFLAGS = \
+ $(GLIB_CFLAGS) \
+ $(GIO_CFLAGS) \
+ $(GIO_UNIX_CFLAGS) \
+ $(GTK_CFLAGS)
+
+mate_search_tool_LDADD = \
+ $(GLIB_LIBS) \
+ $(GIO_LIBS) \
+ $(GIO_UNIX_LIBS) \
+ $(GTK_LIBS) \
+ $(libeggsmclient_LIB) \
+ $(libmateui_deprecated_LIB)
+
diff --git a/gsearchtool/src/gsearchtool-callbacks.c b/gsearchtool/src/gsearchtool-callbacks.c
new file mode 100644
index 00000000..0c040867
--- /dev/null
+++ b/gsearchtool/src/gsearchtool-callbacks.c
@@ -0,0 +1,1953 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * MATE Search Tool
+ *
+ * File: gsearchtool-callbacks.c
+ *
+ * (C) 2002 the Free Software Foundation
+ *
+ * Authors: Dennis Cranston <[email protected]>
+ * George Lebl
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gsearchtool.h"
+#include "gsearchtool-callbacks.h"
+#include "gsearchtool-support.h"
+
+#define SILENT_WINDOW_OPEN_LIMIT 5
+
+#ifdef HAVE_GETPGID
+extern pid_t getpgid (pid_t);
+#endif
+
+gboolean row_selected_by_button_press_event;
+
+static void
+store_window_state_and_geometry (GSearchWindow *gsearch)
+{
+ gsearch->window_width = MAX (gsearch->window_width, MINIMUM_WINDOW_WIDTH);
+ gsearch->window_height = MAX (gsearch->window_height, MINIMUM_WINDOW_HEIGHT);
+
+ g_settings_set_int (gsearch->mate_search_tool_settings,
+ "default-window-width",
+ gsearch->window_width);
+ g_settings_set_int (gsearch->mate_search_tool_settings,
+ "default-window-height",
+ gsearch->window_height);
+ g_settings_set_boolean (gsearch->mate_search_tool_settings,
+ "default-window-maximized",
+ gsearch->is_window_maximized);
+}
+
+static void
+quit_application (GSearchWindow * gsearch)
+{
+ GSearchCommandDetails * command_details = gsearch->command_details;
+
+ if (command_details->command_status == RUNNING) {
+#ifdef HAVE_GETPGID
+ pid_t pgid;
+#endif
+ command_details->command_status = MAKE_IT_QUIT;
+#ifdef HAVE_GETPGID
+ pgid = getpgid (command_details->command_pid);
+
+ if ((pgid > 1) && (pgid != getpid ())) {
+ kill (-(getpgid (command_details->command_pid)), SIGKILL);
+ }
+ else {
+ kill (command_details->command_pid, SIGKILL);
+ }
+#else
+ kill (command_details->command_pid, SIGKILL);
+#endif
+ wait (NULL);
+ }
+ store_window_state_and_geometry (gsearch);
+ gtk_main_quit ();
+}
+
+void
+version_cb (const gchar * option_name,
+ const gchar * value,
+ gpointer data,
+ GError ** error)
+{
+ g_print ("%s %s\n", g_get_application_name (), VERSION);
+ exit (0);
+}
+
+void
+quit_session_cb (EggSMClient * client,
+ gpointer data)
+{
+ quit_application ((GSearchWindow *) data);
+}
+
+void
+quit_cb (GtkWidget * widget,
+ GdkEvent * event,
+ gpointer data)
+{
+ quit_application ((GSearchWindow *) data);
+}
+
+void
+click_close_cb (GtkWidget * widget,
+ gpointer data)
+{
+ quit_application ((GSearchWindow *) data);
+}
+
+void
+click_find_cb (GtkWidget * widget,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ gchar * command;
+
+ if (gsearch->command_details->is_command_timeout_enabled == TRUE) {
+ return;
+ }
+
+ if ((gsearch->command_details->command_status == STOPPED) ||
+ (gsearch->command_details->command_status == ABORTED)) {
+ command = build_search_command (gsearch, TRUE);
+ if (command != NULL) {
+ spawn_search_command (gsearch, command);
+ g_free (command);
+ }
+ }
+}
+
+void
+click_stop_cb (GtkWidget * widget,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ if (gsearch->command_details->command_status == RUNNING) {
+#ifdef HAVE_GETPGID
+ pid_t pgid;
+#endif
+ gtk_widget_set_sensitive (gsearch->stop_button, FALSE);
+ gsearch->command_details->command_status = MAKE_IT_STOP;
+#ifdef HAVE_GETPGID
+ pgid = getpgid (gsearch->command_details->command_pid);
+
+ if ((pgid > 1) && (pgid != getpid ())) {
+ kill (-(getpgid (gsearch->command_details->command_pid)), SIGKILL);
+ }
+ else {
+ kill (gsearch->command_details->command_pid, SIGKILL);
+ }
+#else
+ kill (gsearch->command_details->command_pid, SIGKILL);
+#endif
+ wait (NULL);
+ }
+}
+
+void
+click_help_cb (GtkWidget * widget,
+ gpointer data)
+{
+ GtkWidget * window = data;
+ GError * error = NULL;
+
+ gtk_show_uri (gtk_widget_get_screen (widget), "help:mate-search-tool",
+ gtk_get_current_event_time (), &error);
+ if (error) {
+ GtkWidget * dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Could not open help document."));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ error->message, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+ g_error_free (error);
+ }
+}
+
+void
+click_expander_cb (GObject * object,
+ GParamSpec * param_spec,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ if (gtk_expander_get_expanded (GTK_EXPANDER (object)) == TRUE) {
+ gtk_widget_show (gsearch->available_options_vbox);
+ gtk_window_set_geometry_hints (GTK_WINDOW (gsearch->window),
+ GTK_WIDGET (gsearch->window),
+ &gsearch->window_geometry,
+ GDK_HINT_MIN_SIZE);
+ }
+ else {
+ GdkGeometry default_geometry = {MINIMUM_WINDOW_WIDTH, MINIMUM_WINDOW_HEIGHT};
+
+ gtk_widget_hide (gsearch->available_options_vbox);
+ gtk_window_set_geometry_hints (GTK_WINDOW (gsearch->window),
+ GTK_WIDGET (gsearch->window),
+ &default_geometry,
+ GDK_HINT_MIN_SIZE);
+ }
+}
+
+void
+size_allocate_cb (GtkWidget * widget,
+ GtkAllocation * allocation,
+ gpointer data)
+{
+ GtkWidget * button = data;
+
+ gtk_widget_set_size_request (button, allocation->width, -1);
+}
+
+void
+add_constraint_cb (GtkWidget * widget,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ gint idx;
+
+ idx = gtk_combo_box_get_active (GTK_COMBO_BOX (gsearch->available_options_combo_box));
+ add_constraint (gsearch, idx, NULL, FALSE);
+}
+
+void
+remove_constraint_cb (GtkWidget * widget,
+ gpointer data)
+{
+ GList * list = data;
+
+ GSearchWindow * gsearch = g_list_first (list)->data;
+ GSearchConstraint * constraint = g_list_last (list)->data;
+
+ gsearch->window_geometry.min_height -= WINDOW_HEIGHT_STEP;
+
+ gtk_window_set_geometry_hints (GTK_WINDOW (gsearch->window),
+ GTK_WIDGET (gsearch->window),
+ &gsearch->window_geometry,
+ GDK_HINT_MIN_SIZE);
+
+ gtk_container_remove (GTK_CONTAINER (gsearch->available_options_vbox), gtk_widget_get_parent (widget));
+
+ gsearch->available_options_selected_list =
+ g_list_remove (gsearch->available_options_selected_list, constraint);
+
+ set_constraint_selected_state (gsearch, constraint->constraint_id, FALSE);
+ set_constraint_gsettings_boolean (constraint->constraint_id, FALSE);
+ g_slice_free (GSearchConstraint, constraint);
+ g_list_free (list);
+}
+
+void
+constraint_activate_cb (GtkWidget * widget,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ if ((gtk_widget_get_visible (gsearch->find_button)) &&
+ (gtk_widget_get_sensitive (gsearch->find_button))) {
+ click_find_cb (gsearch->find_button, data);
+ }
+}
+
+void
+constraint_update_info_cb (GtkWidget * widget,
+ gpointer data)
+{
+ static gchar * string;
+ GSearchConstraint * opt = data;
+
+ string = (gchar *) gtk_entry_get_text (GTK_ENTRY (widget));
+ update_constraint_info (opt, string);
+}
+
+void
+name_contains_activate_cb (GtkWidget * widget,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ if ((gtk_widget_get_visible (gsearch->find_button)) &&
+ (gtk_widget_get_sensitive (gsearch->find_button))) {
+ click_find_cb (gsearch->find_button, data);
+ }
+}
+
+void
+look_in_folder_changed_cb (GtkWidget * widget,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ gchar * value;
+
+ value = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (gsearch->look_in_folder_button));
+
+ if (value != NULL) {
+ g_settings_set_string (gsearch->mate_search_tool_settings, "look-in-folder", value);
+ }
+ g_free (value);
+}
+
+
+static gint
+display_dialog_file_open_limit (GtkWidget * window,
+ gint count)
+{
+ GtkWidget * dialog;
+ GtkWidget * button;
+ gchar * primary;
+ gchar * secondary;
+ gint response;
+
+ primary = g_strdup_printf (ngettext ("Are you sure you want to open %d document?",
+ "Are you sure you want to open %d documents?",
+ count),
+ count);
+
+ secondary = g_strdup_printf (ngettext ("This will open %d separate window.",
+ "This will open %d separate windows.",
+ count),
+ count);
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ primary, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ secondary, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ button = gtk_button_new_from_stock ("gtk-open");
+ gtk_widget_set_can_default (button, TRUE);
+ gtk_widget_show (button);
+
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_free (primary);
+ g_free (secondary);
+
+ return response;
+}
+
+static void
+display_dialog_could_not_open_file (GtkWidget * window,
+ const gchar * file,
+ const gchar * message)
+{
+ GtkWidget * dialog;
+ gchar * primary;
+
+ primary = g_strdup_printf (_("Could not open document \"%s\"."), file);
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ primary, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ message, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+ g_free (primary);
+}
+
+static void
+display_dialog_could_not_open_folder (GtkWidget * window,
+ const gchar * folder)
+{
+ GtkWidget * dialog;
+ gchar * primary;
+
+ primary = g_strdup_printf (_("Could not open folder \"%s\"."), folder);
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ primary, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("The caja file manager is not running."));
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+ g_free (primary);
+}
+
+void
+open_file_event_cb (GtkWidget * widget,
+ GdkEventButton * event,
+ gpointer data)
+{
+ open_file_cb ((GtkMenuItem *) widget, data);
+}
+
+void
+open_file_cb (GtkMenuItem * action,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ GtkTreeModel * model;
+ GList * list;
+ guint idx;
+
+ if (gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection)) == 0) {
+ return;
+ }
+
+ list = gtk_tree_selection_get_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ &model);
+
+ if (g_list_length (list) > SILENT_WINDOW_OPEN_LIMIT) {
+ gint response;
+
+ response = display_dialog_file_open_limit (gsearch->window, g_list_length (list));
+
+ if (response == GTK_RESPONSE_CANCEL) {
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+ return;
+ }
+ }
+
+ for (idx = 0; idx < g_list_length (list); idx++) {
+
+ gboolean no_files_found = FALSE;
+ gchar * utf8_name;
+ gchar * locale_file;
+ GtkTreeIter iter;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ g_list_nth_data (list, idx));
+
+ gtk_tree_model_get (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ COLUMN_NAME, &utf8_name,
+ COLUMN_LOCALE_FILE, &locale_file,
+ COLUMN_NO_FILES_FOUND, &no_files_found,
+ -1);
+
+ if (!no_files_found) {
+ GAppInfo * app = NULL;
+
+ if (GTK_IS_MENU_ITEM (action)) {
+ app = g_object_get_data (G_OBJECT (action), "app");
+ }
+
+ if (!g_file_test (locale_file, G_FILE_TEST_EXISTS)) {
+ gtk_tree_selection_unselect_iter (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ &iter);
+ display_dialog_could_not_open_file (gsearch->window, utf8_name,
+ _("The document does not exist."));
+
+ }
+ else if (open_file_with_application (gsearch->window, locale_file, app) == FALSE) {
+
+ if (launch_file (locale_file) == FALSE) {
+
+ if (g_file_test (locale_file, G_FILE_TEST_IS_DIR)) {
+
+ if (open_file_with_filemanager (gsearch->window, locale_file) == FALSE) {
+ display_dialog_could_not_open_folder (gsearch->window, utf8_name);
+ }
+ }
+ else {
+ display_dialog_could_not_open_file (gsearch->window, utf8_name,
+ _("There is no installed viewer capable "
+ "of displaying the document."));
+ }
+ }
+ }
+ }
+ g_free (utf8_name);
+ g_free (locale_file);
+ }
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+}
+
+static gint
+display_dialog_folder_open_limit (GtkWidget * window,
+ gint count)
+{
+ GtkWidget * dialog;
+ GtkWidget * button;
+ gchar * primary;
+ gchar * secondary;
+ gint response;
+
+ primary = g_strdup_printf (ngettext ("Are you sure you want to open %d folder?",
+ "Are you sure you want to open %d folders?",
+ count),
+ count);
+
+ secondary = g_strdup_printf (ngettext ("This will open %d separate window.",
+ "This will open %d separate windows.",
+ count),
+ count);
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ primary, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ secondary, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ button = gtk_button_new_from_stock ("gtk-open");
+ gtk_widget_set_can_default (button, TRUE);
+ gtk_widget_show (button);
+
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_free (primary);
+ g_free (secondary);
+
+ return response;
+}
+
+void
+open_folder_cb (GtkAction * action,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ GtkTreeModel * model;
+ GFile * g_file = NULL;
+ GFileInfo * g_file_info = NULL;
+ GAppInfo * g_app_info = NULL;
+ GList * list;
+ guint idx;
+
+ if (gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection)) == 0) {
+ return;
+ }
+
+ list = gtk_tree_selection_get_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ &model);
+
+ if (g_list_length (list) > SILENT_WINDOW_OPEN_LIMIT) {
+ gint response;
+
+ response = display_dialog_folder_open_limit (gsearch->window, g_list_length (list));
+
+ if (response == GTK_RESPONSE_CANCEL) {
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+ return;
+ }
+ }
+
+ for (idx = 0; idx < g_list_length (list); idx++) {
+
+ gchar * locale_folder;
+ gchar * utf8_folder;
+ gchar * locale_file;
+ GtkTreeIter iter;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ g_list_nth_data (list, idx));
+
+ gtk_tree_model_get (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ COLUMN_RELATIVE_PATH, &utf8_folder,
+ COLUMN_LOCALE_FILE, &locale_file,
+ -1);
+
+ locale_folder = g_path_get_dirname (locale_file);
+
+ if (idx == 0) {
+ g_file = g_file_new_for_path (locale_folder);
+ g_file_info = g_file_query_info (g_file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ g_app_info = g_app_info_get_default_for_type (g_file_info_get_content_type (g_file_info), FALSE);
+ }
+
+ if (open_file_with_application (gsearch->window, locale_folder, g_app_info) == FALSE) {
+
+ if (open_file_with_filemanager (gsearch->window, locale_folder) == FALSE) {
+
+ display_dialog_could_not_open_folder (gsearch->window, utf8_folder);
+
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+ g_free (locale_folder);
+ g_free (utf8_folder);
+ g_object_unref (g_file);
+ g_object_unref (g_file_info);
+ g_object_unref (g_app_info);
+ return;
+ }
+ }
+ g_free (locale_folder);
+ g_free (locale_file);
+ g_free (utf8_folder);
+ }
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+ g_object_unref (g_file);
+ g_object_unref (g_file_info);
+ g_object_unref (g_app_info);
+}
+
+void
+file_changed_cb (GFileMonitor * handle,
+ const gchar * monitor_uri,
+ const gchar * info_uri,
+ GFileMonitorEvent event_type,
+ gpointer data)
+{
+ GSearchMonitor * monitor = data;
+ GSearchWindow * gsearch = monitor->gsearch;
+ GtkTreeModel * model;
+ GtkTreePath * path;
+ GtkTreeIter iter;
+
+ switch (event_type) {
+ case G_FILE_MONITOR_EVENT_DELETED:
+ path = gtk_tree_row_reference_get_path (monitor->reference);
+ model = gtk_tree_row_reference_get_model (monitor->reference);
+ gtk_tree_model_get_iter (model, &iter, path);
+ tree_model_iter_free_monitor (model, NULL, &iter, NULL);
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ update_search_counts (gsearch);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+display_dialog_could_not_move_to_trash (GtkWidget * window,
+ const gchar * file,
+ const gchar * message)
+{
+ GtkWidget * dialog;
+ gchar * primary;
+
+ primary = g_strdup_printf (_("Could not move \"%s\" to trash."), file);
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ primary, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ message, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_widget_show (dialog);
+ g_free (primary);
+}
+
+static gint
+display_dialog_delete_permanently (GtkWidget * window,
+ const gchar * file)
+{
+ GtkWidget * dialog;
+ GtkWidget * button;
+ gchar * primary;
+ gchar * secondary;
+ gint response;
+
+ primary = g_strdup_printf (_("Do you want to delete \"%s\" permanently?"),
+ g_path_get_basename (file));
+
+ secondary = g_strdup_printf (_("Trash is unavailable. Could not move \"%s\" to the trash."),
+ file);
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ primary, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ secondary, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ button = gtk_button_new_from_stock ("gtk-delete");
+ gtk_widget_set_can_default (button, TRUE);
+ gtk_widget_show (button);
+
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (GTK_WIDGET(dialog));
+ g_free (primary);
+ g_free (secondary);
+
+ return response;
+}
+
+static void
+display_dialog_could_not_delete (GtkWidget * window,
+ const gchar * file,
+ const gchar * message)
+{
+ GtkWidget * dialog;
+ gchar * primary;
+
+ primary = g_strdup_printf (_("Could not delete \"%s\"."), file);
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ primary, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ message, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_widget_show (dialog);
+ g_free (primary);
+}
+
+void
+move_to_trash_cb (GtkAction * action,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ GtkTreePath * last_selected_path = NULL;
+ gint total;
+ gint idx;
+
+ if (gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection)) == 0) {
+ return;
+ }
+
+ total = gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection));
+
+ for (idx = 0; idx < total; idx++) {
+ gboolean no_files_found = FALSE;
+ GtkTreeModel * model;
+ GtkTreeIter iter;
+ GList * list;
+ GFile * g_file;
+ GError * error = NULL;
+ gchar * utf8_basename;
+ gchar * utf8_filename;
+ gchar * locale_filename;
+ gboolean result;
+
+ list = gtk_tree_selection_get_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ &model);
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ g_list_nth_data (list, 0));
+
+ gtk_tree_model_get (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ COLUMN_NAME, &utf8_basename,
+ COLUMN_LOCALE_FILE, &locale_filename,
+ COLUMN_NO_FILES_FOUND, &no_files_found,
+ -1);
+
+ if (no_files_found) {
+ g_free (utf8_basename);
+ g_free (locale_filename);
+ return;
+ }
+
+ utf8_filename = g_filename_display_name (locale_filename);
+
+ if (idx + 1 == total) {
+ last_selected_path = gtk_tree_model_get_path (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter);
+ }
+
+ if ((!g_file_test (locale_filename, G_FILE_TEST_EXISTS)) &&
+ (!g_file_test (locale_filename, G_FILE_TEST_IS_SYMLINK))) {
+ gtk_tree_selection_unselect_iter (GTK_TREE_SELECTION (gsearch->search_results_selection), &iter);
+ display_dialog_could_not_move_to_trash (gsearch->window, utf8_basename,
+ _("The document does not exist."));
+ }
+
+ g_file = g_file_new_for_path (locale_filename);
+ result = g_file_trash (g_file, NULL, &error);
+
+ gtk_tree_selection_unselect_iter (GTK_TREE_SELECTION (gsearch->search_results_selection), &iter);
+ g_object_unref (g_file);
+
+ if (result == TRUE) {
+ tree_model_iter_free_monitor (GTK_TREE_MODEL (gsearch->search_results_list_store),
+ NULL, &iter, NULL);
+ gtk_list_store_remove (GTK_LIST_STORE (gsearch->search_results_list_store), &iter);
+ }
+ else {
+ gint response;
+
+ gtk_tree_selection_unselect_iter (GTK_TREE_SELECTION (gsearch->search_results_selection), &iter);
+ response = display_dialog_delete_permanently (gsearch->window, utf8_filename);
+
+ if (response == GTK_RESPONSE_OK) {
+ GFile * g_file_tmp;
+ GError * error_tmp = NULL;
+
+ g_file_tmp = g_file_new_for_path (locale_filename);
+ result = g_file_delete (g_file_tmp, NULL, &error_tmp);
+ g_object_unref (g_file_tmp);
+
+ if (result == TRUE) {
+ tree_model_iter_free_monitor (GTK_TREE_MODEL (gsearch->search_results_list_store),
+ NULL, &iter, NULL);
+ gtk_list_store_remove (GTK_LIST_STORE (gsearch->search_results_list_store), &iter);
+ }
+ else {
+ gchar * message;
+
+ message = g_strdup_printf (_("Deleting \"%s\" failed: %s."),
+ utf8_filename, error_tmp->message);
+
+ display_dialog_could_not_delete (gsearch->window, utf8_basename, message);
+
+ g_error_free (error_tmp);
+ g_free (message);
+ }
+ }
+ else {
+ gchar * message;
+
+ message = g_strdup_printf (_("Moving \"%s\" failed: %s."),
+ utf8_filename,
+ error->message);
+ display_dialog_could_not_move_to_trash (gsearch->window, utf8_basename,
+ message);
+ g_error_free (error);
+ g_free (message);
+ }
+ }
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+ g_free (locale_filename);
+ g_free (utf8_filename);
+ g_free (utf8_basename);
+ }
+
+ /* Bugzilla #397945: Select next row in the search results list */
+ if (last_selected_path != NULL) {
+ if (gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection)) == 0) {
+ gtk_tree_selection_select_path (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ last_selected_path);
+ if (gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection)) == 0) {
+ gtk_tree_path_prev (last_selected_path);
+ gtk_tree_selection_select_path (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ last_selected_path);
+ }
+ }
+ gtk_tree_path_free (last_selected_path);
+ }
+
+ if (gsearch->command_details->command_status != RUNNING) {
+ update_search_counts (gsearch);
+ }
+}
+
+gboolean
+file_button_press_event_cb (GtkWidget * widget,
+ GdkEventButton * event,
+ gpointer data)
+{
+ GtkTreeView * tree = data;
+ GtkTreePath * path;
+
+ row_selected_by_button_press_event = TRUE;
+
+ if (event->window != gtk_tree_view_get_bin_window (tree)) {
+ return FALSE;
+ }
+
+ if (gtk_tree_view_get_path_at_pos (tree, event->x, event->y,
+ &path, NULL, NULL, NULL)) {
+
+ if ((event->button == 1 || event->button == 2 || event->button == 3)
+ && gtk_tree_selection_path_is_selected (gtk_tree_view_get_selection (tree), path)) {
+ row_selected_by_button_press_event = FALSE;
+ }
+ gtk_tree_path_free (path);
+ }
+ else {
+ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (tree));
+ }
+
+ return !(row_selected_by_button_press_event);
+}
+
+gboolean
+file_key_press_event_cb (GtkWidget * widget,
+ GdkEventKey * event,
+ gpointer data)
+{
+ if (event->keyval == GDK_KEY_space ||
+ event->keyval == GDK_KEY_Return ||
+ event->keyval == GDK_KEY_KP_Enter) {
+ if (event->state != GDK_CONTROL_MASK) {
+ open_file_cb ((GtkMenuItem *) NULL, data);
+ return TRUE;
+ }
+ }
+ else if (event->keyval == GDK_KEY_Delete) {
+ move_to_trash_cb ((GtkAction *) NULL, data);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gint
+open_with_list_sort (gconstpointer a,
+ gconstpointer b)
+{
+ const gchar * a_app_name = g_app_info_get_name ((GAppInfo *) a);
+ const gchar * b_app_name = g_app_info_get_name ((GAppInfo *) b);
+ gchar * a_utf8;
+ gchar * b_utf8;
+ gint result;
+
+ a_utf8 = g_utf8_casefold (a_app_name, -1);
+ b_utf8 = g_utf8_casefold (b_app_name, -1);
+
+ result = g_utf8_collate (a_utf8, b_utf8);
+
+ g_free (a_utf8);
+ g_free (b_utf8);
+
+ return result;
+}
+
+static void
+build_popup_menu_for_file (GSearchWindow * gsearch,
+ gchar * file)
+{
+ GtkWidget * new1, * image1, * separatormenuitem1;
+ GtkWidget * new2;
+ gint i;
+
+ if (GTK_IS_MENU (gsearch->search_results_popup_menu) == TRUE) {
+ g_object_ref_sink (gsearch->search_results_popup_menu);
+ g_object_unref (gsearch->search_results_popup_menu);
+ }
+
+ if (GTK_IS_MENU (gsearch->search_results_popup_submenu) == TRUE) {
+ g_object_ref_sink (gsearch->search_results_popup_submenu);
+ g_object_unref (gsearch->search_results_popup_submenu);
+ }
+
+ gsearch->search_results_popup_menu = gtk_menu_new ();
+
+ if (file == NULL || g_file_test (file, G_FILE_TEST_IS_DIR) == TRUE) {
+ /* Popup menu item: Open */
+ new1 = gtk_image_menu_item_new_with_mnemonic (_("_Open"));
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), new1);
+ gtk_widget_show (new1);
+
+ image1 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (new1), image1);
+ gtk_widget_show (image1);
+
+ g_signal_connect (G_OBJECT (new1),
+ "activate",
+ G_CALLBACK (open_file_cb),
+ (gpointer) gsearch);
+ }
+ else {
+ GFile * g_file;
+ GFileInfo * file_info;
+ GIcon * file_icon;
+ GList * list;
+ gchar * str;
+ gint list_length;
+
+ g_file = g_file_new_for_path (file);
+ file_info = g_file_query_info (g_file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ list = g_app_info_get_all_for_type (g_file_info_get_content_type (file_info));
+
+ list_length = g_list_length (list);
+
+ if (list_length <= 0) {
+
+ /* Popup menu item: Open */
+ new1 = gtk_image_menu_item_new_with_mnemonic (_("_Open"));
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), new1);
+ gtk_widget_show (new1);
+
+ image1 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (new1), image1);
+ gtk_widget_show (image1);
+
+ g_signal_connect (G_OBJECT (new1),
+ "activate",
+ G_CALLBACK (open_file_cb),
+ (gpointer) gsearch);
+ }
+ else {
+ if (list_length >= 3) { /* Sort all except first application by name */
+ GList * tmp;
+
+ tmp = g_list_first (list);
+ list = g_list_remove_link (list, tmp);
+ list = g_list_sort (list, open_with_list_sort);
+ list = g_list_prepend (list, tmp->data);
+ g_list_free (tmp);
+ }
+
+ /* Popup menu item: Open with (default) */
+ str = g_strdup_printf (_("_Open with %s"), g_app_info_get_name (list->data));
+ new1 = gtk_image_menu_item_new_with_mnemonic (str);
+ g_free (str);
+ gtk_widget_show (new1);
+
+ g_object_set_data_full (G_OBJECT (new1), "app", (GAppInfo *)list->data,
+ (GDestroyNotify) g_object_unref);
+
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), new1);
+ g_signal_connect ((gpointer) new1, "activate", G_CALLBACK (open_file_cb),
+ (gpointer) gsearch);
+
+ if (g_app_info_get_icon ((GAppInfo *)list->data) != NULL) {
+ file_icon = g_object_ref (g_app_info_get_icon ((GAppInfo *)list->data));
+ gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (new1), file_icon != NULL);
+
+ if (file_icon == NULL) {
+ file_icon = g_themed_icon_new (GTK_STOCK_OPEN);
+ }
+
+ image1 = gtk_image_new_from_gicon (file_icon, GTK_ICON_SIZE_MENU);
+ g_object_unref (file_icon);
+ gtk_widget_show (image1);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (new1), image1);
+ }
+
+ separatormenuitem1 = gtk_separator_menu_item_new ();
+ gtk_widget_show (separatormenuitem1);
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), separatormenuitem1);
+ gtk_widget_set_sensitive (separatormenuitem1, FALSE);
+
+ for (list = g_list_next (list), i = 0; list != NULL; list = g_list_next (list), i++) {
+
+ /* Popup menu item: Open with (others) */
+ if (list_length < 4) {
+ str = g_strdup_printf (_("Open with %s"), g_app_info_get_name (list->data));
+ }
+ else {
+ str = g_strdup_printf ("%s", g_app_info_get_name (list->data));
+ }
+
+ new1 = gtk_image_menu_item_new_with_mnemonic (str);
+ g_free (str);
+ gtk_widget_show (new1);
+
+ g_object_set_data_full (G_OBJECT (new1), "app", (GAppInfo *)list->data,
+ (GDestroyNotify) g_object_unref);
+
+ if (list_length >= 4) {
+
+ if (g_app_info_get_icon ((GAppInfo *)list->data) != NULL) {
+ file_icon = g_object_ref (g_app_info_get_icon ((GAppInfo *)list->data));
+ gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (new1), file_icon != NULL);
+
+ if (file_icon == NULL) {
+ file_icon = g_themed_icon_new (GTK_STOCK_OPEN);
+ }
+
+ image1 = gtk_image_new_from_gicon (file_icon, GTK_ICON_SIZE_MENU);
+ g_object_unref (file_icon);
+ gtk_widget_show (image1);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (new1), image1);
+ }
+
+ if (i == 0) {
+ gsearch->search_results_popup_submenu = gtk_menu_new ();
+
+ /* Popup menu item: Open With */
+ new2 = gtk_menu_item_new_with_mnemonic (_("Open Wit_h"));
+ gtk_widget_show (new2);
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), new2);
+
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (new2), gsearch->search_results_popup_submenu);
+ }
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_submenu), new1);
+
+ /* For submenu items, the "activate" signal is only emitted if the user first clicks
+ on the parent menu item. Since submenus in gtk+ are automatically displayed when
+ the user hovers over them, most will never click on the parent menu item.
+ The work-around is to connect to "button-press-event". */
+ g_signal_connect (G_OBJECT(new1), "button-press-event", G_CALLBACK (open_file_event_cb),
+ (gpointer) gsearch);
+ }
+ else {
+ if (g_app_info_get_icon ((GAppInfo *)list->data) != NULL) {
+
+ file_icon = g_object_ref (g_app_info_get_icon ((GAppInfo *)list->data));
+ gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (new1), file_icon != NULL);
+
+ if (file_icon == NULL) {
+ file_icon = g_themed_icon_new (GTK_STOCK_OPEN);
+ }
+
+ image1 = gtk_image_new_from_gicon (file_icon, GTK_ICON_SIZE_MENU);
+ g_object_unref (file_icon);
+ gtk_widget_show (image1);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (new1), image1);
+ }
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), new1);
+ g_signal_connect ((gpointer) new1, "activate", G_CALLBACK (open_file_cb),
+ (gpointer) gsearch);
+ }
+ }
+
+ if (list_length >= 2) {
+ separatormenuitem1 = gtk_separator_menu_item_new ();
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), separatormenuitem1);
+ gtk_widget_show (separatormenuitem1);
+ }
+ }
+ }
+
+ /* Popup menu item: Open Containing Folder */
+ new1 = gtk_image_menu_item_new_with_mnemonic (_("Open Containing _Folder"));
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), new1);
+ gtk_widget_show (new1);
+
+ image1 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (new1), image1);
+ gtk_widget_show (image1);
+
+ g_signal_connect (G_OBJECT (new1),
+ "activate",
+ G_CALLBACK (open_folder_cb),
+ (gpointer) gsearch);
+
+ /* Popup menu item: Move to Trash */
+ separatormenuitem1 = gtk_separator_menu_item_new ();
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), separatormenuitem1);
+ gtk_widget_show (separatormenuitem1);
+
+ new1 = gtk_image_menu_item_new_with_mnemonic (_("Mo_ve to Trash"));
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), new1);
+ gtk_widget_show (new1);
+
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *pixbuf;
+ icon_theme = gtk_icon_theme_get_default ();
+ pixbuf = gtk_icon_theme_load_icon (icon_theme, "user-trash", GTK_ICON_SIZE_MENU, 0, NULL);
+ image1 = gtk_image_new_from_pixbuf (pixbuf);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (new1), image1);
+ gtk_widget_show (image1);
+
+ g_signal_connect (G_OBJECT (new1),
+ "activate",
+ G_CALLBACK (move_to_trash_cb),
+ (gpointer) gsearch);
+
+ /* Popup menu item: Save Results As... */
+ separatormenuitem1 = gtk_separator_menu_item_new ();
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), separatormenuitem1);
+ gtk_widget_show (separatormenuitem1);
+
+ gsearch->search_results_save_results_as_item = gtk_image_menu_item_new_with_mnemonic (_("_Save Results As..."));
+ gtk_container_add (GTK_CONTAINER (gsearch->search_results_popup_menu), gsearch->search_results_save_results_as_item);
+ gtk_widget_show (gsearch->search_results_save_results_as_item);
+
+ if (gsearch->command_details->command_status == RUNNING) {
+ gtk_widget_set_sensitive (gsearch->search_results_save_results_as_item, FALSE);
+ }
+
+ image1 = gtk_image_new_from_stock ("gtk-save", GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (gsearch->search_results_save_results_as_item), image1);
+ gtk_widget_show (image1);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_save_results_as_item),
+ "activate",
+ G_CALLBACK (show_file_selector_cb),
+ (gpointer) gsearch);
+}
+
+gboolean
+file_button_release_event_cb (GtkWidget * widget,
+ GdkEventButton * event,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (gsearch->search_results_tree_view))) {
+ return FALSE;
+ }
+
+ if (event->button == 1 || event->button == 2) {
+ GtkTreePath *path;
+
+ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (gsearch->search_results_tree_view), event->x, event->y,
+ &path, NULL, NULL, NULL)) {
+ if ((event->state & GDK_SHIFT_MASK) || (event->state & GDK_CONTROL_MASK)) {
+ if (row_selected_by_button_press_event) {
+ gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW(gsearch->search_results_tree_view)), path);
+ }
+ else {
+ gtk_tree_selection_unselect_path (gtk_tree_view_get_selection (GTK_TREE_VIEW(gsearch->search_results_tree_view)), path);
+ }
+ }
+ else {
+ if (gsearch->is_search_results_single_click_to_activate == FALSE) {
+ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW(gsearch->search_results_tree_view)));
+ }
+ gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW(gsearch->search_results_tree_view)), path);
+ }
+ }
+ gtk_tree_path_free (path);
+ }
+
+ if (gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection)) == 0) {
+ return FALSE;
+ }
+
+ if (event->button == 3) {
+ gboolean no_files_found = FALSE;
+ GtkTreeModel * model;
+ GtkTreeIter iter;
+ GList * list;
+ gchar * utf8_name_first;
+ gchar * locale_file_first;
+
+ list = gtk_tree_selection_get_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ &model);
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ g_list_first (list)->data);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ COLUMN_NAME, &utf8_name_first,
+ COLUMN_LOCALE_FILE, &locale_file_first,
+ COLUMN_NO_FILES_FOUND, &no_files_found,
+ -1);
+
+ if (!no_files_found) {
+
+ gboolean show_app_list = TRUE;
+ GAppInfo * first_app_info = NULL;
+ GTimer * timer;
+ GList * tmp;
+ gchar * locale_file_tmp;
+ gchar * file = NULL;
+ gint idx;
+
+ timer = g_timer_new ();
+ g_timer_start (timer);
+
+ if (g_list_length (list) >= 2) {
+
+ /* Verify the selected files each have the same default handler. */
+ for (tmp = g_list_first (list), idx = 0; tmp != NULL; tmp = g_list_next (tmp), idx++) {
+
+ GFile * g_file;
+ GAppInfo * app_info;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ tmp->data);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ COLUMN_LOCALE_FILE, &locale_file_tmp,
+ -1);
+
+ g_file = g_file_new_for_path (locale_file_tmp);
+ app_info = g_file_query_default_handler (g_file, NULL, NULL);
+
+ if (G_IS_APP_INFO (app_info) == FALSE) {
+ show_app_list = FALSE;
+ }
+ else {
+ if (idx == 0) {
+ first_app_info = g_app_info_dup (app_info);
+ g_object_unref (app_info);
+ continue;
+ }
+
+ show_app_list = g_app_info_equal (app_info, first_app_info);
+ g_object_unref (app_info);
+
+ /* Break out, if more that 1.5 seconds have passed */
+ if (g_timer_elapsed (timer, NULL) > 1.50) {
+ show_app_list = FALSE;
+ }
+ }
+ g_object_unref (g_file);
+ g_free (locale_file_tmp);
+
+ if (show_app_list == FALSE) {
+ break;
+ }
+ }
+ g_timer_destroy (timer);
+ if (first_app_info != NULL) {
+ g_object_unref (first_app_info);
+ }
+ }
+
+ file = g_strdup (((show_app_list == TRUE) ? locale_file_first : NULL));
+
+ build_popup_menu_for_file (gsearch, file);
+ gtk_menu_popup (GTK_MENU (gsearch->search_results_popup_menu), NULL, NULL, NULL, NULL,
+ event->button, event->time);
+ g_free (file);
+
+ }
+ g_free (locale_file_first);
+ g_free (utf8_name_first);
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+ }
+ else if (event->button == 1 || event->button == 2) {
+ if (gsearch->is_search_results_single_click_to_activate == TRUE) {
+ if (!(event->state & GDK_CONTROL_MASK) && !(event->state & GDK_SHIFT_MASK)) {
+ open_file_cb ((GtkMenuItem *) NULL, data);
+ }
+ }
+ }
+ return FALSE;
+}
+
+gboolean
+file_event_after_cb (GtkWidget * widget,
+ GdkEventButton * event,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (gsearch->search_results_tree_view))) {
+ return FALSE;
+ }
+
+ if (gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection)) == 0) {
+ return FALSE;
+ }
+
+ if (!(event->state & GDK_CONTROL_MASK) && !(event->state & GDK_SHIFT_MASK)) {
+ if (gsearch->is_search_results_single_click_to_activate == FALSE) {
+ if (event->type == GDK_2BUTTON_PRESS) {
+ open_file_cb ((GtkMenuItem *) NULL, data);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+gboolean
+file_motion_notify_cb (GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer user_data)
+{
+ GSearchWindow * gsearch = user_data;
+ GdkCursor * cursor;
+ GtkTreePath * last_hover_path;
+ GtkTreeIter iter;
+
+ if (gsearch->is_search_results_single_click_to_activate == FALSE) {
+ return FALSE;
+ }
+
+ if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (gsearch->search_results_tree_view))) {
+ return FALSE;
+ }
+
+ last_hover_path = gsearch->search_results_hover_path;
+
+ gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
+ event->x, event->y,
+ &gsearch->search_results_hover_path,
+ NULL, NULL, NULL);
+
+ if (gsearch->search_results_hover_path != NULL) {
+ cursor = gdk_cursor_new (GDK_HAND2);
+ }
+ else {
+ cursor = NULL;
+ }
+
+ gdk_window_set_cursor (event->window, cursor);
+
+ /* Redraw if the hover row has changed */
+ if (!(last_hover_path == NULL && gsearch->search_results_hover_path == NULL) &&
+ (!(last_hover_path != NULL && gsearch->search_results_hover_path != NULL) ||
+ gtk_tree_path_compare (last_hover_path, gsearch->search_results_hover_path))) {
+ if (last_hover_path) {
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store),
+ &iter, last_hover_path);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (gsearch->search_results_list_store),
+ last_hover_path, &iter);
+ }
+
+ if (gsearch->search_results_hover_path) {
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store),
+ &iter, gsearch->search_results_hover_path);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (gsearch->search_results_list_store),
+ gsearch->search_results_hover_path, &iter);
+ }
+ }
+
+ gtk_tree_path_free (last_hover_path);
+
+ return FALSE;
+}
+
+gboolean
+file_leave_notify_cb (GtkWidget *widget,
+ GdkEventCrossing *event,
+ gpointer user_data)
+{
+ GSearchWindow * gsearch = user_data;
+ GtkTreeIter iter;
+
+ if (gsearch->is_search_results_single_click_to_activate && (gsearch->search_results_hover_path != NULL)) {
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store),
+ &iter,
+ gsearch->search_results_hover_path);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (gsearch->search_results_list_store),
+ gsearch->search_results_hover_path,
+ &iter);
+
+ gtk_tree_path_free (gsearch->search_results_hover_path);
+ gsearch->search_results_hover_path = NULL;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+drag_begin_file_cb (GtkWidget * widget,
+ GdkDragContext * context,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ gint number_of_selected_rows;
+
+ number_of_selected_rows = gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection));
+
+ if (number_of_selected_rows > 1) {
+ gtk_drag_set_icon_stock (context, GTK_STOCK_DND_MULTIPLE, 0, 0);
+ }
+ else if (number_of_selected_rows == 1) {
+ GdkPixbuf * pixbuf;
+ GtkTreeModel * model;
+ GtkTreeIter iter;
+ GList * list;
+
+ list = gtk_tree_selection_get_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ &model);
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ g_list_first (list)->data);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ COLUMN_ICON, &pixbuf,
+ -1);
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+
+ if (pixbuf) {
+ gtk_drag_set_icon_pixbuf (context, pixbuf, 0, 0);
+ }
+ else {
+ gtk_drag_set_icon_stock (context, GTK_STOCK_DND, 0, 0);
+ }
+ }
+}
+
+void
+drag_file_cb (GtkWidget * widget,
+ GdkDragContext * context,
+ GtkSelectionData * selection_data,
+ guint info,
+ guint drag_time,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ gchar * uri_list = NULL;
+ GList * list;
+ GtkTreeModel * model;
+ GtkTreeIter iter;
+ guint idx;
+
+ if (gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection)) == 0) {
+ return;
+ }
+
+ list = gtk_tree_selection_get_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ &model);
+
+ for (idx = 0; idx < g_list_length (list); idx++) {
+
+ gboolean no_files_found = FALSE;
+ gchar * utf8_name;
+ gchar * locale_file;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ g_list_nth_data (list, idx));
+
+ gtk_tree_model_get (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ COLUMN_NAME, &utf8_name,
+ COLUMN_LOCALE_FILE, &locale_file,
+ COLUMN_NO_FILES_FOUND, &no_files_found,
+ -1);
+
+ if (!no_files_found) {
+ gchar * tmp_uri = g_filename_to_uri (locale_file, NULL, NULL);
+
+ if (uri_list == NULL) {
+ uri_list = g_strdup (tmp_uri);
+ }
+ else {
+ uri_list = g_strconcat (uri_list, "\n", tmp_uri, NULL);
+ }
+ gtk_selection_data_set (selection_data,
+ gtk_selection_data_get_target (selection_data),
+ 8,
+ (guchar *) uri_list,
+ strlen (uri_list));
+ g_free (tmp_uri);
+ }
+ else {
+ gtk_selection_data_set_text (selection_data, utf8_name, -1);
+ }
+ g_free (utf8_name);
+ g_free (locale_file);
+ }
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+ g_free (uri_list);
+}
+
+
+void
+show_file_selector_cb (GtkAction * action,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ GtkWidget * file_chooser;
+
+ file_chooser = gtk_file_chooser_dialog_new (_("Save Search Results As..."),
+ GTK_WINDOW (gsearch->window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (file_chooser), TRUE);
+ if (gsearch->save_results_as_default_filename != NULL) {
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (file_chooser),
+ gsearch->save_results_as_default_filename);
+ }
+
+ g_signal_connect (G_OBJECT (file_chooser), "response",
+ G_CALLBACK (save_results_cb), gsearch);
+
+ gtk_window_set_modal (GTK_WINDOW (file_chooser), TRUE);
+ gtk_window_set_position (GTK_WINDOW (file_chooser), GTK_WIN_POS_CENTER_ON_PARENT);
+
+ gtk_widget_show (GTK_WIDGET (file_chooser));
+}
+
+static void
+display_dialog_could_not_save_no_name (GtkWidget * window)
+{
+ GtkWidget * dialog;
+ gchar * primary;
+ gchar * secondary;
+
+ primary = g_strdup (_("Could not save document."));
+ secondary = g_strdup (_("You did not select a document name."));
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ primary, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ secondary, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_widget_show (dialog);
+ g_free (primary);
+ g_free (secondary);
+}
+
+static void
+display_dialog_could_not_save_to (GtkWidget * window,
+ const gchar * file,
+ const gchar * message)
+{
+ GtkWidget * dialog;
+ gchar * primary;
+
+ primary = g_strdup_printf (_("Could not save \"%s\" document to \"%s\"."),
+ g_path_get_basename (file),
+ g_path_get_dirname (file));
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ primary, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ message, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_widget_show (dialog);
+ g_free (primary);
+}
+
+static gint
+display_dialog_could_not_save_exists (GtkWidget * window,
+ const gchar * file)
+{
+ GtkWidget * dialog;
+ GtkWidget * button;
+ gchar * primary;
+ gchar * secondary;
+ gint response;
+
+ primary = g_strdup_printf (_("The document \"%s\" already exists. "
+ "Would you like to replace it?"),
+ g_path_get_basename (file));
+
+ secondary = g_strdup (_("If you replace an existing file, "
+ "its contents will be overwritten."));
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ "%s", primary);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", secondary);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ button = gsearchtool_button_new_with_stock_icon (_("_Replace"), GTK_STOCK_OK);
+ gtk_widget_set_can_default (button, TRUE);
+ gtk_widget_show (button);
+
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (GTK_WIDGET(dialog));
+ g_free (primary);
+ g_free (secondary);
+
+ return response;
+}
+
+void
+save_results_cb (GtkWidget * chooser,
+ gint response,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ GtkListStore * store;
+ GtkTreeIter iter;
+ FILE * fp;
+ gchar * utf8 = NULL;
+
+ if (response != GTK_RESPONSE_OK) {
+ gtk_widget_destroy (GTK_WIDGET (chooser));
+ return;
+ }
+
+ store = gsearch->search_results_list_store;
+ g_free (gsearch->save_results_as_default_filename);
+
+ gsearch->save_results_as_default_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
+ gtk_widget_destroy (chooser);
+
+ if (gsearch->save_results_as_default_filename != NULL) {
+ utf8 = g_filename_to_utf8 (gsearch->save_results_as_default_filename, -1, NULL, NULL, NULL);
+ }
+
+ if (utf8 == NULL) {
+ display_dialog_could_not_save_no_name (gsearch->window);
+ return;
+ }
+
+ if (g_file_test (gsearch->save_results_as_default_filename, G_FILE_TEST_IS_DIR)) {
+ display_dialog_could_not_save_to (gsearch->window, utf8,
+ _("The document name you selected is a folder."));
+ g_free (utf8);
+ return;
+ }
+
+ if (g_file_test (gsearch->save_results_as_default_filename, G_FILE_TEST_EXISTS)) {
+
+ gint response;
+
+ response = display_dialog_could_not_save_exists (gsearch->window, utf8);
+
+ if (response != GTK_RESPONSE_OK) {
+ g_free (utf8);
+ return;
+ }
+ }
+
+ if ((fp = fopen (gsearch->save_results_as_default_filename, "w")) != NULL) {
+
+ gint idx;
+
+ for (idx = 0; idx < gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL); idx++)
+ {
+ if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, NULL, idx) == TRUE) {
+
+ gchar * locale_file;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, COLUMN_LOCALE_FILE, &locale_file, -1);
+ fprintf (fp, "%s\n", locale_file);
+ g_free (locale_file);
+ }
+ }
+ fclose (fp);
+ }
+ else {
+ display_dialog_could_not_save_to (gsearch->window, utf8,
+ _("You may not have write permissions to the document."));
+ }
+ g_free (utf8);
+}
+
+void
+save_session_cb (EggSMClient * client,
+ GKeyFile * state_file,
+ gpointer client_data)
+{
+ GSearchWindow * gsearch = client_data;
+ char ** argv;
+ int argc;
+
+ set_clone_command (gsearch, &argc, &argv, "mate-search-tool", FALSE);
+ egg_sm_client_set_restart_command (client, argc, (const char **) argv);
+}
+
+gboolean
+key_press_cb (GtkWidget * widget,
+ GdkEventKey * event,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ if (event->keyval == GDK_KEY_Escape) {
+ if (gsearch->command_details->command_status == RUNNING) {
+ click_stop_cb (widget, data);
+ }
+ else if (gsearch->command_details->is_command_timeout_enabled == FALSE) {
+ quit_cb (widget, (GdkEvent *) NULL, data);
+ }
+ }
+ else if (event->keyval == GDK_KEY_F10) {
+ if (event->state & GDK_SHIFT_MASK) {
+ gboolean no_files_found = FALSE;
+ GtkTreeModel * model;
+ GtkTreeIter iter;
+ GList * list;
+
+ if (gtk_tree_selection_count_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection)) == 0) {
+ return FALSE;
+ }
+
+ list = gtk_tree_selection_get_selected_rows (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ &model);
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ g_list_first (list)->data);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (gsearch->search_results_list_store), &iter,
+ COLUMN_NO_FILES_FOUND, &no_files_found, -1);
+
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+
+ if (!no_files_found) {
+ gtk_menu_popup (GTK_MENU (gsearch->search_results_popup_menu), NULL, NULL, NULL, NULL,
+ event->keyval, event->time);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+gboolean
+not_running_timeout_cb (gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ gsearch->command_details->is_command_timeout_enabled = FALSE;
+ return FALSE;
+}
+
+void
+disable_quick_search_cb (GtkWidget * dialog,
+ gint response,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+
+ if (response == GTK_RESPONSE_OK) {
+ g_settings_set_boolean (gsearch->mate_search_tool_settings, "disable-quick-search", TRUE);
+ }
+}
+
+void
+single_click_to_activate_key_changed_cb (GSettings * settings,
+ gchar * key,
+ gpointer user_data)
+{
+ GSearchWindow * gsearch = user_data;
+ gchar * value;
+
+ value = g_settings_get_string (settings, key);
+
+ gsearch->is_search_results_single_click_to_activate =
+ (strncmp (value, "single", 6) == 0) ? TRUE : FALSE;
+
+ g_free (value);
+}
+
+void
+columns_changed_cb (GtkTreeView * treeview,
+ gpointer user_data)
+{
+ GVariantBuilder array_builder;
+ GSearchWindow * gsearch = user_data;
+ GSList * order;
+ GSList * iter;
+
+ order = gsearchtool_get_columns_order (treeview);
+
+ g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("ai"));
+ for (iter = order; iter; iter = iter->next)
+ g_variant_builder_add (&array_builder, "i", GPOINTER_TO_INT (iter->data));
+
+ if (g_slist_length (order) == NUM_VISIBLE_COLUMNS) {
+ g_settings_set_value (gsearch->mate_search_tool_settings, "columns-order", g_variant_new ("ai", &array_builder));
+ }
+ g_slist_free (order);
+}
+
+gboolean
+window_state_event_cb (GtkWidget * widget,
+ GdkEventWindowState * event,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+
+ if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
+ gsearch->is_window_maximized = TRUE;
+ }
+ else {
+ gsearch->is_window_maximized = FALSE;
+ }
+ return FALSE;
+}
diff --git a/gsearchtool/src/gsearchtool-callbacks.h b/gsearchtool/src/gsearchtool-callbacks.h
new file mode 100644
index 00000000..b9db03a2
--- /dev/null
+++ b/gsearchtool/src/gsearchtool-callbacks.h
@@ -0,0 +1,180 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * MATE Search Tool
+ *
+ * File: gsearchtool-callbacks.h
+ *
+ * (C) 2002 the Free Software Foundation
+ *
+ * Authors: Dennis Cranston <[email protected]>
+ * George Lebl
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _GSEARCHTOOL_CALLBACKS_H_
+#define _GSEARCHTOOL_CALLBACKS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif
+
+#include "eggsmclient.h"
+
+void
+version_cb (const gchar * option_name,
+ const gchar * value,
+ gpointer data,
+ GError ** error);
+void
+quit_session_cb (EggSMClient * client,
+ gpointer data);
+void
+quit_cb (GtkWidget * widget,
+ GdkEvent * event,
+ gpointer data);
+void
+click_close_cb (GtkWidget * widget,
+ gpointer data);
+void
+click_find_cb (GtkWidget * widget,
+ gpointer data);
+void
+click_stop_cb (GtkWidget * widget,
+ gpointer data);
+void
+click_help_cb (GtkWidget * widget,
+ gpointer data);
+void
+click_expander_cb (GObject * object,
+ GParamSpec * param_spec,
+ gpointer data);
+void
+size_allocate_cb (GtkWidget * widget,
+ GtkAllocation * allocation,
+ gpointer data);
+void
+add_constraint_cb (GtkWidget * widget,
+ gpointer data);
+void
+remove_constraint_cb (GtkWidget * widget,
+ gpointer data);
+void
+constraint_activate_cb (GtkWidget * widget,
+ gpointer data);
+void
+constraint_update_info_cb (GtkWidget * widget,
+ gpointer data);
+void
+name_contains_activate_cb (GtkWidget * widget,
+ gpointer data);
+void
+look_in_folder_changed_cb (GtkWidget * widget,
+ gpointer data);
+void
+open_file_cb (GtkMenuItem * action,
+ gpointer data);
+void
+open_file_event_cb (GtkWidget * widget,
+ GdkEventButton * event,
+ gpointer data);
+void
+open_folder_cb (GtkAction * action,
+ gpointer data);
+void
+file_changed_cb (GFileMonitor * handle,
+ const gchar * monitor_uri,
+ const gchar * info_uri,
+ GFileMonitorEvent event_type,
+ gpointer data);
+void
+move_to_trash_cb (GtkAction * action,
+ gpointer data);
+void
+drag_begin_file_cb (GtkWidget * widget,
+ GdkDragContext * context,
+ gpointer data);
+void
+drag_file_cb (GtkWidget * widget,
+ GdkDragContext * context,
+ GtkSelectionData * selection_data,
+ guint info,
+ guint time,
+ gpointer data);
+void
+show_file_selector_cb (GtkAction * action,
+ gpointer data);
+void
+save_results_cb (GtkWidget * chooser,
+ gint response,
+ gpointer data);
+void
+save_session_cb (EggSMClient * client,
+ GKeyFile * state_file,
+ gpointer client_data);
+gboolean
+key_press_cb (GtkWidget * widget,
+ GdkEventKey * event,
+ gpointer data);
+gboolean
+file_button_release_event_cb (GtkWidget * widget,
+ GdkEventButton * event,
+ gpointer data);
+gboolean
+file_event_after_cb (GtkWidget * widget,
+ GdkEventButton * event,
+ gpointer data);
+gboolean
+file_button_press_event_cb (GtkWidget * widget,
+ GdkEventButton * event,
+ gpointer data);
+gboolean
+file_key_press_event_cb (GtkWidget * widget,
+ GdkEventKey * event,
+ gpointer data);
+gboolean
+file_motion_notify_cb (GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer user_data);
+gboolean
+file_leave_notify_cb (GtkWidget *widget,
+ GdkEventCrossing *event,
+ gpointer user_data);
+gboolean
+not_running_timeout_cb (gpointer data);
+
+void
+disable_quick_search_cb (GtkWidget * dialog,
+ gint response,
+ gpointer data);
+void
+single_click_to_activate_key_changed_cb (GSettings * settings,
+ gchar * key,
+ gpointer user_data);
+void
+columns_changed_cb (GtkTreeView * treeview,
+ gpointer user_data);
+gboolean
+window_state_event_cb (GtkWidget * widget,
+ GdkEventWindowState * event,
+ gpointer data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GSEARCHTOOL_CALLBACKS_H_ */
diff --git a/gsearchtool/src/gsearchtool-support.c b/gsearchtool/src/gsearchtool-support.c
new file mode 100644
index 00000000..a120967b
--- /dev/null
+++ b/gsearchtool/src/gsearchtool-support.c
@@ -0,0 +1,1588 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * MATE Search Tool
+ *
+ * File: gsearchtool-support.c
+ *
+ * (C) 2002 the Free Software Foundation
+ *
+ * Authors: Dennis Cranston <[email protected]>
+ * George Lebl
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <glib.h>
+#include <regex.h>
+#include <stdlib.h>
+#include <gdk/gdkx.h>
+#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
+
+#include "gsearchtool.h"
+#include "gsearchtool-callbacks.h"
+#include "gsearchtool-support.h"
+
+#define C_STANDARD_STRFTIME_CHARACTERS "aAbBcdHIjmMpSUwWxXyYZ"
+#define C_STANDARD_NUMERIC_STRFTIME_CHARACTERS "dHIjmMSUwWyY"
+#define SUS_EXTENDED_STRFTIME_MODIFIERS "EO"
+#define BINARY_EXEC_MIME_TYPE "application/x-executable"
+
+GtkTreeViewColumn *
+gsearchtool_gtk_tree_view_get_column_with_sort_column_id (GtkTreeView * treeview,
+ gint id);
+
+/* START OF GENERIC MATE-SEARCH-TOOL FUNCTIONS */
+
+gboolean
+is_path_hidden (const gchar * path)
+{
+ gint results = FALSE;
+ gchar * sub_str;
+ gchar * hidden_path_substr = g_strconcat (G_DIR_SEPARATOR_S, ".", NULL);
+
+ sub_str = g_strstr_len (path, strlen (path), hidden_path_substr);
+
+ if (sub_str != NULL) {
+ gchar * mate_desktop_str;
+
+ mate_desktop_str = g_strconcat (G_DIR_SEPARATOR_S, ".mate-desktop", G_DIR_SEPARATOR_S, NULL);
+
+ /* exclude the .mate-desktop folder */
+ if (strncmp (sub_str, mate_desktop_str, strlen (mate_desktop_str)) == 0) {
+ sub_str++;
+ results = (g_strstr_len (sub_str, strlen (sub_str), hidden_path_substr) != NULL);
+ }
+ else {
+ results = TRUE;
+ }
+
+ g_free (mate_desktop_str);
+ }
+
+ g_free (hidden_path_substr);
+ return results;
+}
+
+gboolean
+is_quick_search_excluded_path (const gchar * path)
+{
+ GSettings * settings;
+ gchar ** exclude_path_list;
+ gchar * dir;
+ gboolean results = FALSE;
+ gint i;
+
+ dir = g_strdup (path);
+
+ /* Remove trailing G_DIR_SEPARATOR. */
+ if ((strlen (dir) > 1) && (g_str_has_suffix (dir, G_DIR_SEPARATOR_S) == TRUE)) {
+ dir[strlen (dir) - 1] = '\0';
+ }
+
+ /* Always exclude a path that is symbolic link. */
+ if (g_file_test (dir, G_FILE_TEST_IS_SYMLINK)) {
+ g_free (dir);
+
+ return TRUE;
+ }
+ g_free (dir);
+
+ settings = g_settings_new ("org.mate.search-tool");
+
+ /* Check path against the Quick-Search-Excluded-Paths list. */
+ exclude_path_list = g_settings_get_strv (settings, "quick-search-excluded-paths");
+
+ if (exclude_path_list) {
+ for (i = 0; exclude_path_list[i]; i++) {
+
+ /* Skip empty or null values. */
+ if (strlen (exclude_path_list[i]) == 0) {
+ continue;
+ }
+
+ dir = g_strdup (exclude_path_list[i]);
+
+ /* Wild-card comparisons. */
+ if (g_strstr_len (dir, strlen (dir), "*") != NULL) {
+
+ if (g_pattern_match_simple (dir, path) == TRUE) {
+
+ results = TRUE;
+ g_free (dir);
+ break;
+ }
+ }
+ /* Non-wild-card comparisons. */
+ else {
+ /* Add a trailing G_DIR_SEPARATOR. */
+ if (g_str_has_suffix (dir, G_DIR_SEPARATOR_S) == FALSE) {
+
+ gchar *tmp;
+
+ tmp = dir;
+ dir = g_strconcat (dir, G_DIR_SEPARATOR_S, NULL);
+ g_free (tmp);
+ }
+
+ if (strcmp (path, dir) == 0) {
+
+ results = TRUE;
+ g_free (dir);
+ break;
+ }
+ }
+ g_free (dir);
+ }
+ g_strfreev (exclude_path_list);
+ }
+
+ g_object_unref (settings);
+ return results;
+}
+
+gboolean
+is_second_scan_excluded_path (const gchar * path)
+{
+ GSettings * settings;
+ gchar ** exclude_path_list;
+ gchar * dir;
+ gboolean results = FALSE;
+ gint i;
+
+ dir = g_strdup (path);
+
+ /* Remove trailing G_DIR_SEPARATOR. */
+ if ((strlen (dir) > 1) && (g_str_has_suffix (dir, G_DIR_SEPARATOR_S) == TRUE)) {
+ dir[strlen (dir) - 1] = '\0';
+ }
+
+ /* Always exclude a path that is symbolic link. */
+ if (g_file_test (dir, G_FILE_TEST_IS_SYMLINK)) {
+ g_free (dir);
+
+ return TRUE;
+ }
+ g_free (dir);
+
+ settings = g_settings_new ("org.mate.search-tool");
+
+ /* Check path against the Quick-Search-Excluded-Paths list. */
+ exclude_path_list = g_settings_get_strv (settings, "quick-search-second-scan-excluded-paths");
+
+ if (exclude_path_list) {
+ for (i = 0; exclude_path_list[i]; i++) {
+
+ /* Skip empty or null values. */
+ if (strlen (exclude_path_list[i]) == 0) {
+ continue;
+ }
+
+ dir = g_strdup (exclude_path_list[i]);
+
+ /* Wild-card comparisons. */
+ if (g_strstr_len (dir, strlen (dir), "*") != NULL) {
+
+ if (g_pattern_match_simple (dir, path) == TRUE) {
+
+ results = TRUE;
+ g_free (dir);
+ break;
+ }
+ }
+ /* Non-wild-card comparisons. */
+ else {
+ /* Add a trailing G_DIR_SEPARATOR. */
+ if (g_str_has_suffix (dir, G_DIR_SEPARATOR_S) == FALSE) {
+
+ gchar *tmp;
+
+ tmp = dir;
+ dir = g_strconcat (dir, G_DIR_SEPARATOR_S, NULL);
+ g_free (tmp);
+ }
+
+ if (strcmp (path, dir) == 0) {
+
+ results = TRUE;
+ g_free (dir);
+ break;
+ }
+ }
+ g_free (dir);
+ }
+ g_strfreev (exclude_path_list);
+ }
+
+ g_object_unref (settings);
+ return results;
+}
+
+gboolean
+compare_regex (const gchar * regex,
+ const gchar * string)
+{
+ regex_t regexec_pattern;
+
+ if (regex == NULL) {
+ return TRUE;
+ }
+
+ if (!regcomp (&regexec_pattern, regex, REG_EXTENDED|REG_NOSUB)) {
+ if (regexec (&regexec_pattern, string, 0, 0, 0) != REG_NOMATCH) {
+ regfree (&regexec_pattern);
+ return TRUE;
+ }
+ regfree (&regexec_pattern);
+ }
+ return FALSE;
+}
+
+gboolean
+limit_string_to_x_lines (GString * string,
+ gint x)
+{
+ int i;
+ int count = 0;
+ for (i = 0; string->str[i] != '\0'; i++) {
+ if (string->str[i] == '\n') {
+ count++;
+ if (count == x) {
+ g_string_truncate (string, i);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+static gint
+count_of_char_in_string (const gchar * string,
+ const gchar c)
+{
+ int cnt = 0;
+ for(; *string; string++) {
+ if (*string == c) cnt++;
+ }
+ return cnt;
+}
+
+gchar *
+escape_single_quotes (const gchar * string)
+{
+ GString * gs;
+
+ if (string == NULL) {
+ return NULL;
+ }
+
+ if (count_of_char_in_string (string, '\'') == 0) {
+ return g_strdup(string);
+ }
+ gs = g_string_new ("");
+ for(; *string; string++) {
+ if (*string == '\'') {
+ g_string_append(gs, "'\\''");
+ }
+ else {
+ g_string_append_c(gs, *string);
+ }
+ }
+ return g_string_free (gs, FALSE);
+}
+
+gchar *
+escape_double_quotes (const gchar * string)
+{
+ GString * gs;
+
+ if (string == NULL) {
+ return NULL;
+ }
+
+ if (count_of_char_in_string (string, '\"') == 0) {
+ return g_strdup(string);
+ }
+ gs = g_string_new ("");
+ for(; *string; string++) {
+ if (*string == '\"') {
+ g_string_append(gs, "\\\"");
+ }
+ else {
+ g_string_append_c(gs, *string);
+ }
+ }
+ return g_string_free (gs, FALSE);
+}
+
+gchar *
+backslash_backslash_characters (const gchar * string)
+{
+ GString * gs;
+
+ if (string == NULL) {
+ return NULL;
+ }
+
+ if (count_of_char_in_string (string, '\\') == 0){
+ return g_strdup(string);
+ }
+ gs = g_string_new ("");
+ for(; *string; string++) {
+ if (*string == '\\') {
+ g_string_append(gs, "\\\\");
+ }
+ else {
+ g_string_append_c(gs, *string);
+ }
+ }
+ return g_string_free (gs, FALSE);
+}
+
+gchar *
+backslash_special_characters (const gchar * string)
+{
+ GString * gs;
+
+ if (string == NULL) {
+ return NULL;
+ }
+
+ if ((count_of_char_in_string (string, '\\') == 0) &&
+ (count_of_char_in_string (string, '-') == 0)) {
+ return g_strdup(string);
+ }
+ gs = g_string_new ("");
+ for(; *string; string++) {
+ if (*string == '\\') {
+ g_string_append(gs, "\\\\");
+ }
+ else if (*string == '-') {
+ g_string_append(gs, "\\-");
+ }
+ else {
+ g_string_append_c(gs, *string);
+ }
+ }
+ return g_string_free (gs, FALSE);
+}
+
+gchar *
+remove_mnemonic_character (const gchar * string)
+{
+ GString * gs;
+ gboolean first_mnemonic = TRUE;
+
+ if (string == NULL) {
+ return NULL;
+ }
+
+ gs = g_string_new ("");
+ for(; *string; string++) {
+ if ((first_mnemonic) && (*string == '_')) {
+ first_mnemonic = FALSE;
+ continue;
+ }
+ g_string_append_c(gs, *string);
+ }
+ return g_string_free (gs, FALSE);
+}
+
+gchar *
+get_readable_date (const CajaDateFormat date_format_enum,
+ const time_t file_time_raw)
+{
+ struct tm * file_time;
+ gchar * format;
+ GDate * today;
+ GDate * file_date;
+ guint32 file_date_age;
+ gchar * readable_date;
+
+ file_time = localtime (&file_time_raw);
+
+ /* Base format of date column on caja date-format key */
+ if (date_format_enum == CAJA_DATE_FORMAT_LOCALE) {
+ return gsearchtool_strdup_strftime ("%c", file_time);
+ } else if (date_format_enum == CAJA_DATE_FORMAT_ISO) {
+ return gsearchtool_strdup_strftime ("%Y-%m-%d %H:%M:%S", file_time);
+ }
+
+ file_date = g_date_new_dmy (file_time->tm_mday,
+ file_time->tm_mon + 1,
+ file_time->tm_year + 1900);
+
+ today = g_date_new ();
+ g_date_set_time_t (today, time (NULL));
+
+ file_date_age = g_date_get_julian (today) - g_date_get_julian (file_date);
+
+ g_date_free (today);
+ g_date_free (file_date);
+
+ if (file_date_age == 0) {
+ /* Translators: Below are the strings displayed in the 'Date Modified'
+ column of the list view. The format of this string can vary depending
+ on age of a file. Please modify the format of the timestamp to match
+ your locale. For example, to display 24 hour time replace the '%-I'
+ with '%-H' and remove the '%p'. (See bugzilla report #120434.) */
+ format = g_strdup(_("today at %-I:%M %p"));
+ } else if (file_date_age == 1) {
+ format = g_strdup(_("yesterday at %-I:%M %p"));
+ } else if (file_date_age < 7) {
+ format = g_strdup(_("%A, %B %-d %Y at %-I:%M:%S %p"));
+ } else {
+ format = g_strdup(_("%A, %B %-d %Y at %-I:%M:%S %p"));
+ }
+
+ readable_date = gsearchtool_strdup_strftime (format, file_time);
+ g_free (format);
+
+ return readable_date;
+}
+
+gchar *
+gsearchtool_strdup_strftime (const gchar * format,
+ struct tm * time_pieces)
+{
+ /* This function is borrowed from eel's eel_strdup_strftime() */
+ GString * string;
+ const char * remainder, * percent;
+ char code[4], buffer[512];
+ char * piece, * result, * converted;
+ size_t string_length;
+ gboolean strip_leading_zeros, turn_leading_zeros_to_spaces;
+ char modifier;
+ int i;
+
+ /* Format could be translated, and contain UTF-8 chars,
+ * so convert to locale encoding which strftime uses */
+ converted = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
+ g_return_val_if_fail (converted != NULL, NULL);
+
+ string = g_string_new ("");
+ remainder = converted;
+
+ /* Walk from % character to % character. */
+ for (;;) {
+ percent = strchr (remainder, '%');
+ if (percent == NULL) {
+ g_string_append (string, remainder);
+ break;
+ }
+ g_string_append_len (string, remainder,
+ percent - remainder);
+
+ /* Handle the "%" character. */
+ remainder = percent + 1;
+ switch (*remainder) {
+ case '-':
+ strip_leading_zeros = TRUE;
+ turn_leading_zeros_to_spaces = FALSE;
+ remainder++;
+ break;
+ case '_':
+ strip_leading_zeros = FALSE;
+ turn_leading_zeros_to_spaces = TRUE;
+ remainder++;
+ break;
+ case '%':
+ g_string_append_c (string, '%');
+ remainder++;
+ continue;
+ case '\0':
+ g_warning ("Trailing %% passed to gsearchtool_strdup_strftime");
+ g_string_append_c (string, '%');
+ continue;
+ default:
+ strip_leading_zeros = FALSE;
+ turn_leading_zeros_to_spaces = FALSE;
+ break;
+ }
+
+ modifier = 0;
+ if (strchr (SUS_EXTENDED_STRFTIME_MODIFIERS, *remainder) != NULL) {
+ modifier = *remainder;
+ remainder++;
+
+ if (*remainder == 0) {
+ g_warning ("Unfinished %%%c modifier passed to gsearchtool_strdup_strftime", modifier);
+ break;
+ }
+ }
+
+ if (strchr (C_STANDARD_STRFTIME_CHARACTERS, *remainder) == NULL) {
+ g_warning ("gsearchtool_strdup_strftime does not support "
+ "non-standard escape code %%%c",
+ *remainder);
+ }
+
+ /* Convert code to strftime format. We have a fixed
+ * limit here that each code can expand to a maximum
+ * of 512 bytes, which is probably OK. There's no
+ * limit on the total size of the result string.
+ */
+ i = 0;
+ code[i++] = '%';
+ if (modifier != 0) {
+#ifdef HAVE_STRFTIME_EXTENSION
+ code[i++] = modifier;
+#endif
+ }
+ code[i++] = *remainder;
+ code[i++] = '\0';
+ string_length = strftime (buffer, sizeof (buffer),
+ code, time_pieces);
+ if (string_length == 0) {
+ /* We could put a warning here, but there's no
+ * way to tell a successful conversion to
+ * empty string from a failure.
+ */
+ buffer[0] = '\0';
+ }
+
+ /* Strip leading zeros if requested. */
+ piece = buffer;
+ if (strip_leading_zeros || turn_leading_zeros_to_spaces) {
+ if (strchr (C_STANDARD_NUMERIC_STRFTIME_CHARACTERS, *remainder) == NULL) {
+ g_warning ("gsearchtool_strdup_strftime does not support "
+ "modifier for non-numeric escape code %%%c%c",
+ remainder[-1],
+ *remainder);
+ }
+ if (*piece == '0') {
+ do {
+ piece++;
+ } while (*piece == '0');
+ if (!g_ascii_isdigit (*piece)) {
+ piece--;
+ }
+ }
+ if (turn_leading_zeros_to_spaces) {
+ memset (buffer, ' ', piece - buffer);
+ piece = buffer;
+ }
+ }
+ remainder++;
+
+ /* Add this piece. */
+ g_string_append (string, piece);
+ }
+
+ /* Convert the string back into utf-8. */
+ result = g_locale_to_utf8 (string->str, -1, NULL, NULL, NULL);
+
+ g_string_free (string, TRUE);
+ g_free (converted);
+
+ return result;
+}
+
+gchar *
+get_file_type_description (const gchar * file,
+ GFileInfo * file_info)
+{
+ const char * content_type = NULL;
+ gchar * desc;
+
+ if (file != NULL) {
+ content_type = g_file_info_get_content_type (file_info);
+ }
+
+ if (content_type == NULL || g_content_type_is_unknown (content_type) == TRUE) {
+ return g_strdup (g_content_type_get_description ("application/octet-stream"));
+ }
+
+ desc = g_strdup (g_content_type_get_description (content_type));
+
+ if (g_file_info_get_is_symlink (file_info) == TRUE) {
+
+ const gchar * symlink_target;
+ gchar * absolute_symlink = NULL;
+ gchar * str = NULL;
+
+ symlink_target = g_file_info_get_symlink_target (file_info);
+
+ if (g_path_is_absolute (symlink_target) != TRUE) {
+ gchar *dirname;
+
+ dirname = g_path_get_dirname (file);
+ absolute_symlink = g_strconcat (dirname, G_DIR_SEPARATOR_S, symlink_target, NULL);
+ g_free (dirname);
+ }
+ else {
+ absolute_symlink = g_strdup (symlink_target);
+ }
+
+ if (g_file_test (absolute_symlink, G_FILE_TEST_EXISTS) != TRUE) {
+ if ((g_ascii_strcasecmp (content_type, "x-special/socket") != 0) &&
+ (g_ascii_strcasecmp (content_type, "x-special/fifo") != 0)) {
+ g_free (absolute_symlink);
+ g_free (desc);
+ return g_strdup (_("link (broken)"));
+ }
+ }
+
+ str = g_strdup_printf (_("link to %s"), (desc != NULL) ? desc : content_type);
+ g_free (absolute_symlink);
+ g_free (desc);
+ return str;
+ }
+ return desc;
+}
+
+static gchar *
+gsearchtool_pixmap_file (const gchar * partial_path)
+{
+ gchar * path;
+
+ path = g_build_filename(DATADIR "/pixmaps/mate-search-tool", partial_path, NULL);
+ if (g_file_test(path, G_FILE_TEST_EXISTS)){
+ return path;
+ }
+ g_free (path);
+ return NULL;
+}
+
+static GdkPixbuf *
+gsearchtool_load_thumbnail_frame (void)
+{
+ GdkPixbuf * pixbuf = NULL;
+ gchar * image_path;
+
+ image_path = gsearchtool_pixmap_file("thumbnail_frame.png");
+
+ if (image_path != NULL){
+ pixbuf = gdk_pixbuf_new_from_file(image_path, NULL);
+ }
+ g_free(image_path);
+ return pixbuf;
+}
+
+static void
+gsearchtool_draw_frame_row (GdkPixbuf * frame_image,
+ gint target_width,
+ gint source_width,
+ gint source_v_position,
+ gint dest_v_position,
+ GdkPixbuf * result_pixbuf,
+ gint left_offset,
+ gint height)
+{
+ gint remaining_width;
+ gint h_offset;
+ gint slab_width;
+
+ remaining_width = target_width;
+ h_offset = 0;
+ while (remaining_width > 0) {
+ slab_width = remaining_width > source_width ? source_width : remaining_width;
+ gdk_pixbuf_copy_area (frame_image, left_offset, source_v_position, slab_width,
+ height, result_pixbuf, left_offset + h_offset, dest_v_position);
+ remaining_width -= slab_width;
+ h_offset += slab_width;
+ }
+}
+
+static void
+gsearchtool_draw_frame_column (GdkPixbuf * frame_image,
+ gint target_height,
+ gint source_height,
+ gint source_h_position,
+ gint dest_h_position,
+ GdkPixbuf * result_pixbuf,
+ gint top_offset,
+ gint width)
+{
+ gint remaining_height;
+ gint v_offset;
+ gint slab_height;
+
+ remaining_height = target_height;
+ v_offset = 0;
+ while (remaining_height > 0) {
+ slab_height = remaining_height > source_height ? source_height : remaining_height;
+ gdk_pixbuf_copy_area (frame_image, source_h_position, top_offset, width, slab_height,
+ result_pixbuf, dest_h_position, top_offset + v_offset);
+ remaining_height -= slab_height;
+ v_offset += slab_height;
+ }
+}
+
+static GdkPixbuf *
+gsearchtool_stretch_frame_image (GdkPixbuf *frame_image,
+ gint left_offset,
+ gint top_offset,
+ gint right_offset,
+ gint bottom_offset,
+ gint dest_width,
+ gint dest_height,
+ gboolean fill_flag)
+{
+ GdkPixbuf * result_pixbuf;
+ gint frame_width, frame_height;
+ gint target_width, target_frame_width;
+ gint target_height, target_frame_height;
+
+ frame_width = gdk_pixbuf_get_width (frame_image);
+ frame_height = gdk_pixbuf_get_height (frame_image);
+
+ if (fill_flag) {
+ result_pixbuf = gdk_pixbuf_scale_simple (frame_image, dest_width, dest_height, GDK_INTERP_NEAREST);
+ } else {
+ result_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, dest_width, dest_height);
+ }
+
+ /* clear the new pixbuf */
+ if (fill_flag == FALSE) {
+ gdk_pixbuf_fill (result_pixbuf, 0xffffffff);
+ }
+
+ target_width = dest_width - left_offset - right_offset;
+ target_frame_width = frame_width - left_offset - right_offset;
+
+ target_height = dest_height - top_offset - bottom_offset;
+ target_frame_height = frame_height - top_offset - bottom_offset;
+
+ /* Draw the left top corner and top row */
+ gdk_pixbuf_copy_area (frame_image, 0, 0, left_offset, top_offset, result_pixbuf, 0, 0);
+ gsearchtool_draw_frame_row (frame_image, target_width, target_frame_width, 0, 0,
+ result_pixbuf, left_offset, top_offset);
+
+ /* Draw the right top corner and left column */
+ gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, 0, right_offset, top_offset,
+ result_pixbuf, dest_width - right_offset, 0);
+ gsearchtool_draw_frame_column (frame_image, target_height, target_frame_height, 0, 0,
+ result_pixbuf, top_offset, left_offset);
+
+ /* Draw the bottom right corner and bottom row */
+ gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, frame_height - bottom_offset,
+ right_offset, bottom_offset, result_pixbuf, dest_width - right_offset,
+ dest_height - bottom_offset);
+ gsearchtool_draw_frame_row (frame_image, target_width, target_frame_width,
+ frame_height - bottom_offset, dest_height - bottom_offset,
+ result_pixbuf, left_offset, bottom_offset);
+
+ /* Draw the bottom left corner and the right column */
+ gdk_pixbuf_copy_area (frame_image, 0, frame_height - bottom_offset, left_offset, bottom_offset,
+ result_pixbuf, 0, dest_height - bottom_offset);
+ gsearchtool_draw_frame_column (frame_image, target_height, target_frame_height,
+ frame_width - right_offset, dest_width - right_offset,
+ result_pixbuf, top_offset, right_offset);
+ return result_pixbuf;
+}
+
+static GdkPixbuf *
+gsearchtool_embed_image_in_frame (GdkPixbuf * source_image,
+ GdkPixbuf * frame_image,
+ gint left_offset,
+ gint top_offset,
+ gint right_offset,
+ gint bottom_offset)
+{
+ GdkPixbuf * result_pixbuf;
+ gint source_width, source_height;
+ gint dest_width, dest_height;
+
+ source_width = gdk_pixbuf_get_width (source_image);
+ source_height = gdk_pixbuf_get_height (source_image);
+
+ dest_width = source_width + left_offset + right_offset;
+ dest_height = source_height + top_offset + bottom_offset;
+
+ result_pixbuf = gsearchtool_stretch_frame_image (frame_image, left_offset, top_offset, right_offset, bottom_offset,
+ dest_width, dest_height, FALSE);
+
+ gdk_pixbuf_copy_area (source_image, 0, 0, source_width, source_height, result_pixbuf, left_offset, top_offset);
+
+ return result_pixbuf;
+}
+
+static void
+gsearchtool_thumbnail_frame_image (GdkPixbuf ** pixbuf)
+{
+ GdkPixbuf * pixbuf_with_frame;
+ GdkPixbuf * frame;
+
+ frame = gsearchtool_load_thumbnail_frame ();
+ if (frame == NULL) {
+ return;
+ }
+
+ pixbuf_with_frame = gsearchtool_embed_image_in_frame (*pixbuf, frame, 3, 3, 6, 6);
+ g_object_unref (*pixbuf);
+ g_object_unref (frame);
+
+ *pixbuf = pixbuf_with_frame;
+}
+
+static GdkPixbuf *
+gsearchtool_get_thumbnail_image (const gchar * thumbnail)
+{
+ GdkPixbuf * pixbuf = NULL;
+
+ if (thumbnail != NULL) {
+ if (g_file_test (thumbnail, G_FILE_TEST_EXISTS)) {
+
+ GdkPixbuf * thumbnail_pixbuf = NULL;
+ gfloat scale_factor_x = 1.0;
+ gfloat scale_factor_y = 1.0;
+ gint scale_x;
+ gint scale_y;
+
+ thumbnail_pixbuf = gdk_pixbuf_new_from_file (thumbnail, NULL);
+ gsearchtool_thumbnail_frame_image (&thumbnail_pixbuf);
+
+ if (gdk_pixbuf_get_width (thumbnail_pixbuf) > ICON_SIZE) {
+ scale_factor_x = (gfloat) ICON_SIZE / (gfloat) gdk_pixbuf_get_width (thumbnail_pixbuf);
+ }
+ if (gdk_pixbuf_get_height (thumbnail_pixbuf) > ICON_SIZE) {
+ scale_factor_y = (gfloat) ICON_SIZE / (gfloat) gdk_pixbuf_get_height (thumbnail_pixbuf);
+ }
+
+ if (gdk_pixbuf_get_width (thumbnail_pixbuf) > gdk_pixbuf_get_height (thumbnail_pixbuf)) {
+ scale_x = ICON_SIZE;
+ scale_y = (gint) (gdk_pixbuf_get_height (thumbnail_pixbuf) * scale_factor_x);
+ }
+ else {
+ scale_x = (gint) (gdk_pixbuf_get_width (thumbnail_pixbuf) * scale_factor_y);
+ scale_y = ICON_SIZE;
+ }
+
+ pixbuf = gdk_pixbuf_scale_simple (thumbnail_pixbuf, scale_x, scale_y, GDK_INTERP_BILINEAR);
+ g_object_unref (thumbnail_pixbuf);
+ }
+ }
+ return pixbuf;
+}
+
+static GdkPixbuf *
+get_themed_icon_pixbuf (GThemedIcon * icon,
+ int size,
+ GtkIconTheme * icon_theme)
+{
+ char ** icon_names;
+ GtkIconInfo * icon_info;
+ GdkPixbuf * pixbuf;
+ GError * error = NULL;
+
+ g_object_get (icon, "names", &icon_names, NULL);
+
+ icon_info = gtk_icon_theme_choose_icon (icon_theme, (const char **)icon_names, size, 0);
+ if (icon_info == NULL) {
+ icon_info = gtk_icon_theme_lookup_icon (icon_theme, "text-x-generic", size, GTK_ICON_LOOKUP_USE_BUILTIN);
+ }
+ pixbuf = gtk_icon_info_load_icon (icon_info, &error);
+ if (pixbuf == NULL) {
+ g_warning ("Could not load icon pixbuf: %s\n", error->message);
+ g_clear_error (&error);
+ }
+
+ gtk_icon_info_free (icon_info);
+ g_strfreev (icon_names);
+
+ return pixbuf;
+}
+
+
+
+GdkPixbuf *
+get_file_pixbuf (GSearchWindow * gsearch,
+ GFileInfo * file_info)
+{
+ GdkPixbuf * pixbuf;
+ GIcon * icon = NULL;
+ const gchar * thumbnail_path = NULL;
+
+ if (file_info == NULL) {
+ return NULL;
+ }
+
+ icon = g_file_info_get_icon (file_info);
+
+ if (gsearch->show_thumbnails == TRUE) {
+ thumbnail_path = g_file_info_get_attribute_byte_string (file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
+ }
+
+ if (thumbnail_path != NULL) {
+ pixbuf = gsearchtool_get_thumbnail_image (thumbnail_path);
+ }
+ else {
+ gchar * icon_string;
+
+ icon_string = g_icon_to_string (icon);
+ pixbuf = (GdkPixbuf *) g_hash_table_lookup (gsearch->search_results_filename_hash_table, icon_string);
+
+ if (pixbuf == NULL) {
+ pixbuf = get_themed_icon_pixbuf (G_THEMED_ICON (icon), ICON_SIZE, gtk_icon_theme_get_default ());
+ g_hash_table_insert (gsearch->search_results_filename_hash_table, g_strdup (icon_string), pixbuf);
+ }
+ g_free (icon_string);
+ }
+ return pixbuf;
+}
+
+gboolean
+open_file_with_filemanager (GtkWidget * window,
+ const gchar * file)
+{
+ GDesktopAppInfo * d_app_info;
+ GKeyFile * key_file;
+ GdkAppLaunchContext * ctx = NULL;
+ GList * list = NULL;
+ GAppInfo * g_app_info;
+ GFile * g_file;
+ gchar * command;
+ gchar * contents;
+ gchar * uri;
+ gboolean result = TRUE;
+
+ uri = g_filename_to_uri (file, NULL, NULL);
+ list = g_list_prepend (list, uri);
+
+ g_file = g_file_new_for_path (file);
+ g_app_info = g_file_query_default_handler (g_file, NULL, NULL);
+
+ if (strcmp (g_app_info_get_executable (g_app_info), "caja") == 0) {
+ command = g_strconcat ("caja ",
+ "--sm-disable ",
+ "--no-desktop ",
+ "--no-default-window ",
+ NULL);
+ }
+ else {
+ command = g_strconcat (g_app_info_get_executable (g_app_info),
+ " ", NULL);
+ }
+
+ contents = g_strdup_printf ("[Desktop Entry]\n"
+ "Name=Caja\n"
+ "Icon=file-manager\n"
+ "Exec=%s\n"
+ "Terminal=false\n"
+ "StartupNotify=true\n"
+ "Type=Application\n",
+ command);
+ key_file = g_key_file_new ();
+ g_key_file_load_from_data (key_file, contents, strlen(contents), G_KEY_FILE_NONE, NULL);
+ d_app_info = g_desktop_app_info_new_from_keyfile (key_file);
+
+ if (d_app_info != NULL) {
+ ctx = gdk_app_launch_context_new ();
+ gdk_app_launch_context_set_screen (ctx, gtk_widget_get_screen (window));
+
+ result = g_app_info_launch_uris (G_APP_INFO (d_app_info), list, G_APP_LAUNCH_CONTEXT (ctx), NULL);
+ }
+ else {
+ result = FALSE;
+ }
+
+ g_object_unref (g_app_info);
+ g_object_unref (d_app_info);
+ g_object_unref (g_file);
+ g_object_unref (ctx);
+ g_key_file_free (key_file);
+ g_list_free (list);
+ g_free (contents);
+ g_free (command);
+ g_free (uri);
+
+ return result;
+}
+
+gboolean
+open_file_with_application (GtkWidget * window,
+ const gchar * file,
+ GAppInfo * app)
+{
+ GdkAppLaunchContext * context;
+ GdkScreen * screen;
+ gboolean result;
+
+ if (g_file_test (file, G_FILE_TEST_IS_DIR) == TRUE) {
+ return FALSE;
+ }
+
+ context = gdk_app_launch_context_new ();
+ screen = gtk_widget_get_screen (window);
+ gdk_app_launch_context_set_screen (context, screen);
+
+ if (app == NULL) {
+ gchar * uri;
+
+ uri = g_filename_to_uri (file, NULL, NULL);
+ result = g_app_info_launch_default_for_uri (uri, (GAppLaunchContext *) context, NULL);
+ g_free (uri);
+ }
+ else {
+ GList * g_file_list = NULL;
+ GFile * g_file = NULL;
+
+ g_file = g_file_new_for_path (file);
+
+ if (g_file == NULL) {
+ result = FALSE;
+ }
+ else {
+ g_file_list = g_list_prepend (g_file_list, g_file);
+
+ result = g_app_info_launch (app, g_file_list, (GAppLaunchContext *) context, NULL);
+ g_list_free (g_file_list);
+ g_object_unref (g_file);
+ }
+ }
+ return result;
+}
+
+gboolean
+launch_file (const gchar * file)
+{
+ const char * content_type = g_content_type_guess (file, NULL, 0, NULL);
+ gboolean result = FALSE;
+
+ if ((g_file_test (file, G_FILE_TEST_IS_EXECUTABLE)) &&
+ (g_ascii_strcasecmp (content_type, BINARY_EXEC_MIME_TYPE) == 0)) {
+ result = g_spawn_command_line_async (file, NULL);
+ }
+
+ return result;
+}
+
+gchar *
+gsearchtool_get_unique_filename (const gchar * path,
+ const gchar * suffix)
+{
+ const gint num_of_words = 12;
+ gchar * words[] = {
+ "foo",
+ "bar",
+ "blah",
+ "cranston",
+ "frobate",
+ "hadjaha",
+ "greasy",
+ "hammer",
+ "eek",
+ "larry",
+ "curly",
+ "moe",
+ NULL};
+ gchar * retval = NULL;
+ gboolean exists = TRUE;
+
+ while (exists) {
+ gchar * file;
+ gint rnd;
+ gint word;
+
+ rnd = rand ();
+ word = rand () % num_of_words;
+
+ file = g_strdup_printf ("%s-%010x%s",
+ words [word],
+ (guint) rnd,
+ suffix);
+
+ g_free (retval);
+ retval = g_strconcat (path, G_DIR_SEPARATOR_S, file, NULL);
+ exists = g_file_test (retval, G_FILE_TEST_EXISTS);
+ g_free (file);
+ }
+ return retval;
+}
+
+GtkWidget *
+gsearchtool_button_new_with_stock_icon (const gchar * string,
+ const gchar * stock_id)
+{
+ GtkWidget * align;
+ GtkWidget * button;
+ GtkWidget * hbox;
+ GtkWidget * image;
+ GtkWidget * label;
+
+ button = gtk_button_new ();
+ label = gtk_label_new_with_mnemonic (string);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
+ image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
+ hbox = gtk_hbox_new (FALSE, 2);
+ align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+ gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (button), align);
+ gtk_container_add (GTK_CONTAINER (align), hbox);
+ gtk_widget_show_all (align);
+
+ return button;
+}
+
+GSList *
+gsearchtool_get_columns_order (GtkTreeView * treeview)
+{
+ GSList *order = NULL;
+ GList * columns;
+ GList * col;
+
+ columns = gtk_tree_view_get_columns (treeview);
+
+ for (col = columns; col; col = col->next) {
+ gint id;
+
+ id = gtk_tree_view_column_get_sort_column_id (col->data);
+ order = g_slist_prepend (order, GINT_TO_POINTER (id));
+ }
+ g_list_free (columns);
+
+ order = g_slist_reverse (order);
+ return order;
+}
+
+GtkTreeViewColumn *
+gsearchtool_gtk_tree_view_get_column_with_sort_column_id (GtkTreeView * treeview,
+ gint id)
+{
+ GtkTreeViewColumn * col = NULL;
+ GList * columns;
+ GList * it;
+
+ columns = gtk_tree_view_get_columns (treeview);
+
+ for (it = columns; it; it = it->next) {
+ if (gtk_tree_view_column_get_sort_column_id (it->data) == id) {
+ col = it->data;
+ break;
+ }
+ }
+ g_list_free (columns);
+ return col;
+}
+
+void
+gsearchtool_set_columns_order (GtkTreeView * treeview)
+{
+ GtkTreeViewColumn * last = NULL;
+ GSettings * settings;
+ GVariant * value;
+
+ settings = g_settings_new ("org.mate.search-tool");
+
+ value = g_settings_get_value (settings, "columns-order");
+
+ if (value) {
+ GVariantIter *iter;
+ GVariant *item;
+
+ g_variant_get (value, "ai", &iter);
+
+ while ((item = g_variant_iter_next_value (iter))) {
+ GtkTreeViewColumn * cur;
+ gint id;
+
+ g_variant_get (item, "i", &id);
+
+ if (id >= 0 && id < NUM_COLUMNS) {
+
+ cur = gsearchtool_gtk_tree_view_get_column_with_sort_column_id (treeview, id);
+
+ if (cur && cur != last) {
+ gtk_tree_view_move_column_after (treeview, cur, last);
+ last = cur;
+ }
+ }
+ g_variant_unref (item);
+ }
+ g_variant_iter_free (iter);
+ g_variant_unref (value);
+ }
+ g_object_unref (settings);
+}
+
+void
+gsearchtool_get_stored_window_geometry (gint * width,
+ gint * height)
+{
+ GSettings * settings;
+ gint saved_width;
+ gint saved_height;
+
+ if (width == NULL || height == NULL) {
+ return;
+ }
+
+ settings = g_settings_new ("org.mate.search-tool");
+
+ saved_width = g_settings_get_int (settings, "default-window-width");
+ saved_height = g_settings_get_int (settings, "default-window-height");
+
+ if (saved_width == -1) {
+ saved_width = DEFAULT_WINDOW_WIDTH;
+ }
+
+ if (saved_height == -1) {
+ saved_height = DEFAULT_WINDOW_HEIGHT;
+ }
+
+ *width = MAX (saved_width, MINIMUM_WINDOW_WIDTH);
+ *height = MAX (saved_height, MINIMUM_WINDOW_HEIGHT);
+ g_object_unref (settings);
+}
+
+/* START OF CAJA/EEL FUNCTIONS: USED FOR HANDLING OF DUPLICATE FILENAMES */
+
+/* Localizers:
+ * Feel free to leave out the st, nd, rd and th suffix or
+ * make some or all of them match.
+ */
+
+/* localizers: tag used to detect the first copy of a file */
+static const char untranslated_copy_duplicate_tag[] = N_(" (copy)");
+/* localizers: tag used to detect the second copy of a file */
+static const char untranslated_another_copy_duplicate_tag[] = N_(" (another copy)");
+
+/* localizers: tag used to detect the x11th copy of a file */
+static const char untranslated_x11th_copy_duplicate_tag[] = N_("th copy)");
+/* localizers: tag used to detect the x12th copy of a file */
+static const char untranslated_x12th_copy_duplicate_tag[] = N_("th copy)");
+/* localizers: tag used to detect the x13th copy of a file */
+static const char untranslated_x13th_copy_duplicate_tag[] = N_("th copy)");
+
+/* localizers: tag used to detect the x1st copy of a file */
+static const char untranslated_st_copy_duplicate_tag[] = N_("st copy)");
+/* localizers: tag used to detect the x2nd copy of a file */
+static const char untranslated_nd_copy_duplicate_tag[] = N_("nd copy)");
+/* localizers: tag used to detect the x3rd copy of a file */
+static const char untranslated_rd_copy_duplicate_tag[] = N_("rd copy)");
+
+/* localizers: tag used to detect the xxth copy of a file */
+static const char untranslated_th_copy_duplicate_tag[] = N_("th copy)");
+
+#define COPY_DUPLICATE_TAG _(untranslated_copy_duplicate_tag)
+#define ANOTHER_COPY_DUPLICATE_TAG _(untranslated_another_copy_duplicate_tag)
+#define X11TH_COPY_DUPLICATE_TAG _(untranslated_x11th_copy_duplicate_tag)
+#define X12TH_COPY_DUPLICATE_TAG _(untranslated_x12th_copy_duplicate_tag)
+#define X13TH_COPY_DUPLICATE_TAG _(untranslated_x13th_copy_duplicate_tag)
+
+#define ST_COPY_DUPLICATE_TAG _(untranslated_st_copy_duplicate_tag)
+#define ND_COPY_DUPLICATE_TAG _(untranslated_nd_copy_duplicate_tag)
+#define RD_COPY_DUPLICATE_TAG _(untranslated_rd_copy_duplicate_tag)
+#define TH_COPY_DUPLICATE_TAG _(untranslated_th_copy_duplicate_tag)
+
+/* localizers: appended to first file copy */
+static const char untranslated_first_copy_duplicate_format[] = N_("%s (copy)%s");
+/* localizers: appended to second file copy */
+static const char untranslated_second_copy_duplicate_format[] = N_("%s (another copy)%s");
+
+/* localizers: appended to x11th file copy */
+static const char untranslated_x11th_copy_duplicate_format[] = N_("%s (%dth copy)%s");
+/* localizers: appended to x12th file copy */
+static const char untranslated_x12th_copy_duplicate_format[] = N_("%s (%dth copy)%s");
+/* localizers: appended to x13th file copy */
+static const char untranslated_x13th_copy_duplicate_format[] = N_("%s (%dth copy)%s");
+
+/* localizers: appended to x1st file copy */
+static const char untranslated_st_copy_duplicate_format[] = N_("%s (%dst copy)%s");
+/* localizers: appended to x2nd file copy */
+static const char untranslated_nd_copy_duplicate_format[] = N_("%s (%dnd copy)%s");
+/* localizers: appended to x3rd file copy */
+static const char untranslated_rd_copy_duplicate_format[] = N_("%s (%drd copy)%s");
+/* localizers: appended to xxth file copy */
+static const char untranslated_th_copy_duplicate_format[] = N_("%s (%dth copy)%s");
+
+#define FIRST_COPY_DUPLICATE_FORMAT _(untranslated_first_copy_duplicate_format)
+#define SECOND_COPY_DUPLICATE_FORMAT _(untranslated_second_copy_duplicate_format)
+#define X11TH_COPY_DUPLICATE_FORMAT _(untranslated_x11th_copy_duplicate_format)
+#define X12TH_COPY_DUPLICATE_FORMAT _(untranslated_x12th_copy_duplicate_format)
+#define X13TH_COPY_DUPLICATE_FORMAT _(untranslated_x13th_copy_duplicate_format)
+
+#define ST_COPY_DUPLICATE_FORMAT _(untranslated_st_copy_duplicate_format)
+#define ND_COPY_DUPLICATE_FORMAT _(untranslated_nd_copy_duplicate_format)
+#define RD_COPY_DUPLICATE_FORMAT _(untranslated_rd_copy_duplicate_format)
+#define TH_COPY_DUPLICATE_FORMAT _(untranslated_th_copy_duplicate_format)
+
+static gchar *
+make_valid_utf8 (const gchar * name)
+{
+ GString *string;
+ const char *remainder, *invalid;
+ int remaining_bytes, valid_bytes;
+
+ string = NULL;
+ remainder = name;
+ remaining_bytes = strlen (name);
+
+ while (remaining_bytes != 0) {
+ if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
+ break;
+ }
+ valid_bytes = invalid - remainder;
+
+ if (string == NULL) {
+ string = g_string_sized_new (remaining_bytes);
+ }
+ g_string_append_len (string, remainder, valid_bytes);
+ g_string_append_c (string, '?');
+
+ remaining_bytes -= valid_bytes + 1;
+ remainder = invalid + 1;
+ }
+
+ if (string == NULL) {
+ return g_strdup (name);
+ }
+
+ g_string_append (string, remainder);
+ g_string_append (string, _(" (invalid Unicode)"));
+ g_assert (g_utf8_validate (string->str, -1, NULL));
+
+ return g_string_free (string, FALSE);
+}
+
+static gchar *
+extract_string_until (const gchar * original,
+ const gchar * until_substring)
+{
+ gchar * result;
+
+ g_assert ((gint) strlen (original) >= until_substring - original);
+ g_assert (until_substring - original >= 0);
+
+ result = g_malloc (until_substring - original + 1);
+ strncpy (result, original, until_substring - original);
+ result[until_substring - original] = '\0';
+
+ return result;
+}
+
+/* Dismantle a file name, separating the base name, the file suffix and removing any
+ * (xxxcopy), etc. string. Figure out the count that corresponds to the given
+ * (xxxcopy) substring.
+ */
+static void
+parse_previous_duplicate_name (const gchar * name,
+ gchar ** name_base,
+ const gchar ** suffix,
+ gint * count)
+{
+ const gchar * tag;
+
+ g_assert (name[0] != '\0');
+
+ *suffix = strchr (name + 1, '.');
+ if (*suffix == NULL || (*suffix)[1] == '\0') {
+ /* no suffix */
+ *suffix = "";
+ }
+
+ tag = strstr (name, COPY_DUPLICATE_TAG);
+ if (tag != NULL) {
+ if (tag > *suffix) {
+ /* handle case "foo. (copy)" */
+ *suffix = "";
+ }
+ *name_base = extract_string_until (name, tag);
+ *count = 1;
+ return;
+ }
+
+ tag = strstr (name, ANOTHER_COPY_DUPLICATE_TAG);
+ if (tag != NULL) {
+ if (tag > *suffix) {
+ /* handle case "foo. (another copy)" */
+ *suffix = "";
+ }
+ *name_base = extract_string_until (name, tag);
+ *count = 2;
+ return;
+ }
+
+ /* Check to see if we got one of st, nd, rd, th. */
+ tag = strstr (name, X11TH_COPY_DUPLICATE_TAG);
+
+ if (tag == NULL) {
+ tag = strstr (name, X12TH_COPY_DUPLICATE_TAG);
+ }
+ if (tag == NULL) {
+ tag = strstr (name, X13TH_COPY_DUPLICATE_TAG);
+ }
+ if (tag == NULL) {
+ tag = strstr (name, ST_COPY_DUPLICATE_TAG);
+ }
+ if (tag == NULL) {
+ tag = strstr (name, ND_COPY_DUPLICATE_TAG);
+ }
+ if (tag == NULL) {
+ tag = strstr (name, RD_COPY_DUPLICATE_TAG);
+ }
+ if (tag == NULL) {
+ tag = strstr (name, TH_COPY_DUPLICATE_TAG);
+ }
+
+ /* If we got one of st, nd, rd, th, fish out the duplicate number. */
+ if (tag != NULL) {
+ /* localizers: opening parentheses to match the "th copy)" string */
+ tag = strstr (name, _(" ("));
+ if (tag != NULL) {
+ if (tag > *suffix) {
+ /* handle case "foo. (22nd copy)" */
+ *suffix = "";
+ }
+ *name_base = extract_string_until (name, tag);
+ /* localizers: opening parentheses of the "th copy)" string */
+ if (sscanf (tag, _(" (%d"), count) == 1) {
+ if (*count < 1 || *count > 1000000) {
+ /* keep the count within a reasonable range */
+ *count = 0;
+ }
+ return;
+ }
+ *count = 0;
+ return;
+ }
+ }
+
+ *count = 0;
+ if (**suffix != '\0') {
+ *name_base = extract_string_until (name, *suffix);
+ } else {
+ *name_base = g_strdup (name);
+ }
+}
+
+static gchar *
+make_next_duplicate_name (const gchar *base,
+ const gchar *suffix,
+ gint count)
+{
+ const gchar * format;
+ gchar * result;
+
+ if (count < 1) {
+ g_warning ("bad count %d in make_next_duplicate_name()", count);
+ count = 1;
+ }
+
+ if (count <= 2) {
+
+ /* Handle special cases for low numbers.
+ * Perhaps for some locales we will need to add more.
+ */
+ switch (count) {
+ default:
+ g_assert_not_reached ();
+ /* fall through */
+ case 1:
+ format = FIRST_COPY_DUPLICATE_FORMAT;
+ break;
+ case 2:
+ format = SECOND_COPY_DUPLICATE_FORMAT;
+ break;
+
+ }
+ result = g_strdup_printf (format, base, suffix);
+ } else {
+
+ /* Handle special cases for the first few numbers of each ten.
+ * For locales where getting this exactly right is difficult,
+ * these can just be made all the same as the general case below.
+ */
+
+ /* Handle special cases for x11th - x20th.
+ */
+ switch (count % 100) {
+ case 11:
+ format = X11TH_COPY_DUPLICATE_FORMAT;
+ break;
+ case 12:
+ format = X12TH_COPY_DUPLICATE_FORMAT;
+ break;
+ case 13:
+ format = X13TH_COPY_DUPLICATE_FORMAT;
+ break;
+ default:
+ format = NULL;
+ break;
+ }
+
+ if (format == NULL) {
+ switch (count % 10) {
+ case 1:
+ format = ST_COPY_DUPLICATE_FORMAT;
+ break;
+ case 2:
+ format = ND_COPY_DUPLICATE_FORMAT;
+ break;
+ case 3:
+ format = RD_COPY_DUPLICATE_FORMAT;
+ break;
+ default:
+ /* The general case. */
+ format = TH_COPY_DUPLICATE_FORMAT;
+ break;
+ }
+ }
+ result = g_strdup_printf (format, base, count, suffix);
+ }
+ return result;
+}
+
+static gchar *
+get_duplicate_name (const gchar *name)
+{
+ const gchar * suffix;
+ gchar * name_base;
+ gchar * result;
+ gint count;
+
+ parse_previous_duplicate_name (name, &name_base, &suffix, &count);
+ result = make_next_duplicate_name (name_base, suffix, count + 1);
+ g_free (name_base);
+
+ return result;
+}
+
+gchar *
+gsearchtool_get_next_duplicate_name (const gchar * basename)
+{
+ gchar * utf8_name;
+ gchar * utf8_result;
+ gchar * result;
+
+ utf8_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
+
+ if (utf8_name == NULL) {
+ /* Couldn't convert to utf8 - probably
+ * G_BROKEN_FILENAMES not set when it should be.
+ * Try converting from the locale */
+ utf8_name = g_locale_to_utf8 (basename, -1, NULL, NULL, NULL);
+
+ if (utf8_name == NULL) {
+ utf8_name = make_valid_utf8 (basename);
+ }
+ }
+
+ utf8_result = get_duplicate_name (utf8_name);
+ g_free (utf8_name);
+
+ result = g_filename_from_utf8 (utf8_result, -1, NULL, NULL, NULL);
+ g_free (utf8_result);
+ return result;
+}
diff --git a/gsearchtool/src/gsearchtool-support.h b/gsearchtool/src/gsearchtool-support.h
new file mode 100644
index 00000000..15585d5d
--- /dev/null
+++ b/gsearchtool/src/gsearchtool-support.h
@@ -0,0 +1,114 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * MATE Search Tool
+ *
+ * File: gsearchtool-support.h
+ *
+ * (C) 2002 the Free Software Foundation
+ *
+ * Authors: Dennis Cranston <[email protected]>
+ * George Lebl
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _GSEARCHTOOL_SUPPORT_H_
+#define _GSEARCHTOOL_SUPPORT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif
+
+#include "gsearchtool.h"
+
+#define ICON_SIZE 24
+
+gboolean
+is_path_hidden (const gchar * path);
+
+gboolean
+is_quick_search_excluded_path (const gchar * path);
+
+gboolean
+is_second_scan_excluded_path (const gchar * path);
+
+gboolean
+compare_regex (const gchar * regex,
+ const gchar * string);
+gboolean
+limit_string_to_x_lines (GString * string,
+ gint x);
+gchar *
+escape_single_quotes (const gchar * string);
+
+gchar *
+escape_double_quotes (const gchar * string);
+
+gchar *
+backslash_backslash_characters (const gchar * string);
+
+gchar *
+backslash_special_characters (const gchar * string);
+
+gchar *
+remove_mnemonic_character (const gchar * string);
+
+gchar *
+get_readable_date (const CajaDateFormat date_format_enum,
+ const time_t file_time_raw);
+gchar *
+gsearchtool_strdup_strftime (const gchar * format,
+ struct tm * time_pieces);
+gchar *
+get_file_type_description (const gchar * file,
+ GFileInfo * file_info);
+GdkPixbuf *
+get_file_pixbuf (GSearchWindow * gsearch,
+ GFileInfo * file_info);
+gboolean
+open_file_with_filemanager (GtkWidget * window,
+ const gchar * file);
+gboolean
+open_file_with_application (GtkWidget * window,
+ const gchar * file,
+ GAppInfo * app);
+gboolean
+launch_file (const gchar * file);
+
+gchar *
+gsearchtool_get_unique_filename (const gchar * path,
+ const gchar * suffix);
+GtkWidget *
+gsearchtool_button_new_with_stock_icon (const gchar * string,
+ const gchar * stock_id);
+GSList *
+gsearchtool_get_columns_order (GtkTreeView * treeview);
+
+void
+gsearchtool_set_columns_order (GtkTreeView * treeview);
+
+void
+gsearchtool_get_stored_window_geometry (gint * width,
+ gint * height);
+gchar *
+gsearchtool_get_next_duplicate_name (const gchar * basname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GSEARCHTOOL_SUPPORT_H */
diff --git a/gsearchtool/src/gsearchtool.c b/gsearchtool/src/gsearchtool.c
new file mode 100644
index 00000000..757e8ca2
--- /dev/null
+++ b/gsearchtool/src/gsearchtool.c
@@ -0,0 +1,3070 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * MATE Search Tool
+ *
+ * File: gsearchtool.c
+ *
+ * (C) 1998,2002 the Free Software Foundation
+ *
+ * Authors: Dennis Cranston <[email protected]>
+ * George Lebl
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fnmatch.h>
+#ifndef FNM_CASEFOLD
+# define FNM_CASEFOLD 0
+#endif
+
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <gio/gio.h>
+#include <locale.h>
+
+#include "gsearchtool.h"
+#include "gsearchtool-callbacks.h"
+#include "gsearchtool-support.h"
+#include "gsearchtool-entry.h"
+
+#define MATE_SEARCH_TOOL_DEFAULT_ICON_SIZE 16
+#define MATE_SEARCH_TOOL_STOCK "panel-searchtool"
+#define MATE_SEARCH_TOOL_REFRESH_DURATION 50000
+#define LEFT_LABEL_SPACING " "
+
+static GObjectClass * parent_class;
+
+typedef enum {
+ SEARCH_CONSTRAINT_TYPE_BOOLEAN,
+ SEARCH_CONSTRAINT_TYPE_NUMERIC,
+ SEARCH_CONSTRAINT_TYPE_TEXT,
+ SEARCH_CONSTRAINT_TYPE_DATE_BEFORE,
+ SEARCH_CONSTRAINT_TYPE_DATE_AFTER,
+ SEARCH_CONSTRAINT_TYPE_SEPARATOR,
+ SEARCH_CONSTRAINT_TYPE_NONE
+} GSearchConstraintType;
+
+typedef struct _GSearchOptionTemplate GSearchOptionTemplate;
+
+struct _GSearchOptionTemplate {
+ GSearchConstraintType type; /* The available option type */
+ gchar * option; /* An option string to pass to the command */
+ gchar * desc; /* The description for display */
+ gchar * units; /* Optional units for display */
+ gboolean is_selected;
+};
+
+static GSearchOptionTemplate GSearchOptionTemplates[] = {
+ { SEARCH_CONSTRAINT_TYPE_TEXT, NULL, N_("Contains the _text"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_SEPARATOR, NULL, NULL, NULL, TRUE },
+ { SEARCH_CONSTRAINT_TYPE_DATE_BEFORE, "-mtime -%d", N_("_Date modified less than"), N_("days"), FALSE },
+ { SEARCH_CONSTRAINT_TYPE_DATE_AFTER, "\\( -mtime +%d -o -mtime %d \\)", N_("Date modified more than"), N_("days"), FALSE },
+ { SEARCH_CONSTRAINT_TYPE_SEPARATOR, NULL, NULL, NULL, TRUE },
+ { SEARCH_CONSTRAINT_TYPE_NUMERIC, "\\( -size %uc -o -size +%uc \\)", N_("S_ize at least"), N_("kilobytes"), FALSE },
+ { SEARCH_CONSTRAINT_TYPE_NUMERIC, "\\( -size %uc -o -size -%uc \\)", N_("Si_ze at most"), N_("kilobytes"), FALSE },
+ { SEARCH_CONSTRAINT_TYPE_BOOLEAN, "-size 0c \\( -type f -o -type d \\)", N_("File is empty"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_SEPARATOR, NULL, NULL, NULL, TRUE },
+ { SEARCH_CONSTRAINT_TYPE_TEXT, "-user '%s'", N_("Owned by _user"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_TEXT, "-group '%s'", N_("Owned by _group"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_BOOLEAN, "\\( -nouser -o -nogroup \\)", N_("Owner is unrecognized"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_SEPARATOR, NULL, NULL, NULL, TRUE },
+ { SEARCH_CONSTRAINT_TYPE_TEXT, "'!' -name '*%s*'", N_("Na_me does not contain"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_TEXT, "-regex '%s'", N_("Name matches regular e_xpression"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_SEPARATOR, NULL, NULL, NULL, TRUE },
+ { SEARCH_CONSTRAINT_TYPE_BOOLEAN, "SHOW_HIDDEN_FILES", N_("Show hidden and backup files"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_BOOLEAN, "-follow", N_("Follow symbolic links"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_BOOLEAN, "EXCLUDE_OTHER_FILESYSTEMS", N_("Exclude other filesystems"), NULL, FALSE },
+ { SEARCH_CONSTRAINT_TYPE_NONE, NULL, NULL, NULL, FALSE}
+};
+
+enum {
+ SEARCH_CONSTRAINT_CONTAINS_THE_TEXT,
+ SEARCH_CONSTRAINT_TYPE_SEPARATOR_00,
+ SEARCH_CONSTRAINT_DATE_MODIFIED_BEFORE,
+ SEARCH_CONSTRAINT_DATE_MODIFIED_AFTER,
+ SEARCH_CONSTRAINT_TYPE_SEPARATOR_01,
+ SEARCH_CONSTRAINT_SIZE_IS_MORE_THAN,
+ SEARCH_CONSTRAINT_SIZE_IS_LESS_THAN,
+ SEARCH_CONSTRAINT_FILE_IS_EMPTY,
+ SEARCH_CONSTRAINT_TYPE_SEPARATOR_02,
+ SEARCH_CONSTRAINT_OWNED_BY_USER,
+ SEARCH_CONSTRAINT_OWNED_BY_GROUP,
+ SEARCH_CONSTRAINT_OWNER_IS_UNRECOGNIZED,
+ SEARCH_CONSTRAINT_TYPE_SEPARATOR_03,
+ SEARCH_CONSTRAINT_FILE_IS_NOT_NAMED,
+ SEARCH_CONSTRAINT_FILE_MATCHES_REGULAR_EXPRESSION,
+ SEARCH_CONSTRAINT_TYPE_SEPARATOR_04,
+ SEARCH_CONSTRAINT_SHOW_HIDDEN_FILES_AND_FOLDERS,
+ SEARCH_CONSTRAINT_FOLLOW_SYMBOLIC_LINKS,
+ SEARCH_CONSTRAINT_SEARCH_OTHER_FILESYSTEMS,
+ SEARCH_CONSTRAINT_MAXIMUM_POSSIBLE
+};
+
+static GtkTargetEntry GSearchDndTable[] = {
+ { "text/uri-list", 0, 1 },
+ { "text/plain", 0, 0 },
+ { "STRING", 0, 0 }
+};
+
+static guint GSearchTotalDnds = sizeof (GSearchDndTable) / sizeof (GSearchDndTable[0]);
+
+struct _GSearchGOptionArguments {
+ gchar * name;
+ gchar * path;
+ gchar * contains;
+ gchar * user;
+ gchar * group;
+ gboolean nouser;
+ gchar * mtimeless;
+ gchar * mtimemore;
+ gchar * sizeless;
+ gchar * sizemore;
+ gboolean empty;
+ gchar * notnamed;
+ gchar * regex;
+ gboolean hidden;
+ gboolean follow;
+ gboolean mounts;
+ gchar * sortby;
+ gboolean descending;
+ gboolean start;
+} GSearchGOptionArguments;
+
+static GOptionEntry GSearchGOptionEntries[] = {
+ { "version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, version_cb, N_("Show version of the application"), NULL},
+ { "named", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.name, NULL, N_("STRING") },
+ { "path", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.path, NULL, N_("PATH") },
+ { "sortby", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.sortby, NULL, N_("VALUE") },
+ { "descending", 0, 0, G_OPTION_ARG_NONE, &GSearchGOptionArguments.descending, NULL, NULL },
+ { "start", 0, 0, G_OPTION_ARG_NONE, &GSearchGOptionArguments.start, NULL, NULL },
+ { "contains", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.contains, NULL, N_("STRING") },
+ { "mtimeless", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.mtimeless, NULL, N_("DAYS") },
+ { "mtimemore", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.mtimemore, NULL, N_("DAYS") },
+ { "sizemore", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.sizemore, NULL, N_("KILOBYTES") },
+ { "sizeless", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.sizeless, NULL, N_("KILOBYTES") },
+ { "empty", 0, 0, G_OPTION_ARG_NONE, &GSearchGOptionArguments.empty, NULL, NULL },
+ { "user", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.user, NULL, N_("USER") },
+ { "group", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.group, NULL, N_("GROUP") },
+ { "nouser", 0, 0, G_OPTION_ARG_NONE, &GSearchGOptionArguments.nouser, NULL, NULL },
+ { "notnamed", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.notnamed, NULL, N_("STRING") },
+ { "regex", 0, 0, G_OPTION_ARG_STRING, &GSearchGOptionArguments.regex, NULL, N_("PATTERN") },
+ { "hidden", 0, 0, G_OPTION_ARG_NONE, &GSearchGOptionArguments.hidden, NULL, NULL },
+ { "follow", 0, 0, G_OPTION_ARG_NONE, &GSearchGOptionArguments.follow, NULL, NULL },
+ { "mounts", 0, 0, G_OPTION_ARG_NONE, &GSearchGOptionArguments.mounts, NULL, NULL },
+ { NULL }
+};
+
+static gchar * find_command_default_name_argument;
+static gchar * locate_command_default_options;
+pid_t locate_database_check_command_pid;
+
+static gboolean
+handle_locate_command_stdout_io (GIOChannel * ioc,
+ GIOCondition condition,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ gboolean broken_pipe = FALSE;
+
+ if (condition & G_IO_IN) {
+
+ GError * error = NULL;
+ GString * string;
+
+ string = g_string_new (NULL);
+
+ while (ioc->is_readable != TRUE);
+
+ do {
+ gint status;
+
+ do {
+ status = g_io_channel_read_line_string (ioc, string, NULL, &error);
+
+ if (status == G_IO_STATUS_EOF) {
+ broken_pipe = TRUE;
+ }
+ else if (status == G_IO_STATUS_AGAIN) {
+ if (gtk_events_pending ()) {
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+ }
+ }
+ else if ((string->len != 0) && (strncmp (string->str, "/", 1) == 0)) {
+ gsearch->is_locate_database_available = TRUE;
+ broken_pipe = TRUE;
+ }
+
+ } while (status == G_IO_STATUS_AGAIN && broken_pipe == FALSE);
+
+ if (broken_pipe == TRUE) {
+ break;
+ }
+
+ if (status != G_IO_STATUS_NORMAL) {
+ if (error != NULL) {
+ g_warning ("handle_locate_command_stdout_io(): %s", error->message);
+ g_error_free (error);
+ }
+ }
+
+ } while (g_io_channel_get_buffer_condition (ioc) & G_IO_IN);
+
+ waitpid (locate_database_check_command_pid, NULL, 0);
+ g_string_free (string, TRUE);
+ }
+
+ if (!(condition & G_IO_IN) || broken_pipe == TRUE) {
+ gsearch->is_locate_database_check_finished = TRUE;
+ g_io_channel_shutdown (ioc, TRUE, NULL);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+setup_case_insensitive_arguments (GSearchWindow * gsearch)
+{
+ static gboolean case_insensitive_arguments_initialized = FALSE;
+ gchar * cmd_stderr;
+ gchar * grep_cmd;
+ gchar * locate;
+
+ if (case_insensitive_arguments_initialized == TRUE) {
+ return;
+ }
+ case_insensitive_arguments_initialized = TRUE;
+
+ /* check find command for -iname argument compatibility */
+ g_spawn_command_line_sync ("find /dev/null -iname 'string'", NULL, &cmd_stderr, NULL, NULL);
+
+ if ((cmd_stderr != NULL) && (strlen (cmd_stderr) == 0)) {
+ find_command_default_name_argument = g_strdup ("-iname");
+ GSearchOptionTemplates[SEARCH_CONSTRAINT_FILE_IS_NOT_NAMED].option = g_strdup ("'!' -iname '*%s*'");
+ }
+ else {
+ find_command_default_name_argument = g_strdup ("-name");
+ }
+ g_free (cmd_stderr);
+
+ /* check grep command for -i argument compatibility */
+ grep_cmd = g_strdup_printf ("%s -i 'string' /dev/null", GREP_COMMAND);
+ g_spawn_command_line_sync (grep_cmd, NULL, &cmd_stderr, NULL, NULL);
+
+ if ((cmd_stderr != NULL) && (strlen (cmd_stderr) == 0)) {
+ g_free (cmd_stderr);
+ g_free (grep_cmd);
+
+ /* check grep command for -I argument compatibility, bug 568840 */
+ grep_cmd = g_strdup_printf ("%s -i -I 'string' /dev/null", GREP_COMMAND);
+ g_spawn_command_line_sync (grep_cmd, NULL, &cmd_stderr, NULL, NULL);
+
+ if ((cmd_stderr != NULL) && (strlen (cmd_stderr) == 0)) {
+ GSearchOptionTemplates[SEARCH_CONSTRAINT_CONTAINS_THE_TEXT].option =
+ g_strdup_printf ("'!' -type p -exec %s -i -I -c '%%s' {} \\;", GREP_COMMAND);
+ }
+ else {
+ GSearchOptionTemplates[SEARCH_CONSTRAINT_CONTAINS_THE_TEXT].option =
+ g_strdup_printf ("'!' -type p -exec %s -i -c '%%s' {} \\;", GREP_COMMAND);
+ }
+ }
+ else {
+ GSearchOptionTemplates[SEARCH_CONSTRAINT_CONTAINS_THE_TEXT].option =
+ g_strdup_printf ("'!' -type p -exec %s -c '%%s' {} \\;", GREP_COMMAND);
+ }
+ g_free (cmd_stderr);
+
+ locate = g_find_program_in_path ("locate");
+
+ if (locate != NULL) {
+ GIOChannel * ioc_stdout;
+ gchar ** argv = NULL;
+ gchar *command = NULL;
+ gint child_stdout;
+
+ /* check locate command for -i argument compatibility */
+ command = g_strconcat (locate, " -i /", NULL);
+ g_shell_parse_argv (command, NULL, &argv, NULL);
+ g_free (command);
+
+ gsearch->is_locate_database_check_finished = FALSE;
+ gsearch->is_locate_database_available = FALSE;
+
+ /* run locate command asynchronously because on some systems it can be slow */
+ if (g_spawn_async_with_pipes (g_get_home_dir (), argv, NULL,
+ G_SPAWN_SEARCH_PATH, NULL, NULL,
+ &locate_database_check_command_pid, NULL, &child_stdout,
+ NULL, NULL)) {
+
+ ioc_stdout = g_io_channel_unix_new (child_stdout);
+ g_io_channel_set_encoding (ioc_stdout, NULL, NULL);
+ g_io_channel_set_flags (ioc_stdout, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_add_watch (ioc_stdout, G_IO_IN | G_IO_HUP,
+ handle_locate_command_stdout_io, gsearch);
+ g_io_channel_unref (ioc_stdout);
+ }
+ else {
+ gsearch->is_locate_database_check_finished = TRUE;
+ }
+
+ g_strfreev (argv);
+
+ while (gsearch->is_locate_database_check_finished == FALSE) {
+ if (gtk_events_pending ()) {
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+ }
+ }
+
+ if (gsearch->is_locate_database_available == TRUE) {
+ locate_command_default_options = g_strdup ("-i");
+ }
+ else {
+ /* run locate again to check if it can find anything */
+ command = g_strconcat (locate, " /", NULL);
+ g_shell_parse_argv (command, NULL, &argv, NULL);
+ g_free (command);
+
+ gsearch->is_locate_database_check_finished = FALSE;
+ locate_command_default_options = g_strdup ("");
+
+ /* run locate command asynchronously because on some systems it can be slow */
+ if (g_spawn_async_with_pipes (g_get_home_dir (), argv, NULL,
+ G_SPAWN_SEARCH_PATH, NULL, NULL,
+ &locate_database_check_command_pid, NULL, &child_stdout,
+ NULL, NULL)) {
+
+ ioc_stdout = g_io_channel_unix_new (child_stdout);
+ g_io_channel_set_encoding (ioc_stdout, NULL, NULL);
+ g_io_channel_set_flags (ioc_stdout, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_add_watch (ioc_stdout, G_IO_IN | G_IO_HUP,
+ handle_locate_command_stdout_io, gsearch);
+ g_io_channel_unref (ioc_stdout);
+ }
+ else {
+ gsearch->is_locate_database_check_finished = TRUE;
+ }
+
+ g_strfreev (argv);
+
+ while (gsearch->is_locate_database_check_finished == FALSE) {
+ if (gtk_events_pending ()) {
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+ }
+ }
+
+ if (gsearch->is_locate_database_available == FALSE) {
+ g_warning (_("A locate database has probably not been created."));
+ }
+ }
+ }
+ else {
+ /* locate is not installed */
+ locate_command_default_options = g_strdup ("");
+ gsearch->is_locate_database_available = FALSE;
+ }
+ g_free (grep_cmd);
+ g_free (locate);
+}
+
+static gchar *
+setup_find_name_options (gchar * file)
+{
+ /* This function builds the name options for the find command. This in
+ done to insure that the find command returns hidden files and folders. */
+
+ GString * command;
+ command = g_string_new ("");
+
+ if (strstr (file, "*") == NULL) {
+
+ if ((strlen (file) == 0) || (file[0] != '.')) {
+ g_string_append_printf (command, "\\( %s \"*%s*\" -o %s \".*%s*\" \\) ",
+ find_command_default_name_argument, file,
+ find_command_default_name_argument, file);
+ }
+ else {
+ g_string_append_printf (command, "\\( %s \"*%s*\" -o %s \".*%s*\" -o %s \"%s*\" \\) ",
+ find_command_default_name_argument, file,
+ find_command_default_name_argument, file,
+ find_command_default_name_argument, file);
+ }
+ }
+ else {
+ if (file[0] == '.') {
+ g_string_append_printf (command, "\\( %s \"%s\" -o %s \".*%s\" \\) ",
+ find_command_default_name_argument, file,
+ find_command_default_name_argument, file);
+ }
+ else if (file[0] != '*') {
+ g_string_append_printf (command, "%s \"%s\" ",
+ find_command_default_name_argument, file);
+ }
+ else {
+ if ((strlen (file) >= 1) && (file[1] == '.')) {
+ g_string_append_printf (command, "\\( %s \"%s\" -o %s \"%s\" \\) ",
+ find_command_default_name_argument, file,
+ find_command_default_name_argument, &file[1]);
+ }
+ else {
+ g_string_append_printf (command, "\\( %s \"%s\" -o %s \".%s\" \\) ",
+ find_command_default_name_argument, file,
+ find_command_default_name_argument, file);
+ }
+ }
+ }
+ return g_string_free (command, FALSE);
+}
+
+static gboolean
+has_additional_constraints (GSearchWindow * gsearch)
+{
+ GList * list;
+
+ if (gsearch->available_options_selected_list != NULL) {
+
+ for (list = gsearch->available_options_selected_list; list != NULL; list = g_list_next (list)) {
+
+ GSearchConstraint * constraint = list->data;
+
+ switch (GSearchOptionTemplates[constraint->constraint_id].type) {
+ case SEARCH_CONSTRAINT_TYPE_BOOLEAN:
+ case SEARCH_CONSTRAINT_TYPE_NUMERIC:
+ case SEARCH_CONSTRAINT_TYPE_DATE_BEFORE:
+ case SEARCH_CONSTRAINT_TYPE_DATE_AFTER:
+ return TRUE;
+ case SEARCH_CONSTRAINT_TYPE_TEXT:
+ if (strlen (constraint->data.text) > 0) {
+ return TRUE;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ return FALSE;
+}
+
+static void
+display_dialog_character_set_conversion_error (GtkWidget * window,
+ gchar * string,
+ GError * error)
+{
+ GtkWidget * dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Character set conversion failed for \"%s\""),
+ string);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ (error == NULL) ? " " : error->message, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+}
+
+static void
+start_animation (GSearchWindow * gsearch, gboolean first_pass)
+{
+ if (first_pass == TRUE) {
+
+ gchar *title = NULL;
+
+ title = g_strconcat (_("Searching..."), " - ", _("Search for Files"), NULL);
+ gtk_window_set_title (GTK_WINDOW (gsearch->window), title);
+
+ gtk_label_set_text (GTK_LABEL (gsearch->files_found_label), "");
+ if (g_settings_get_boolean (gsearch->mate_desktop_interface_settings, "enable-animations")) {
+ gtk_spinner_start (GTK_SPINNER (gsearch->progress_spinner));
+ gtk_widget_show (gsearch->progress_spinner);
+ }
+ g_free (title);
+
+ gsearch->focus = gtk_window_get_focus (GTK_WINDOW (gsearch->window));
+
+ gtk_window_set_default (GTK_WINDOW (gsearch->window), gsearch->stop_button);
+ gtk_widget_show (gsearch->stop_button);
+ gtk_widget_set_sensitive (gsearch->stop_button, TRUE);
+ gtk_widget_hide (gsearch->find_button);
+ gtk_widget_set_sensitive (gsearch->find_button, FALSE);
+ gtk_widget_set_sensitive (gsearch->search_results_vbox, TRUE);
+ gtk_widget_set_sensitive (GTK_WIDGET (gsearch->search_results_tree_view), TRUE);
+ gtk_widget_set_sensitive (gsearch->available_options_vbox, FALSE);
+ gtk_widget_set_sensitive (gsearch->show_more_options_expander, FALSE);
+ gtk_widget_set_sensitive (gsearch->name_and_folder_table, FALSE);
+ }
+}
+
+static void
+stop_animation (GSearchWindow * gsearch)
+{
+ gtk_spinner_stop (GTK_SPINNER (gsearch->progress_spinner));
+
+ gtk_window_set_default (GTK_WINDOW (gsearch->window), gsearch->find_button);
+ gtk_widget_set_sensitive (gsearch->available_options_vbox, TRUE);
+ gtk_widget_set_sensitive (gsearch->show_more_options_expander, TRUE);
+ gtk_widget_set_sensitive (gsearch->name_and_folder_table, TRUE);
+ gtk_widget_set_sensitive (gsearch->find_button, TRUE);
+ gtk_widget_hide (gsearch->progress_spinner);
+ gtk_widget_hide (gsearch->stop_button);
+ gtk_widget_show (gsearch->find_button);
+
+ if (GTK_IS_MENU_ITEM (gsearch->search_results_save_results_as_item) == TRUE) {
+ gtk_widget_set_sensitive (gsearch->search_results_save_results_as_item, TRUE);
+ }
+
+ if (gtk_window_get_focus (GTK_WINDOW (gsearch->window)) == NULL) {
+ gtk_window_set_focus (GTK_WINDOW (gsearch->window), gsearch->focus);
+ }
+}
+
+gchar *
+build_search_command (GSearchWindow * gsearch,
+ gboolean first_pass)
+{
+ GString * command;
+ GError * error = NULL;
+ gchar * file_is_named_utf8;
+ gchar * file_is_named_locale;
+ gchar * file_is_named_escaped;
+ gchar * file_is_named_backslashed;
+ gchar * look_in_folder_locale;
+ gchar * look_in_folder_escaped;
+ gchar * look_in_folder_backslashed;
+
+ start_animation (gsearch, first_pass);
+ setup_case_insensitive_arguments (gsearch);
+
+ file_is_named_utf8 = g_strdup ((gchar *) gtk_entry_get_text (GTK_ENTRY (gsearch_history_entry_get_entry
+ (GSEARCH_HISTORY_ENTRY (gsearch->name_contains_entry)))));
+
+ if (!file_is_named_utf8 || !*file_is_named_utf8) {
+ g_free (file_is_named_utf8);
+ file_is_named_utf8 = g_strdup ("*");
+ }
+ else {
+ gchar * locale;
+
+ locale = g_locale_from_utf8 (file_is_named_utf8, -1, NULL, NULL, &error);
+ if (locale == NULL) {
+ stop_animation (gsearch);
+ display_dialog_character_set_conversion_error (gsearch->window, file_is_named_utf8, error);
+ g_free (file_is_named_utf8);
+ g_error_free (error);
+ return NULL;
+ }
+ gsearch_history_entry_prepend_text (GSEARCH_HISTORY_ENTRY (gsearch->name_contains_entry), file_is_named_utf8);
+
+ if ((strstr (locale, "*") == NULL) && (strstr (locale, "?") == NULL)) {
+ gchar *tmp;
+
+ tmp = file_is_named_utf8;
+ file_is_named_utf8 = g_strconcat ("*", file_is_named_utf8, "*", NULL);
+ g_free (tmp);
+ }
+
+ g_free (locale);
+ }
+
+ file_is_named_locale = g_locale_from_utf8 (file_is_named_utf8, -1, NULL, NULL, &error);
+ if (file_is_named_locale == NULL) {
+ stop_animation (gsearch);
+ display_dialog_character_set_conversion_error (gsearch->window, file_is_named_utf8, error);
+ g_free (file_is_named_utf8);
+ g_error_free (error);
+ return NULL;
+ }
+
+ look_in_folder_locale = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (gsearch->look_in_folder_button));
+
+ if (look_in_folder_locale == NULL) {
+ /* If for some reason a path was not returned fallback to the user's home directory. */
+ look_in_folder_locale = g_strdup (g_get_home_dir ());
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (gsearch->look_in_folder_button), look_in_folder_locale);
+ }
+
+ if (!g_str_has_suffix (look_in_folder_locale, G_DIR_SEPARATOR_S)) {
+ gchar *tmp;
+
+ tmp = look_in_folder_locale;
+ look_in_folder_locale = g_strconcat (look_in_folder_locale, G_DIR_SEPARATOR_S, NULL);
+ g_free (tmp);
+ }
+ g_free (gsearch->command_details->look_in_folder_string);
+
+ look_in_folder_backslashed = backslash_backslash_characters (look_in_folder_locale);
+ look_in_folder_escaped = escape_double_quotes (look_in_folder_backslashed);
+ gsearch->command_details->look_in_folder_string = g_strdup (look_in_folder_locale);
+
+ command = g_string_new ("");
+ gsearch->command_details->is_command_show_hidden_files_enabled = FALSE;
+ gsearch->command_details->name_contains_regex_string = NULL;
+ gsearch->command_details->name_contains_pattern_string = NULL;
+
+ gsearch->command_details->is_command_first_pass = first_pass;
+ if (gsearch->command_details->is_command_first_pass == TRUE) {
+ gsearch->command_details->is_command_using_quick_mode = FALSE;
+ }
+
+ if ((gtk_widget_get_visible (gsearch->available_options_vbox) == FALSE) ||
+ (has_additional_constraints (gsearch) == FALSE)) {
+
+ file_is_named_backslashed = backslash_backslash_characters (file_is_named_locale);
+ file_is_named_escaped = escape_double_quotes (file_is_named_backslashed);
+ gsearch->command_details->name_contains_pattern_string = g_strdup (file_is_named_utf8);
+
+ if (gsearch->command_details->is_command_first_pass == TRUE) {
+
+ gchar * locate;
+ CajaSpeedTradeoff show_thumbnails_enum;
+ gboolean disable_quick_search;
+
+ locate = g_find_program_in_path ("locate");
+ disable_quick_search = g_settings_get_boolean (gsearch->mate_search_tool_settings, "disable-quick-search");
+ gsearch->command_details->is_command_second_pass_enabled = !g_settings_get_boolean (gsearch->mate_search_tool_settings, "disable-quick-search-second-scan");
+
+ /* Use caja settings for thumbnails if caja is installed, else fall back to the caja default */
+ if (gsearch->caja_schema_exists) {
+ show_thumbnails_enum = g_settings_get_enum (gsearch->caja_settings, "show-image-thumbnails");
+ } else {
+ show_thumbnails_enum = SPEED_TRADEOFF_LOCAL_ONLY;
+ }
+
+ if (show_thumbnails_enum == SPEED_TRADEOFF_ALWAYS ||
+ show_thumbnails_enum == SPEED_TRADEOFF_LOCAL_ONLY) {
+ GVariant * value;
+ guint64 size_limit = 10485760;
+
+ if (gsearch->caja_schema_exists) {
+ value = g_settings_get_value (gsearch->caja_settings, "thumbnail-limit");
+ if (value) {
+ size_limit = g_variant_get_uint64 (value);
+ g_variant_unref (value);
+ }
+ }
+
+ gsearch->show_thumbnails = TRUE;
+ gsearch->show_thumbnails_file_size_limit = size_limit;
+ }
+ else {
+ gsearch->show_thumbnails = FALSE;
+ gsearch->show_thumbnails_file_size_limit = 0;
+ }
+
+ if ((disable_quick_search == FALSE)
+ && (gsearch->is_locate_database_available == TRUE)
+ && (locate != NULL)
+ && (is_quick_search_excluded_path (look_in_folder_locale) == FALSE)) {
+
+ g_string_append_printf (command, "%s %s \"%s*%s\"",
+ locate,
+ locate_command_default_options,
+ look_in_folder_escaped,
+ file_is_named_escaped);
+ gsearch->command_details->is_command_using_quick_mode = TRUE;
+ }
+ else {
+ g_string_append_printf (command, "find \"%s\" %s \"%s\" -print",
+ look_in_folder_escaped,
+ find_command_default_name_argument,
+ file_is_named_escaped);
+ }
+ g_free (locate);
+ }
+ else {
+ g_string_append_printf (command, "find \"%s\" %s \"%s\" -print",
+ look_in_folder_escaped,
+ find_command_default_name_argument,
+ file_is_named_escaped);
+ }
+ }
+ else {
+ GList * list;
+ gboolean disable_mount_argument = TRUE;
+
+ gsearch->command_details->is_command_regex_matching_enabled = FALSE;
+ file_is_named_backslashed = backslash_backslash_characters (file_is_named_locale);
+ file_is_named_escaped = escape_double_quotes (file_is_named_backslashed);
+
+ g_string_append_printf (command, "find \"%s\" %s",
+ look_in_folder_escaped,
+ setup_find_name_options (file_is_named_escaped));
+
+ for (list = gsearch->available_options_selected_list; list != NULL; list = g_list_next (list)) {
+
+ GSearchConstraint * constraint = list->data;
+
+ switch (GSearchOptionTemplates[constraint->constraint_id].type) {
+ case SEARCH_CONSTRAINT_TYPE_BOOLEAN:
+ if (strcmp (GSearchOptionTemplates[constraint->constraint_id].option, "EXCLUDE_OTHER_FILESYSTEMS") == 0) {
+ disable_mount_argument = FALSE;
+ }
+ else if (strcmp (GSearchOptionTemplates[constraint->constraint_id].option, "SHOW_HIDDEN_FILES") == 0) {
+ gsearch->command_details->is_command_show_hidden_files_enabled = TRUE;
+ }
+ else {
+ g_string_append_printf (command, "%s ",
+ GSearchOptionTemplates[constraint->constraint_id].option);
+ }
+ break;
+ case SEARCH_CONSTRAINT_TYPE_TEXT:
+ if (strcmp (GSearchOptionTemplates[constraint->constraint_id].option, "-regex '%s'") == 0) {
+
+ gchar * escaped;
+ gchar * regex;
+
+ escaped = backslash_special_characters (constraint->data.text);
+ regex = escape_single_quotes (escaped);
+
+ if (regex != NULL) {
+ gsearch->command_details->is_command_regex_matching_enabled = TRUE;
+ gsearch->command_details->name_contains_regex_string = g_locale_from_utf8 (regex, -1, NULL, NULL, NULL);
+ }
+
+ g_free (escaped);
+ g_free (regex);
+ }
+ else {
+ gchar * escaped;
+ gchar * backslashed;
+ gchar * locale;
+
+ backslashed = backslash_special_characters (constraint->data.text);
+ escaped = escape_single_quotes (backslashed);
+
+ locale = g_locale_from_utf8 (escaped, -1, NULL, NULL, NULL);
+
+ if (strlen (locale) != 0) {
+ g_string_append_printf (command,
+ GSearchOptionTemplates[constraint->constraint_id].option,
+ locale);
+
+ g_string_append_c (command, ' ');
+ }
+
+ g_free (escaped);
+ g_free (backslashed);
+ g_free (locale);
+ }
+ break;
+ case SEARCH_CONSTRAINT_TYPE_NUMERIC:
+ g_string_append_printf (command,
+ GSearchOptionTemplates[constraint->constraint_id].option,
+ (constraint->data.number * 1024),
+ (constraint->data.number * 1024));
+ g_string_append_c (command, ' ');
+ break;
+ case SEARCH_CONSTRAINT_TYPE_DATE_BEFORE:
+ g_string_append_printf (command,
+ GSearchOptionTemplates[constraint->constraint_id].option,
+ constraint->data.time);
+ g_string_append_c (command, ' ');
+ break;
+ case SEARCH_CONSTRAINT_TYPE_DATE_AFTER:
+ g_string_append_printf (command,
+ GSearchOptionTemplates[constraint->constraint_id].option,
+ constraint->data.time,
+ constraint->data.time);
+ g_string_append_c (command, ' ');
+ break;
+ default:
+ break;
+ }
+ }
+ gsearch->command_details->name_contains_pattern_string = g_strdup ("*");
+
+ if (disable_mount_argument != TRUE) {
+ g_string_append (command, "-xdev ");
+ }
+
+ g_string_append (command, "-print ");
+ }
+ g_free (file_is_named_locale);
+ g_free (file_is_named_utf8);
+ g_free (file_is_named_backslashed);
+ g_free (file_is_named_escaped);
+ g_free (look_in_folder_locale);
+ g_free (look_in_folder_backslashed);
+ g_free (look_in_folder_escaped);
+
+ return g_string_free (command, FALSE);
+}
+
+static void
+add_file_to_search_results (const gchar * file,
+ GtkListStore * store,
+ GtkTreeIter * iter,
+ GSearchWindow * gsearch)
+{
+ GdkPixbuf * pixbuf;
+ GSearchMonitor * monitor;
+ GFileMonitor * handle;
+ GFileInfo * file_info;
+ GFile * g_file;
+ GError * error = NULL;
+ GTimeVal time_val;
+ GtkTreePath * path;
+ GtkTreeRowReference * reference;
+ gchar * description;
+ gchar * readable_size;
+ gchar * readable_date;
+ gchar * utf8_base_name;
+ gchar * utf8_relative_dir_name;
+ gchar * base_name;
+ gchar * dir_name;
+ gchar * relative_dir_name;
+ gchar * look_in_folder;
+
+ if (g_hash_table_lookup_extended (gsearch->search_results_filename_hash_table, file, NULL, NULL) == TRUE) {
+ return;
+ }
+
+ if ((g_file_test (file, G_FILE_TEST_EXISTS) != TRUE) &&
+ (g_file_test (file, G_FILE_TEST_IS_SYMLINK) != TRUE)) {
+ return;
+ }
+
+ g_hash_table_insert (gsearch->search_results_filename_hash_table, g_strdup (file), NULL);
+
+ if (gtk_tree_view_get_headers_visible (GTK_TREE_VIEW (gsearch->search_results_tree_view)) == FALSE) {
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (gsearch->search_results_tree_view), TRUE);
+ }
+
+ g_file = g_file_new_for_path (file);
+ file_info = g_file_query_info (g_file, "standard::*,time::modified,thumbnail::path", 0, NULL, NULL);
+
+ pixbuf = get_file_pixbuf (gsearch, file_info);
+ description = get_file_type_description (file, file_info);
+ readable_size = g_format_size (g_file_info_get_size (file_info));
+
+ g_file_info_get_modification_time (file_info, &time_val);
+ readable_date = get_readable_date (gsearch->search_results_date_format, time_val.tv_sec);
+
+ base_name = g_path_get_basename (file);
+ dir_name = g_path_get_dirname (file);
+
+ look_in_folder = g_strdup (gsearch->command_details->look_in_folder_string);
+ if (strlen (look_in_folder) > 1) {
+ gchar * path_str;
+
+ if (g_str_has_suffix (look_in_folder, G_DIR_SEPARATOR_S) == TRUE) {
+ look_in_folder[strlen (look_in_folder) - 1] = '\0';
+ }
+ path_str = g_path_get_dirname (look_in_folder);
+ if (strcmp (path_str, G_DIR_SEPARATOR_S) == 0) {
+ relative_dir_name = g_strconcat (&dir_name[strlen (path_str)], NULL);
+ }
+ else {
+ relative_dir_name = g_strconcat (&dir_name[strlen (path_str) + 1], NULL);
+ }
+ g_free (path_str);
+ }
+ else {
+ relative_dir_name = g_strdup (dir_name);
+ }
+
+ utf8_base_name = g_filename_display_basename (file);
+ utf8_relative_dir_name = g_filename_display_name (relative_dir_name);
+
+ gtk_list_store_append (GTK_LIST_STORE (store), iter);
+ gtk_list_store_set (GTK_LIST_STORE (store), iter,
+ COLUMN_ICON, pixbuf,
+ COLUMN_NAME, utf8_base_name,
+ COLUMN_RELATIVE_PATH, utf8_relative_dir_name,
+ COLUMN_LOCALE_FILE, file,
+ COLUMN_READABLE_SIZE, readable_size,
+ COLUMN_SIZE, (-1) * (gdouble) g_file_info_get_size(file_info),
+ COLUMN_TYPE, (description != NULL) ? description : g_strdup (g_file_info_get_content_type (file_info)),
+ COLUMN_READABLE_DATE, readable_date,
+ COLUMN_DATE, (-1) * (gdouble) time_val.tv_sec,
+ COLUMN_NO_FILES_FOUND, FALSE,
+ -1);
+
+ monitor = g_slice_new0 (GSearchMonitor);
+ if (monitor) {
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+ reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
+ gtk_tree_path_free (path);
+
+ handle = g_file_monitor_file (g_file, G_FILE_MONITOR_EVENT_DELETED, NULL, &error);
+
+ if (error == NULL) {
+ monitor->gsearch = gsearch;
+ monitor->reference = reference;
+ monitor->handle = handle;
+ gtk_list_store_set (GTK_LIST_STORE (store), iter,
+ COLUMN_MONITOR, monitor, -1);
+
+ g_signal_connect (handle, "changed",
+ G_CALLBACK (file_changed_cb), monitor);
+ }
+ else {
+ gtk_tree_row_reference_free (reference);
+ g_slice_free (GSearchMonitor, monitor);
+ g_clear_error (&error);
+ }
+ }
+
+ g_object_unref (g_file);
+ g_object_unref (file_info);
+ g_free (base_name);
+ g_free (dir_name);
+ g_free (relative_dir_name);
+ g_free (utf8_base_name);
+ g_free (utf8_relative_dir_name);
+ g_free (look_in_folder);
+ g_free (description);
+ g_free (readable_size);
+ g_free (readable_date);
+}
+
+static void
+add_no_files_found_message (GSearchWindow * gsearch)
+{
+ /* When the list is empty append a 'No Files Found.' message. */
+ gtk_widget_set_sensitive (GTK_WIDGET (gsearch->search_results_tree_view), FALSE);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (gsearch->search_results_tree_view), FALSE);
+ gtk_tree_view_column_set_visible (gsearch->search_results_folder_column, FALSE);
+ gtk_tree_view_column_set_visible (gsearch->search_results_size_column, FALSE);
+ gtk_tree_view_column_set_visible (gsearch->search_results_type_column, FALSE);
+ gtk_tree_view_column_set_visible (gsearch->search_results_date_column, FALSE);
+ gtk_tree_view_columns_autosize (GTK_TREE_VIEW (gsearch->search_results_tree_view));
+ g_object_set (gsearch->search_results_name_cell_renderer,
+ "underline", PANGO_UNDERLINE_NONE,
+ "underline-set", FALSE,
+ NULL);
+ gtk_list_store_append (GTK_LIST_STORE (gsearch->search_results_list_store), &gsearch->search_results_iter);
+ gtk_list_store_set (GTK_LIST_STORE (gsearch->search_results_list_store), &gsearch->search_results_iter,
+ COLUMN_ICON, NULL,
+ COLUMN_NAME, _("No files found"),
+ COLUMN_RELATIVE_PATH, "",
+ COLUMN_LOCALE_FILE, "",
+ COLUMN_READABLE_SIZE, "",
+ COLUMN_SIZE, (gdouble) 0,
+ COLUMN_TYPE, "",
+ COLUMN_READABLE_DATE, "",
+ COLUMN_DATE, (gdouble) 0,
+ COLUMN_NO_FILES_FOUND, TRUE,
+ -1);
+}
+
+void
+update_search_counts (GSearchWindow * gsearch)
+{
+ gchar * title_bar_string = NULL;
+ gchar * message_string = NULL;
+ gchar * stopped_string = NULL;
+ gchar * tmp;
+ gint total_files;
+
+ if (gsearch->command_details->command_status == ABORTED) {
+ stopped_string = g_strdup (_("(stopped)"));
+ }
+
+ total_files = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (gsearch->search_results_list_store), NULL);
+
+ if (total_files == 0) {
+ title_bar_string = g_strdup (_("No Files Found"));
+ message_string = g_strdup (_("No files found"));
+ add_no_files_found_message (gsearch);
+ }
+ else {
+ title_bar_string = g_strdup_printf (ngettext ("%'d File Found",
+ "%'d Files Found",
+ total_files),
+ total_files);
+ message_string = g_strdup_printf (ngettext ("%'d file found",
+ "%'d files found",
+ total_files),
+ total_files);
+ }
+
+ if (stopped_string != NULL) {
+ tmp = message_string;
+ message_string = g_strconcat (message_string, " ", stopped_string, NULL);
+ g_free (tmp);
+
+ tmp = title_bar_string;
+ title_bar_string = g_strconcat (title_bar_string, " ", stopped_string, NULL);
+ g_free (tmp);
+ }
+
+ tmp = title_bar_string;
+ title_bar_string = g_strconcat (title_bar_string, " - ", _("Search for Files"), NULL);
+ gtk_window_set_title (GTK_WINDOW (gsearch->window), title_bar_string);
+ g_free (tmp);
+
+ gtk_label_set_text (GTK_LABEL (gsearch->files_found_label), message_string);
+
+ g_free (title_bar_string);
+ g_free (message_string);
+ g_free (stopped_string);
+}
+
+static void
+intermediate_file_count_update (GSearchWindow * gsearch)
+{
+ gchar * string;
+ gint count;
+
+ count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (gsearch->search_results_list_store), NULL);
+
+ if (count > 0) {
+
+ string = g_strdup_printf (ngettext ("%'d file found",
+ "%'d files found",
+ count),
+ count);
+
+ gtk_label_set_text (GTK_LABEL (gsearch->files_found_label), string);
+ g_free (string);
+ }
+}
+
+gboolean
+tree_model_iter_free_monitor (GtkTreeModel * model,
+ GtkTreePath * path,
+ GtkTreeIter * iter,
+ gpointer data)
+{
+ GSearchMonitor * monitor;
+
+ g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
+
+ gtk_tree_model_get (model, iter, COLUMN_MONITOR, &monitor, -1);
+ if (monitor) {
+ g_file_monitor_cancel (monitor->handle);
+ gtk_tree_row_reference_free (monitor->reference);
+ g_slice_free (GSearchMonitor, monitor);
+ }
+ return FALSE;
+}
+
+static GtkTreeModel *
+gsearch_create_list_of_templates (void)
+{
+ GtkListStore * store;
+ GtkTreeIter iter;
+ gint idx;
+
+ store = gtk_list_store_new (1, G_TYPE_STRING);
+
+ for (idx = 0; GSearchOptionTemplates[idx].type != SEARCH_CONSTRAINT_TYPE_NONE; idx++) {
+
+ if (GSearchOptionTemplates[idx].type == SEARCH_CONSTRAINT_TYPE_SEPARATOR) {
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, "separator", -1);
+ }
+ else {
+ gchar * text = remove_mnemonic_character (_(GSearchOptionTemplates[idx].desc));
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, text, -1);
+ g_free (text);
+ }
+ }
+ return GTK_TREE_MODEL (store);
+}
+
+static void
+set_constraint_info_defaults (GSearchConstraint * opt)
+{
+ switch (GSearchOptionTemplates[opt->constraint_id].type) {
+ case SEARCH_CONSTRAINT_TYPE_BOOLEAN:
+ break;
+ case SEARCH_CONSTRAINT_TYPE_TEXT:
+ opt->data.text = "";
+ break;
+ case SEARCH_CONSTRAINT_TYPE_NUMERIC:
+ opt->data.number = 0;
+ break;
+ case SEARCH_CONSTRAINT_TYPE_DATE_BEFORE:
+ case SEARCH_CONSTRAINT_TYPE_DATE_AFTER:
+ opt->data.time = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+update_constraint_info (GSearchConstraint * constraint,
+ gchar * info)
+{
+ switch (GSearchOptionTemplates[constraint->constraint_id].type) {
+ case SEARCH_CONSTRAINT_TYPE_TEXT:
+ constraint->data.text = info;
+ break;
+ case SEARCH_CONSTRAINT_TYPE_NUMERIC:
+ sscanf (info, "%d", &constraint->data.number);
+ break;
+ case SEARCH_CONSTRAINT_TYPE_DATE_BEFORE:
+ case SEARCH_CONSTRAINT_TYPE_DATE_AFTER:
+ sscanf (info, "%d", &constraint->data.time);
+ break;
+ default:
+ g_warning (_("Entry changed called for a non entry option!"));
+ break;
+ }
+}
+
+void
+set_constraint_selected_state (GSearchWindow * gsearch,
+ gint constraint_id,
+ gboolean state)
+{
+ gint idx;
+
+ GSearchOptionTemplates[constraint_id].is_selected = state;
+
+ for (idx = 0; GSearchOptionTemplates[idx].type != SEARCH_CONSTRAINT_TYPE_NONE; idx++) {
+ if (GSearchOptionTemplates[idx].is_selected == FALSE) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (gsearch->available_options_combo_box), idx);
+ gtk_widget_set_sensitive (gsearch->available_options_add_button, TRUE);
+ gtk_widget_set_sensitive (gsearch->available_options_combo_box, TRUE);
+ gtk_widget_set_sensitive (gsearch->available_options_label, TRUE);
+ return;
+ }
+ }
+ gtk_widget_set_sensitive (gsearch->available_options_add_button, FALSE);
+ gtk_widget_set_sensitive (gsearch->available_options_combo_box, FALSE);
+ gtk_widget_set_sensitive (gsearch->available_options_label, FALSE);
+}
+
+void
+set_constraint_gsettings_boolean (gint constraint_id,
+ gboolean flag)
+{
+ GSettings * select_settings;
+
+ select_settings = g_settings_new ("org.mate.search-tool.select");
+
+ switch (constraint_id) {
+
+ case SEARCH_CONSTRAINT_CONTAINS_THE_TEXT:
+ g_settings_set_boolean (select_settings, "contains-the-text",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_DATE_MODIFIED_BEFORE:
+ g_settings_set_boolean (select_settings, "date-modified-less-than",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_DATE_MODIFIED_AFTER:
+ g_settings_set_boolean (select_settings, "date-modified-more-than",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_SIZE_IS_MORE_THAN:
+ g_settings_set_boolean (select_settings, "size-at-least",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_SIZE_IS_LESS_THAN:
+ g_settings_set_boolean (select_settings, "size-at-most",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_FILE_IS_EMPTY:
+ g_settings_set_boolean (select_settings, "file-is-empty",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_OWNED_BY_USER:
+ g_settings_set_boolean (select_settings, "owned-by-user",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_OWNED_BY_GROUP:
+ g_settings_set_boolean (select_settings, "owned-by-group",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_OWNER_IS_UNRECOGNIZED:
+ g_settings_set_boolean (select_settings, "owner-is-unrecognized",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_FILE_IS_NOT_NAMED:
+ g_settings_set_boolean (select_settings, "name-does-not-contain",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_FILE_MATCHES_REGULAR_EXPRESSION:
+ g_settings_set_boolean (select_settings, "name-matches-regular-expression",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_SHOW_HIDDEN_FILES_AND_FOLDERS:
+ g_settings_set_boolean (select_settings, "show-hidden-files-and-folders",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_FOLLOW_SYMBOLIC_LINKS:
+ g_settings_set_boolean (select_settings, "follow-symbolic-links",
+ flag);
+ break;
+ case SEARCH_CONSTRAINT_SEARCH_OTHER_FILESYSTEMS:
+ g_settings_set_boolean (select_settings, "exclude-other-filesystems",
+ flag);
+ break;
+
+ default:
+ break;
+ }
+ g_object_unref (select_settings);
+}
+
+/*
+ * add_atk_namedesc
+ * @widget : The Gtk Widget for which @name and @desc are added.
+ * @name : Accessible Name
+ * @desc : Accessible Description
+ * Description: This function adds accessible name and description to a
+ * Gtk widget.
+ */
+
+static void
+add_atk_namedesc (GtkWidget * widget,
+ const gchar * name,
+ const gchar * desc)
+{
+ AtkObject * atk_widget;
+
+ g_assert (GTK_IS_WIDGET (widget));
+
+ atk_widget = gtk_widget_get_accessible (widget);
+
+ if (name != NULL)
+ atk_object_set_name (atk_widget, name);
+ if (desc !=NULL)
+ atk_object_set_description (atk_widget, desc);
+}
+
+/*
+ * add_atk_relation
+ * @obj1 : The first widget in the relation @rel_type
+ * @obj2 : The second widget in the relation @rel_type.
+ * @rel_type : Relation type which relates @obj1 and @obj2
+ * Description: This function establishes Atk Relation between two given
+ * objects.
+ */
+
+static void
+add_atk_relation (GtkWidget * obj1,
+ GtkWidget * obj2,
+ AtkRelationType rel_type)
+{
+ AtkObject * atk_obj1, * atk_obj2;
+ AtkRelationSet * relation_set;
+ AtkRelation * relation;
+
+ g_assert (GTK_IS_WIDGET (obj1));
+ g_assert (GTK_IS_WIDGET (obj2));
+
+ atk_obj1 = gtk_widget_get_accessible (obj1);
+
+ atk_obj2 = gtk_widget_get_accessible (obj2);
+
+ relation_set = atk_object_ref_relation_set (atk_obj1);
+ relation = atk_relation_new (&atk_obj2, 1, rel_type);
+ atk_relation_set_add (relation_set, relation);
+ g_object_unref (G_OBJECT (relation));
+
+}
+
+static void
+gsearch_setup_goption_descriptions (void)
+{
+ gint i = 1;
+ gint j;
+
+ GSearchGOptionEntries[i++].description = g_strdup (_("Set the text of \"Name contains\" search option"));
+ GSearchGOptionEntries[i++].description = g_strdup (_("Set the text of \"Look in folder\" search option"));
+ GSearchGOptionEntries[i++].description = g_strdup (_("Sort files by one of the following: name, folder, size, type, or date"));
+ GSearchGOptionEntries[i++].description = g_strdup (_("Set sort order to descending, the default is ascending"));
+ GSearchGOptionEntries[i++].description = g_strdup (_("Automatically start a search"));
+
+ for (j = 0; GSearchOptionTemplates[j].type != SEARCH_CONSTRAINT_TYPE_NONE; j++) {
+ if (GSearchOptionTemplates[j].type != SEARCH_CONSTRAINT_TYPE_SEPARATOR) {
+ gchar *text = remove_mnemonic_character (_(GSearchOptionTemplates[j].desc));
+ if (GSearchOptionTemplates[j].type == SEARCH_CONSTRAINT_TYPE_BOOLEAN) {
+ GSearchGOptionEntries[i++].description = g_strdup_printf (_("Select the \"%s\" search option"), text);
+ }
+ else {
+ GSearchGOptionEntries[i++].description = g_strdup_printf (_("Select and set the \"%s\" search option"), text);
+ }
+ g_free (text);
+ }
+ }
+}
+
+static gboolean
+handle_goption_args (GSearchWindow * gsearch)
+{
+ gboolean goption_args_found = FALSE;
+ gint sort_by;
+
+ if (GSearchGOptionArguments.name != NULL) {
+ goption_args_found = TRUE;
+ gtk_entry_set_text (GTK_ENTRY (gsearch_history_entry_get_entry (GSEARCH_HISTORY_ENTRY (gsearch->name_contains_entry))),
+ g_locale_to_utf8 (GSearchGOptionArguments.name, -1, NULL, NULL, NULL));
+ }
+ if (GSearchGOptionArguments.path != NULL) {
+ goption_args_found = TRUE;
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (gsearch->look_in_folder_button),
+ g_locale_to_utf8 (GSearchGOptionArguments.path, -1, NULL, NULL, NULL));
+ }
+ if (GSearchGOptionArguments.contains != NULL) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_CONTAINS_THE_TEXT,
+ GSearchGOptionArguments.contains, TRUE);
+ }
+ if (GSearchGOptionArguments.mtimeless != NULL) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_DATE_MODIFIED_BEFORE,
+ GSearchGOptionArguments.mtimeless, TRUE);
+ }
+ if (GSearchGOptionArguments.mtimemore != NULL) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_DATE_MODIFIED_AFTER,
+ GSearchGOptionArguments.mtimemore, TRUE);
+ }
+ if (GSearchGOptionArguments.sizemore != NULL) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_SIZE_IS_MORE_THAN,
+ GSearchGOptionArguments.sizemore, TRUE);
+ }
+ if (GSearchGOptionArguments.sizeless != NULL) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_SIZE_IS_LESS_THAN,
+ GSearchGOptionArguments.sizeless, TRUE);
+ }
+ if (GSearchGOptionArguments.empty) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_FILE_IS_EMPTY, NULL, TRUE);
+ }
+ if (GSearchGOptionArguments.user != NULL) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_OWNED_BY_USER,
+ GSearchGOptionArguments.user, TRUE);
+ }
+ if (GSearchGOptionArguments.group != NULL) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_OWNED_BY_GROUP,
+ GSearchGOptionArguments.group, TRUE);
+ }
+ if (GSearchGOptionArguments.nouser) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_OWNER_IS_UNRECOGNIZED, NULL, TRUE);
+ }
+ if (GSearchGOptionArguments.notnamed != NULL) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_FILE_IS_NOT_NAMED,
+ GSearchGOptionArguments.notnamed, TRUE);
+ }
+ if (GSearchGOptionArguments.regex != NULL) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_FILE_MATCHES_REGULAR_EXPRESSION,
+ GSearchGOptionArguments.regex, TRUE);
+ }
+ if (GSearchGOptionArguments.hidden) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_SHOW_HIDDEN_FILES_AND_FOLDERS, NULL, TRUE);
+ }
+ if (GSearchGOptionArguments.follow) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_FOLLOW_SYMBOLIC_LINKS, NULL, TRUE);
+ }
+ if (GSearchGOptionArguments.mounts) {
+ goption_args_found = TRUE;
+ add_constraint (gsearch, SEARCH_CONSTRAINT_SEARCH_OTHER_FILESYSTEMS, NULL, TRUE);
+ }
+ if (GSearchGOptionArguments.sortby != NULL) {
+
+ goption_args_found = TRUE;
+ if (strcmp (GSearchGOptionArguments.sortby, "name") == 0) {
+ sort_by = COLUMN_NAME;
+ }
+ else if (strcmp (GSearchGOptionArguments.sortby, "folder") == 0) {
+ sort_by = COLUMN_RELATIVE_PATH;
+ }
+ else if (strcmp (GSearchGOptionArguments.sortby, "size") == 0) {
+ sort_by = COLUMN_SIZE;
+ }
+ else if (strcmp (GSearchGOptionArguments.sortby, "type") == 0) {
+ sort_by = COLUMN_TYPE;
+ }
+ else if (strcmp (GSearchGOptionArguments.sortby, "date") == 0) {
+ sort_by = COLUMN_DATE;
+ }
+ else {
+ g_warning (_("Invalid option passed to sortby command line argument."));
+ sort_by = COLUMN_NAME;
+ }
+
+ if (GSearchGOptionArguments.descending) {
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (gsearch->search_results_list_store), sort_by,
+ GTK_SORT_DESCENDING);
+ }
+ else {
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (gsearch->search_results_list_store), sort_by,
+ GTK_SORT_ASCENDING);
+ }
+ }
+ if (GSearchGOptionArguments.start) {
+ goption_args_found = TRUE;
+ click_find_cb (gsearch->find_button, (gpointer) gsearch);
+ }
+ return goption_args_found;
+}
+
+static gboolean
+handle_search_command_stdout_io (GIOChannel * ioc,
+ GIOCondition condition,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ gboolean broken_pipe = FALSE;
+
+ if (condition & G_IO_IN) {
+
+ GError * error = NULL;
+ GTimer * timer;
+ GString * string;
+ GdkRectangle prior_rect;
+ GdkRectangle after_rect;
+ gulong duration;
+ gint look_in_folder_string_length;
+
+ string = g_string_new (NULL);
+ look_in_folder_string_length = strlen (gsearch->command_details->look_in_folder_string);
+
+ timer = g_timer_new ();
+ g_timer_start (timer);
+
+ while (ioc->is_readable != TRUE);
+
+ do {
+ gchar * utf8 = NULL;
+ gchar * filename = NULL;
+ gint status;
+
+ if (gsearch->command_details->command_status == MAKE_IT_STOP) {
+ broken_pipe = TRUE;
+ break;
+ }
+ else if (gsearch->command_details->command_status != RUNNING) {
+ break;
+ }
+
+ do {
+ status = g_io_channel_read_line_string (ioc, string, NULL, &error);
+
+ if (status == G_IO_STATUS_EOF) {
+ broken_pipe = TRUE;
+ }
+ else if (status == G_IO_STATUS_AGAIN) {
+ if (gtk_events_pending ()) {
+ intermediate_file_count_update (gsearch);
+ while (gtk_events_pending ()) {
+ if (gsearch->command_details->command_status == MAKE_IT_QUIT) {
+ return FALSE;
+ }
+ gtk_main_iteration ();
+ }
+
+ }
+ }
+
+ } while (status == G_IO_STATUS_AGAIN && broken_pipe == FALSE);
+
+ if (broken_pipe == TRUE) {
+ break;
+ }
+
+ if (status != G_IO_STATUS_NORMAL) {
+ if (error != NULL) {
+ g_warning ("handle_search_command_stdout_io(): %s", error->message);
+ g_error_free (error);
+ }
+ continue;
+ }
+
+ string = g_string_truncate (string, string->len - 1);
+ if (string->len <= 1) {
+ continue;
+ }
+
+ utf8 = g_filename_display_name (string->str);
+ if (utf8 == NULL) {
+ continue;
+ }
+
+ if (strncmp (string->str, gsearch->command_details->look_in_folder_string, look_in_folder_string_length) == 0) {
+
+ if (strlen (string->str) != look_in_folder_string_length) {
+
+ filename = g_path_get_basename (utf8);
+
+ if (fnmatch (gsearch->command_details->name_contains_pattern_string, filename, FNM_NOESCAPE | FNM_CASEFOLD ) != FNM_NOMATCH) {
+ if (gsearch->command_details->is_command_show_hidden_files_enabled) {
+ if (gsearch->command_details->is_command_regex_matching_enabled == FALSE) {
+ add_file_to_search_results (string->str, gsearch->search_results_list_store, &gsearch->search_results_iter, gsearch);
+ }
+ else if (compare_regex (gsearch->command_details->name_contains_regex_string, filename)) {
+ add_file_to_search_results (string->str, gsearch->search_results_list_store, &gsearch->search_results_iter, gsearch);
+ }
+ }
+ else if ((is_path_hidden (string->str) == FALSE ||
+ is_path_hidden (gsearch->command_details->look_in_folder_string) == TRUE) &&
+ (!g_str_has_suffix (string->str, "~"))) {
+ if (gsearch->command_details->is_command_regex_matching_enabled == FALSE) {
+ add_file_to_search_results (string->str, gsearch->search_results_list_store, &gsearch->search_results_iter, gsearch);
+ }
+ else if (compare_regex (gsearch->command_details->name_contains_regex_string, filename)) {
+ add_file_to_search_results (string->str, gsearch->search_results_list_store, &gsearch->search_results_iter, gsearch);
+ }
+ }
+ }
+ }
+ }
+ g_free (utf8);
+ g_free (filename);
+
+ gtk_tree_view_get_visible_rect (GTK_TREE_VIEW (gsearch->search_results_tree_view), &prior_rect);
+
+ if (prior_rect.y == 0) {
+ gtk_tree_view_get_visible_rect (GTK_TREE_VIEW (gsearch->search_results_tree_view), &after_rect);
+ if (after_rect.y <= 40) { /* limit this hack to the first few pixels */
+ gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (gsearch->search_results_tree_view), -1, 0);
+ }
+ }
+
+ g_timer_elapsed (timer, &duration);
+
+ if (duration > MATE_SEARCH_TOOL_REFRESH_DURATION) {
+ if (gtk_events_pending ()) {
+ intermediate_file_count_update (gsearch);
+ while (gtk_events_pending ()) {
+ if (gsearch->command_details->command_status == MAKE_IT_QUIT) {
+ return FALSE;
+ }
+ gtk_main_iteration ();
+ }
+ }
+ g_timer_reset (timer);
+ }
+
+ } while (g_io_channel_get_buffer_condition (ioc) & G_IO_IN);
+
+ g_string_free (string, TRUE);
+ g_timer_destroy (timer);
+ }
+
+ if (!(condition & G_IO_IN) || broken_pipe == TRUE) {
+
+ g_io_channel_shutdown (ioc, TRUE, NULL);
+
+ if ((gsearch->command_details->command_status != MAKE_IT_STOP)
+ && (gsearch->command_details->is_command_using_quick_mode == TRUE)
+ && (gsearch->command_details->is_command_first_pass == TRUE)
+ && (gsearch->command_details->is_command_second_pass_enabled == TRUE)
+ && (is_second_scan_excluded_path (gsearch->command_details->look_in_folder_string) == FALSE)) {
+
+ gchar * command;
+
+ /* Free these strings now because they are reassign values during the second pass. */
+ g_free (gsearch->command_details->name_contains_pattern_string);
+ g_free (gsearch->command_details->name_contains_regex_string);
+
+ command = build_search_command (gsearch, FALSE);
+ if (command != NULL) {
+ spawn_search_command (gsearch, command);
+ g_free (command);
+ }
+ }
+ else {
+ gsearch->command_details->command_status = (gsearch->command_details->command_status == MAKE_IT_STOP) ? ABORTED : STOPPED;
+ gsearch->command_details->is_command_timeout_enabled = TRUE;
+ g_hash_table_destroy (gsearch->search_results_pixbuf_hash_table);
+ g_hash_table_destroy (gsearch->search_results_filename_hash_table);
+ g_timeout_add (500, not_running_timeout_cb, (gpointer) gsearch);
+
+ update_search_counts (gsearch);
+ stop_animation (gsearch);
+
+ /* Free the gchar fields of search_command structure. */
+ g_free (gsearch->command_details->name_contains_pattern_string);
+ g_free (gsearch->command_details->name_contains_regex_string);
+
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+handle_search_command_stderr_io (GIOChannel * ioc,
+ GIOCondition condition,
+ gpointer data)
+{
+ GSearchWindow * gsearch = data;
+ static GString * error_msgs = NULL;
+ static gboolean truncate_error_msgs = FALSE;
+ gboolean broken_pipe = FALSE;
+
+ if (condition & G_IO_IN) {
+
+ GString * string;
+ GError * error = NULL;
+ gchar * utf8 = NULL;
+
+ string = g_string_new (NULL);
+
+ if (error_msgs == NULL) {
+ error_msgs = g_string_new (NULL);
+ }
+
+ while (ioc->is_readable != TRUE);
+
+ do {
+ gint status;
+
+ do {
+ status = g_io_channel_read_line_string (ioc, string, NULL, &error);
+
+ if (status == G_IO_STATUS_EOF) {
+ broken_pipe = TRUE;
+ }
+ else if (status == G_IO_STATUS_AGAIN) {
+ if (gtk_events_pending ()) {
+ intermediate_file_count_update (gsearch);
+ while (gtk_events_pending ()) {
+ if (gsearch->command_details->command_status == MAKE_IT_QUIT) {
+ break;
+ }
+ gtk_main_iteration ();
+
+ }
+ }
+ }
+
+ } while (status == G_IO_STATUS_AGAIN && broken_pipe == FALSE);
+
+ if (broken_pipe == TRUE) {
+ break;
+ }
+
+ if (status != G_IO_STATUS_NORMAL) {
+ if (error != NULL) {
+ g_warning ("handle_search_command_stderr_io(): %s", error->message);
+ g_error_free (error);
+ }
+ continue;
+ }
+
+ if (truncate_error_msgs == FALSE) {
+ if ((strstr (string->str, "ermission denied") == NULL) &&
+ (strstr (string->str, "No such file or directory") == NULL) &&
+ (strncmp (string->str, "grep: ", 6) != 0) &&
+ (strcmp (string->str, "find: ") != 0)) {
+ utf8 = g_locale_to_utf8 (string->str, -1, NULL, NULL, NULL);
+ error_msgs = g_string_append (error_msgs, utf8);
+ truncate_error_msgs = limit_string_to_x_lines (error_msgs, 20);
+ }
+ }
+
+ } while (g_io_channel_get_buffer_condition (ioc) & G_IO_IN);
+
+ g_string_free (string, TRUE);
+ g_free (utf8);
+ }
+
+ if (!(condition & G_IO_IN) || broken_pipe == TRUE) {
+
+ if (error_msgs != NULL) {
+
+ if (error_msgs->len > 0) {
+
+ GtkWidget * dialog;
+
+ if (truncate_error_msgs) {
+ error_msgs = g_string_append (error_msgs,
+ _("\n... Too many errors to display ..."));
+ }
+
+ if (gsearch->command_details->is_command_using_quick_mode != TRUE) {
+
+ GtkWidget * hbox;
+ GtkWidget * spacer;
+ GtkWidget * expander;
+ GtkWidget * label;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (gsearch->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("The search results may be invalid."
+ " There were errors while performing this search."));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), " ");
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+
+ hbox = gtk_hbox_new (0, FALSE);
+
+ spacer = gtk_label_new (" ");
+ gtk_box_pack_start (GTK_BOX (hbox), spacer, FALSE, FALSE, 0);
+
+ expander = gtk_expander_new_with_mnemonic (_("Show more _details"));
+ gtk_container_set_border_width (GTK_CONTAINER (expander), 6);
+ gtk_expander_set_spacing (GTK_EXPANDER (expander), 6);
+ gtk_box_pack_start (GTK_BOX (hbox), expander, TRUE, TRUE, 0);
+
+ label = gtk_label_new (error_msgs->str);
+ gtk_container_add (GTK_CONTAINER (expander), label);
+
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, FALSE, FALSE, 0);
+ gtk_widget_show_all (hbox);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+ }
+ else if ((gsearch->command_details->is_command_second_pass_enabled == FALSE) ||
+ (is_second_scan_excluded_path (gsearch->command_details->look_in_folder_string) == TRUE)) {
+
+ GtkWidget * button;
+ GtkWidget * hbox;
+ GtkWidget * spacer;
+ GtkWidget * expander;
+ GtkWidget * label;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (gsearch->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CANCEL,
+ _("The search results may be out of date or invalid."
+ " Do you want to disable the quick search feature?"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "Please reference the help documentation for instructions "
+ "on how to configure and enable quick searches.");
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+
+ hbox = gtk_hbox_new (0, FALSE);
+
+ spacer = gtk_label_new (" ");
+ gtk_box_pack_start (GTK_BOX (hbox), spacer, FALSE, FALSE, 0);
+
+ expander = gtk_expander_new_with_mnemonic (_("Show more _details"));
+ gtk_container_set_border_width (GTK_CONTAINER (expander), 6);
+ gtk_expander_set_spacing (GTK_EXPANDER (expander), 6);
+ gtk_box_pack_start (GTK_BOX (hbox), expander, TRUE, TRUE, 0);
+
+ label = gtk_label_new (error_msgs->str);
+ gtk_container_add (GTK_CONTAINER (expander), label);
+
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, FALSE, FALSE, 0);
+ gtk_widget_show_all (hbox);
+
+ button = gsearchtool_button_new_with_stock_icon (_("Disable _Quick Search"), GTK_STOCK_OK);
+ gtk_widget_set_can_default (button, TRUE);
+ gtk_widget_show (button);
+
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (disable_quick_search_cb), (gpointer) gsearch);
+
+ gtk_widget_show (dialog);
+ }
+ }
+ truncate_error_msgs = FALSE;
+ g_string_truncate (error_msgs, 0);
+ }
+ g_io_channel_shutdown (ioc, TRUE, NULL);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+child_command_set_pgid_cb (gpointer data)
+{
+ if (setpgid (0, 0) < 0) {
+ g_print (_("Failed to set process group id of child %d: %s.\n"),
+ getpid (), g_strerror (errno));
+ }
+}
+
+void
+spawn_search_command (GSearchWindow * gsearch,
+ gchar * command)
+{
+ GIOChannel * ioc_stdout;
+ GIOChannel * ioc_stderr;
+ GError * error = NULL;
+ gchar ** argv = NULL;
+ gint child_stdout;
+ gint child_stderr;
+
+ if (!g_shell_parse_argv (command, NULL, &argv, &error)) {
+ GtkWidget * dialog;
+
+ stop_animation (gsearch);
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (gsearch->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Error parsing the search command."));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ (error == NULL) ? " " : error->message, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_error_free (error);
+ g_strfreev (argv);
+
+ /* Free the gchar fields of search_command structure. */
+ g_free (gsearch->command_details->look_in_folder_string);
+ g_free (gsearch->command_details->name_contains_pattern_string);
+ g_free (gsearch->command_details->name_contains_regex_string);
+ return;
+ }
+
+ if (!g_spawn_async_with_pipes (g_get_home_dir (), argv, NULL,
+ G_SPAWN_SEARCH_PATH,
+ child_command_set_pgid_cb, NULL, &gsearch->command_details->command_pid, NULL, &child_stdout,
+ &child_stderr, &error)) {
+ GtkWidget * dialog;
+
+ stop_animation (gsearch);
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (gsearch->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Error running the search command."));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ (error == NULL) ? " " : error->message, NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_error_free (error);
+ g_strfreev (argv);
+
+ /* Free the gchar fields of search_command structure. */
+ g_free (gsearch->command_details->look_in_folder_string);
+ g_free (gsearch->command_details->name_contains_pattern_string);
+ g_free (gsearch->command_details->name_contains_regex_string);
+ return;
+ }
+
+ if (gsearch->command_details->is_command_first_pass == TRUE) {
+
+ gsearch->command_details->command_status = RUNNING;
+ gsearch->search_results_pixbuf_hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ gsearch->search_results_filename_hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ /* Get the value of the caja date-format key if available. */
+ if (gsearch->caja_schema_exists) {
+ gsearch->search_results_date_format = g_settings_get_enum (gsearch->caja_settings, "date-format");
+ } else {
+ gsearch->search_results_date_format = CAJA_DATE_FORMAT_LOCALE;
+ }
+
+ gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (gsearch->search_results_tree_view), 0, 0);
+ gtk_tree_model_foreach (GTK_TREE_MODEL (gsearch->search_results_list_store),
+ (GtkTreeModelForeachFunc) tree_model_iter_free_monitor, gsearch);
+ gtk_list_store_clear (GTK_LIST_STORE (gsearch->search_results_list_store));
+
+ gtk_tree_view_column_set_visible (gsearch->search_results_folder_column, TRUE);
+ gtk_tree_view_column_set_visible (gsearch->search_results_size_column, TRUE);
+ gtk_tree_view_column_set_visible (gsearch->search_results_type_column, TRUE);
+ gtk_tree_view_column_set_visible (gsearch->search_results_date_column, TRUE);
+ }
+
+ ioc_stdout = g_io_channel_unix_new (child_stdout);
+ ioc_stderr = g_io_channel_unix_new (child_stderr);
+
+ g_io_channel_set_encoding (ioc_stdout, NULL, NULL);
+ g_io_channel_set_encoding (ioc_stderr, NULL, NULL);
+
+ g_io_channel_set_flags (ioc_stdout, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_flags (ioc_stderr, G_IO_FLAG_NONBLOCK, NULL);
+
+ g_io_add_watch (ioc_stdout, G_IO_IN | G_IO_HUP,
+ handle_search_command_stdout_io, gsearch);
+ g_io_add_watch (ioc_stderr, G_IO_IN | G_IO_HUP,
+ handle_search_command_stderr_io, gsearch);
+
+ g_io_channel_unref (ioc_stdout);
+ g_io_channel_unref (ioc_stderr);
+ g_strfreev (argv);
+}
+
+static GtkWidget *
+create_constraint_box (GSearchWindow * gsearch,
+ GSearchConstraint * opt,
+ gchar * value)
+{
+ GtkWidget * hbox;
+ GtkWidget * label;
+ GtkWidget * entry;
+ GtkWidget * entry_hbox;
+ GtkWidget * button;
+
+ hbox = gtk_hbox_new (FALSE, 12);
+
+ switch (GSearchOptionTemplates[opt->constraint_id].type) {
+ case SEARCH_CONSTRAINT_TYPE_BOOLEAN:
+ {
+ gchar * text = remove_mnemonic_character (GSearchOptionTemplates[opt->constraint_id].desc);
+ gchar * desc = g_strconcat (LEFT_LABEL_SPACING, _(text), ".", NULL);
+ label = gtk_label_new (desc);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ g_free (desc);
+ g_free (text);
+ }
+ break;
+ case SEARCH_CONSTRAINT_TYPE_TEXT:
+ case SEARCH_CONSTRAINT_TYPE_NUMERIC:
+ case SEARCH_CONSTRAINT_TYPE_DATE_BEFORE:
+ case SEARCH_CONSTRAINT_TYPE_DATE_AFTER:
+ {
+ gchar * desc = g_strconcat (LEFT_LABEL_SPACING, _(GSearchOptionTemplates[opt->constraint_id].desc), ":", NULL);
+ label = gtk_label_new_with_mnemonic (desc);
+ g_free (desc);
+ }
+
+ /* add description label */
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ if (GSearchOptionTemplates[opt->constraint_id].type == SEARCH_CONSTRAINT_TYPE_TEXT) {
+ entry = gtk_entry_new ();
+ if (value != NULL) {
+ gtk_entry_set_text (GTK_ENTRY (entry), value);
+ opt->data.text = value;
+ }
+ }
+ else {
+ entry = gtk_spin_button_new_with_range (0, 999999999, 1);
+ if (value != NULL) {
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (entry), atoi (value));
+ opt->data.time = atoi (value);
+ opt->data.number = atoi (value);
+ }
+ }
+
+ if (gsearch->is_window_accessible) {
+ gchar * text = remove_mnemonic_character (GSearchOptionTemplates[opt->constraint_id].desc);
+ gchar * name;
+ gchar * desc;
+
+ if (GSearchOptionTemplates[opt->constraint_id].units == NULL) {
+ name = g_strdup (_(text));
+ desc = g_strdup_printf (_("Enter a text value for the \"%s\" search option."), _(text));
+ }
+ else {
+ /* Translators: Below is a string displaying the search options name
+ and unit value. For example, "\"Date modified less than\" in days". */
+ name = g_strdup_printf (_("\"%s\" in %s"), _(text),
+ _(GSearchOptionTemplates[opt->constraint_id].units));
+ desc = g_strdup_printf (_("Enter a value in %s for the \"%s\" search option."),
+ _(GSearchOptionTemplates[opt->constraint_id].units),
+ _(text));
+ }
+ add_atk_namedesc (GTK_WIDGET (entry), name, desc);
+ g_free (name);
+ g_free (desc);
+ g_free (text);
+ }
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (entry));
+
+ g_signal_connect (G_OBJECT (entry), "changed",
+ G_CALLBACK (constraint_update_info_cb), opt);
+
+ g_signal_connect (G_OBJECT (entry), "activate",
+ G_CALLBACK (constraint_activate_cb),
+ (gpointer) gsearch);
+
+ /* add text field */
+ entry_hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), entry_hbox, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (entry_hbox), entry, TRUE, TRUE, 0);
+
+ /* add units label */
+ if (GSearchOptionTemplates[opt->constraint_id].units != NULL)
+ {
+ label = gtk_label_new_with_mnemonic (_(GSearchOptionTemplates[opt->constraint_id].units));
+ gtk_box_pack_start (GTK_BOX (entry_hbox), label, FALSE, FALSE, 0);
+ }
+
+ break;
+ default:
+ /* This should never happen. If it does, there is a bug */
+ label = gtk_label_new ("???");
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+ break;
+ }
+
+ button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+ gtk_widget_set_can_default (button, FALSE);
+
+ {
+ GList * list = NULL;
+
+ list = g_list_append (list, (gpointer) gsearch);
+ list = g_list_append (list, (gpointer) opt);
+
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (remove_constraint_cb),
+ (gpointer) list);
+
+ }
+ gtk_size_group_add_widget (gsearch->available_options_button_size_group, button);
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ if (gsearch->is_window_accessible) {
+ gchar * text = remove_mnemonic_character (GSearchOptionTemplates[opt->constraint_id].desc);
+ gchar * name = g_strdup_printf (_("Remove \"%s\""), _(text));
+ gchar * desc = g_strdup_printf (_("Click to remove the \"%s\" search option."), _(text));
+ add_atk_namedesc (GTK_WIDGET (button), name, desc);
+ g_free (name);
+ g_free (desc);
+ g_free (text);
+ }
+ return hbox;
+}
+
+void
+add_constraint (GSearchWindow * gsearch,
+ gint constraint_id,
+ gchar * value,
+ gboolean show_constraint)
+{
+ GSearchConstraint * constraint = g_slice_new (GSearchConstraint);
+ GtkWidget * widget;
+
+ if (show_constraint) {
+ if (gtk_widget_get_visible (gsearch->available_options_vbox) == FALSE) {
+ gtk_expander_set_expanded (GTK_EXPANDER (gsearch->show_more_options_expander), TRUE);
+ gtk_widget_show (gsearch->available_options_vbox);
+ }
+ }
+
+ gsearch->window_geometry.min_height += WINDOW_HEIGHT_STEP;
+
+ if (gtk_widget_get_visible (gsearch->available_options_vbox)) {
+ gtk_window_set_geometry_hints (GTK_WINDOW (gsearch->window),
+ GTK_WIDGET (gsearch->window),
+ &gsearch->window_geometry,
+ GDK_HINT_MIN_SIZE);
+ }
+
+ constraint->constraint_id = constraint_id;
+ set_constraint_info_defaults (constraint);
+ set_constraint_gsettings_boolean (constraint->constraint_id, TRUE);
+
+ widget = create_constraint_box (gsearch, constraint, value);
+ gtk_box_pack_start (GTK_BOX (gsearch->available_options_vbox), widget, FALSE, FALSE, 0);
+ gtk_widget_show_all (widget);
+
+ gsearch->available_options_selected_list =
+ g_list_append (gsearch->available_options_selected_list, constraint);
+
+ set_constraint_selected_state (gsearch, constraint->constraint_id, TRUE);
+}
+
+static void
+set_sensitive (GtkCellLayout * cell_layout,
+ GtkCellRenderer * cell,
+ GtkTreeModel * tree_model,
+ GtkTreeIter * iter,
+ gpointer data)
+{
+ GtkTreePath * path;
+ gint idx;
+
+ path = gtk_tree_model_get_path (tree_model, iter);
+ idx = gtk_tree_path_get_indices (path)[0];
+ gtk_tree_path_free (path);
+
+ g_object_set (cell, "sensitive", !(GSearchOptionTemplates[idx].is_selected), NULL);
+}
+
+static gboolean
+is_separator (GtkTreeModel * model,
+ GtkTreeIter * iter,
+ gpointer data)
+{
+ GtkTreePath * path;
+ gint idx;
+
+ path = gtk_tree_model_get_path (model, iter);
+ idx = gtk_tree_path_get_indices (path)[0];
+ gtk_tree_path_free (path);
+
+ return (GSearchOptionTemplates[idx].type == SEARCH_CONSTRAINT_TYPE_SEPARATOR);
+}
+
+static void
+create_additional_constraint_section (GSearchWindow * gsearch)
+{
+ GtkCellRenderer * renderer;
+ GtkTreeModel * model;
+ GtkWidget * hbox;
+ gchar * desc;
+
+ gsearch->available_options_vbox = gtk_vbox_new (FALSE, 6);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_end (GTK_BOX (gsearch->available_options_vbox), hbox, FALSE, FALSE, 0);
+
+ desc = g_strconcat (LEFT_LABEL_SPACING, _("A_vailable options:"), NULL);
+ gsearch->available_options_label = gtk_label_new_with_mnemonic (desc);
+ g_free (desc);
+
+ gtk_box_pack_start (GTK_BOX (hbox), gsearch->available_options_label, FALSE, FALSE, 0);
+
+ model = gsearch_create_list_of_templates ();
+ gsearch->available_options_combo_box = gtk_combo_box_new_with_model (model);
+ g_object_unref (model);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (gsearch->available_options_label), GTK_WIDGET (gsearch->available_options_combo_box));
+ gtk_combo_box_set_active (GTK_COMBO_BOX (gsearch->available_options_combo_box), 0);
+ gtk_box_pack_start (GTK_BOX (hbox), gsearch->available_options_combo_box, TRUE, TRUE, 0);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (gsearch->available_options_combo_box),
+ renderer,
+ TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (gsearch->available_options_combo_box), renderer,
+ "text", 0,
+ NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (gsearch->available_options_combo_box),
+ renderer,
+ set_sensitive,
+ NULL, NULL);
+ gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (gsearch->available_options_combo_box),
+ is_separator, NULL, NULL);
+
+ if (gsearch->is_window_accessible) {
+ add_atk_namedesc (GTK_WIDGET (gsearch->available_options_combo_box), _("Available options"),
+ _("Select a search option from the drop-down list."));
+ }
+
+ gsearch->available_options_add_button = gtk_button_new_from_stock (GTK_STOCK_ADD);
+ gtk_widget_set_can_default (gsearch->available_options_add_button, FALSE);
+ gsearch->available_options_button_size_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
+ gtk_size_group_add_widget (gsearch->available_options_button_size_group, gsearch->available_options_add_button);
+
+ g_signal_connect (G_OBJECT (gsearch->available_options_add_button),"clicked",
+ G_CALLBACK (add_constraint_cb), (gpointer) gsearch);
+
+ if (gsearch->is_window_accessible) {
+ add_atk_namedesc (GTK_WIDGET (gsearch->available_options_add_button), _("Add search option"),
+ _("Click to add the selected available search option."));
+ }
+
+ gtk_box_pack_end (GTK_BOX (hbox), gsearch->available_options_add_button, FALSE, FALSE, 0);
+}
+
+static void
+filename_cell_data_func (GtkTreeViewColumn * column,
+ GtkCellRenderer * renderer,
+ GtkTreeModel * model,
+ GtkTreeIter * iter,
+ GSearchWindow * gsearch)
+{
+ GtkTreePath * path;
+ PangoUnderline underline;
+ gboolean underline_set;
+
+ if (gsearch->is_search_results_single_click_to_activate == TRUE) {
+
+ path = gtk_tree_model_get_path (model, iter);
+
+ if ((gsearch->search_results_hover_path == NULL) ||
+ (gtk_tree_path_compare (path, gsearch->search_results_hover_path) != 0)) {
+ underline = PANGO_UNDERLINE_NONE;
+ underline_set = FALSE;
+ }
+ else {
+ underline = PANGO_UNDERLINE_SINGLE;
+ underline_set = TRUE;
+ }
+ gtk_tree_path_free (path);
+ }
+ else {
+ underline = PANGO_UNDERLINE_NONE;
+ underline_set = FALSE;
+ }
+
+ g_object_set (gsearch->search_results_name_cell_renderer,
+ "underline", underline,
+ "underline-set", underline_set,
+ NULL);
+}
+
+static gboolean
+gsearch_equal_func (GtkTreeModel * model,
+ gint column,
+ const gchar * key,
+ GtkTreeIter * iter,
+ gpointer search_data)
+{
+ gboolean results = TRUE;
+ gchar * name;
+
+ gtk_tree_model_get (model, iter, COLUMN_NAME, &name, -1);
+
+ if (name != NULL) {
+ gchar * casefold_key;
+ gchar * casefold_name;
+
+ casefold_key = g_utf8_casefold (key, -1);
+ casefold_name = g_utf8_casefold (name, -1);
+
+ if ((casefold_key != NULL) &&
+ (casefold_name != NULL) &&
+ (strstr (casefold_name, casefold_key) != NULL)) {
+ results = FALSE;
+ }
+ g_free (casefold_key);
+ g_free (casefold_name);
+ g_free (name);
+ }
+ return results;
+}
+
+static GtkWidget *
+create_search_results_section (GSearchWindow * gsearch)
+{
+ GtkWidget * label;
+ GtkWidget * vbox;
+ GtkWidget * hbox;
+ GtkWidget * window;
+ GtkTreeViewColumn * column;
+ GtkCellRenderer * renderer;
+
+ vbox = gtk_vbox_new (FALSE, 6);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new_with_mnemonic (_("S_earch results:"));
+ g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
+
+ gsearch->progress_spinner = gtk_spinner_new ();
+ gtk_widget_set_size_request (gsearch->progress_spinner,
+ GTK_ICON_SIZE_MENU, GTK_ICON_SIZE_MENU);
+ gtk_box_pack_start (GTK_BOX (hbox), gsearch->progress_spinner, FALSE, FALSE, 0);
+
+ gsearch->files_found_label = gtk_label_new (NULL);
+ gtk_label_set_selectable (GTK_LABEL (gsearch->files_found_label), TRUE);
+ g_object_set (G_OBJECT (gsearch->files_found_label), "xalign", 1.0, NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), gsearch->files_found_label, TRUE, TRUE, 0);
+
+ window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (window), GTK_SHADOW_IN);
+ gtk_container_set_border_width (GTK_CONTAINER (window), 0);
+ gtk_widget_set_size_request (window, 530, 160);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ gsearch->search_results_list_store = gtk_list_store_new (NUM_COLUMNS,
+ GDK_TYPE_PIXBUF,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_DOUBLE,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_DOUBLE,
+ G_TYPE_POINTER,
+ G_TYPE_BOOLEAN);
+
+ gsearch->search_results_tree_view = GTK_TREE_VIEW (gtk_tree_view_new_with_model (GTK_TREE_MODEL (gsearch->search_results_list_store)));
+
+ gtk_tree_view_set_headers_visible (gsearch->search_results_tree_view, FALSE);
+ gtk_tree_view_set_search_equal_func (gsearch->search_results_tree_view,
+ gsearch_equal_func, NULL, NULL);
+ gtk_tree_view_set_rules_hint (gsearch->search_results_tree_view, TRUE);
+ g_object_unref (G_OBJECT (gsearch->search_results_list_store));
+
+ if (gsearch->is_window_accessible) {
+ add_atk_namedesc (GTK_WIDGET (gsearch->search_results_tree_view), _("List View"), NULL);
+ }
+
+ gsearch->search_results_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (gsearch->search_results_tree_view));
+
+ gtk_tree_selection_set_mode (GTK_TREE_SELECTION (gsearch->search_results_selection),
+ GTK_SELECTION_MULTIPLE);
+
+ gtk_drag_source_set (GTK_WIDGET (gsearch->search_results_tree_view),
+ GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
+ GSearchDndTable, GSearchTotalDnds,
+ GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_tree_view),
+ "drag_data_get",
+ G_CALLBACK (drag_file_cb),
+ (gpointer) gsearch);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_tree_view),
+ "drag_begin",
+ G_CALLBACK (drag_begin_file_cb),
+ (gpointer) gsearch);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_tree_view),
+ "event_after",
+ G_CALLBACK (file_event_after_cb),
+ (gpointer) gsearch);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_tree_view),
+ "button_release_event",
+ G_CALLBACK (file_button_release_event_cb),
+ (gpointer) gsearch);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_tree_view),
+ "button_press_event",
+ G_CALLBACK (file_button_press_event_cb),
+ (gpointer) gsearch->search_results_tree_view);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_tree_view),
+ "key_press_event",
+ G_CALLBACK (file_key_press_event_cb),
+ (gpointer) gsearch);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_tree_view),
+ "motion_notify_event",
+ G_CALLBACK (file_motion_notify_cb),
+ (gpointer) gsearch);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_tree_view),
+ "leave_notify_event",
+ G_CALLBACK (file_leave_notify_cb),
+ (gpointer) gsearch);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (gsearch->search_results_tree_view));
+
+ gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (gsearch->search_results_tree_view));
+ gtk_box_pack_end (GTK_BOX (vbox), window, TRUE, TRUE, 0);
+
+ /* create the name column */
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Name"));
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "pixbuf", COLUMN_ICON,
+ NULL);
+
+ gsearch->search_results_name_cell_renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, gsearch->search_results_name_cell_renderer, TRUE);
+ gtk_tree_view_column_set_attributes (column, gsearch->search_results_name_cell_renderer,
+ "text", COLUMN_NAME,
+ NULL);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_cell_data_func (column, renderer,
+ (GtkTreeCellDataFunc) filename_cell_data_func,
+ gsearch, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (gsearch->search_results_tree_view), column);
+
+ /* create the folder column */
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Folder"), renderer,
+ "text", COLUMN_RELATIVE_PATH,
+ NULL);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_RELATIVE_PATH);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (gsearch->search_results_tree_view), column);
+ gsearch->search_results_folder_column = column;
+
+ /* create the size column */
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "xalign", 1.0, NULL);
+ column = gtk_tree_view_column_new_with_attributes (_("Size"), renderer,
+ "text", COLUMN_READABLE_SIZE,
+ NULL);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_SIZE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (gsearch->search_results_tree_view), column);
+ gsearch->search_results_size_column = column;
+
+ /* create the type column */
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Type"), renderer,
+ "text", COLUMN_TYPE,
+ NULL);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_TYPE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (gsearch->search_results_tree_view), column);
+ gsearch->search_results_type_column = column;
+
+ /* create the date modified column */
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Date Modified"), renderer,
+ "text", COLUMN_READABLE_DATE,
+ NULL);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_DATE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (gsearch->search_results_tree_view), column);
+ gsearch->search_results_date_column = column;
+
+ gsearchtool_set_columns_order (gsearch->search_results_tree_view);
+
+ g_signal_connect (G_OBJECT (gsearch->search_results_tree_view),
+ "columns-changed",
+ G_CALLBACK (columns_changed_cb),
+ (gpointer) gsearch);
+ return vbox;
+}
+
+static void
+register_gsearchtool_icon (GtkIconFactory * factory)
+{
+ GtkIconSource * source;
+ GtkIconSet * icon_set;
+
+ source = gtk_icon_source_new ();
+
+ gtk_icon_source_set_icon_name (source, MATE_SEARCH_TOOL_ICON);
+
+ icon_set = gtk_icon_set_new ();
+ gtk_icon_set_add_source (icon_set, source);
+
+ gtk_icon_factory_add (factory, MATE_SEARCH_TOOL_STOCK, icon_set);
+
+ gtk_icon_set_unref (icon_set);
+
+ gtk_icon_source_free (source);
+}
+
+static void
+gsearchtool_init_stock_icons (void)
+{
+ GtkIconFactory * factory;
+ GtkIconSize gsearchtool_icon_size;
+
+ gsearchtool_icon_size = gtk_icon_size_register ("panel-menu",
+ MATE_SEARCH_TOOL_DEFAULT_ICON_SIZE,
+ MATE_SEARCH_TOOL_DEFAULT_ICON_SIZE);
+
+ factory = gtk_icon_factory_new ();
+ gtk_icon_factory_add_default (factory);
+
+ register_gsearchtool_icon (factory);
+
+ g_object_unref (factory);
+}
+
+void
+set_clone_command (GSearchWindow * gsearch,
+ gint * argcp,
+ gchar *** argvp,
+ gpointer client_data,
+ gboolean escape_values)
+{
+ gchar ** argv;
+ gchar * file_is_named_utf8;
+ gchar * file_is_named_locale;
+ gchar * look_in_folder_locale;
+ gchar * tmp;
+ GList * list;
+ gint i = 0;
+
+ argv = g_new0 (gchar*, SEARCH_CONSTRAINT_MAXIMUM_POSSIBLE);
+
+ argv[i++] = (gchar *) client_data;
+
+ file_is_named_utf8 = (gchar *) gtk_entry_get_text (GTK_ENTRY (gsearch_history_entry_get_entry (GSEARCH_HISTORY_ENTRY (gsearch->name_contains_entry))));
+ file_is_named_locale = g_locale_from_utf8 (file_is_named_utf8 != NULL ? file_is_named_utf8 : "" ,
+ -1, NULL, NULL, NULL);
+ if (escape_values)
+ tmp = g_shell_quote (file_is_named_locale);
+ else
+ tmp = g_strdup (file_is_named_locale);
+ argv[i++] = g_strdup_printf ("--named=%s", tmp);
+ g_free (tmp);
+ g_free (file_is_named_locale);
+
+ look_in_folder_locale = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (gsearch->look_in_folder_button));
+
+ if (look_in_folder_locale == NULL) {
+ look_in_folder_locale = g_strdup ("");
+ }
+
+ if (escape_values)
+ tmp = g_shell_quote (look_in_folder_locale);
+ else
+ tmp = g_strdup (look_in_folder_locale);
+ argv[i++] = g_strdup_printf ("--path=%s", tmp);
+ g_free (tmp);
+ g_free (look_in_folder_locale);
+
+ if (gtk_widget_get_visible (gsearch->available_options_vbox)) {
+ for (list = gsearch->available_options_selected_list; list != NULL; list = g_list_next (list)) {
+ GSearchConstraint * constraint = list->data;
+ gchar * locale = NULL;
+
+ switch (constraint->constraint_id) {
+ case SEARCH_CONSTRAINT_CONTAINS_THE_TEXT:
+ locale = g_locale_from_utf8 (constraint->data.text, -1, NULL, NULL, NULL);
+ if (escape_values)
+ tmp = g_shell_quote (locale);
+ else
+ tmp = g_strdup (locale);
+ argv[i++] = g_strdup_printf ("--contains=%s", tmp);
+ g_free (tmp);
+ break;
+ case SEARCH_CONSTRAINT_DATE_MODIFIED_BEFORE:
+ argv[i++] = g_strdup_printf ("--mtimeless=%d", constraint->data.time);
+ break;
+ case SEARCH_CONSTRAINT_DATE_MODIFIED_AFTER:
+ argv[i++] = g_strdup_printf ("--mtimemore=%d", constraint->data.time);
+ break;
+ case SEARCH_CONSTRAINT_SIZE_IS_MORE_THAN:
+ argv[i++] = g_strdup_printf ("--sizemore=%u", constraint->data.number);
+ break;
+ case SEARCH_CONSTRAINT_SIZE_IS_LESS_THAN:
+ argv[i++] = g_strdup_printf ("--sizeless=%u", constraint->data.number);
+ break;
+ case SEARCH_CONSTRAINT_FILE_IS_EMPTY:
+ argv[i++] = g_strdup ("--empty");
+ break;
+ case SEARCH_CONSTRAINT_OWNED_BY_USER:
+ locale = g_locale_from_utf8 (constraint->data.text, -1, NULL, NULL, NULL);
+ if (escape_values)
+ tmp = g_shell_quote (locale);
+ else
+ tmp = g_strdup (locale);
+ argv[i++] = g_strdup_printf ("--user=%s", tmp);
+ g_free (tmp);
+ break;
+ case SEARCH_CONSTRAINT_OWNED_BY_GROUP:
+ locale = g_locale_from_utf8 (constraint->data.text, -1, NULL, NULL, NULL);
+ if (escape_values)
+ tmp = g_shell_quote (locale);
+ else
+ tmp = g_strdup (locale);
+ argv[i++] = g_strdup_printf ("--group=%s", tmp);
+ g_free (tmp);
+ break;
+ case SEARCH_CONSTRAINT_OWNER_IS_UNRECOGNIZED:
+ argv[i++] = g_strdup ("--nouser");
+ break;
+ case SEARCH_CONSTRAINT_FILE_IS_NOT_NAMED:
+ locale = g_locale_from_utf8 (constraint->data.text, -1, NULL, NULL, NULL);
+ if (escape_values)
+ tmp = g_shell_quote (locale);
+ else
+ tmp = g_strdup (locale);
+ argv[i++] = g_strdup_printf ("--notnamed=%s", tmp);
+ g_free (tmp);
+ break;
+ case SEARCH_CONSTRAINT_FILE_MATCHES_REGULAR_EXPRESSION:
+ locale = g_locale_from_utf8 (constraint->data.text, -1, NULL, NULL, NULL);
+ if (escape_values)
+ tmp = g_shell_quote (locale);
+ else
+ tmp = g_strdup (locale);
+ argv[i++] = g_strdup_printf ("--regex=%s", tmp);
+ g_free (tmp);
+ break;
+ case SEARCH_CONSTRAINT_SHOW_HIDDEN_FILES_AND_FOLDERS:
+ argv[i++] = g_strdup ("--hidden");
+ break;
+ case SEARCH_CONSTRAINT_FOLLOW_SYMBOLIC_LINKS:
+ argv[i++] = g_strdup ("--follow");
+ break;
+ case SEARCH_CONSTRAINT_SEARCH_OTHER_FILESYSTEMS:
+ argv[i++] = g_strdup ("--mounts");
+ break;
+ default:
+ break;
+ }
+ g_free (locale);
+ }
+ }
+ *argvp = argv;
+ *argcp = i;
+}
+
+static void
+handle_gsettings_settings (GSearchWindow * gsearch)
+{
+ if (g_settings_get_boolean (gsearch->mate_search_tool_settings, "show-additional-options")) {
+ if (gtk_widget_get_visible (gsearch->available_options_vbox) == FALSE) {
+ gtk_expander_set_expanded (GTK_EXPANDER (gsearch->show_more_options_expander), TRUE);
+ gtk_widget_show (gsearch->available_options_vbox);
+ }
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "contains-the-text")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_CONTAINS_THE_TEXT, "", FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "date-modified-less-than")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_DATE_MODIFIED_BEFORE, "", FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "date-modified-more-than")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_DATE_MODIFIED_AFTER, "", FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "size-at-least")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_SIZE_IS_MORE_THAN, "", FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "size-at-most")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_SIZE_IS_LESS_THAN, "", FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "file-is-empty")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_FILE_IS_EMPTY, NULL, FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "owned-by-user")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_OWNED_BY_USER, "", FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "owned-by-group")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_OWNED_BY_GROUP, "", FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "owner-is-unrecognized")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_OWNER_IS_UNRECOGNIZED, NULL, FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "name-does-not-contain")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_FILE_IS_NOT_NAMED, "", FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "name-matches-regular-expression")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_FILE_MATCHES_REGULAR_EXPRESSION, "", FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "show-hidden-files-and-folders")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_SHOW_HIDDEN_FILES_AND_FOLDERS, NULL, FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "follow-symbolic-links")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_FOLLOW_SYMBOLIC_LINKS, NULL, FALSE);
+ }
+
+ if (g_settings_get_boolean (gsearch->mate_search_tool_select_settings, "exclude-other-filesystems")) {
+ add_constraint (gsearch, SEARCH_CONSTRAINT_SEARCH_OTHER_FILESYSTEMS, NULL, FALSE);
+ }
+}
+
+static void
+gsearch_window_size_allocate (GtkWidget * widget,
+ GtkAllocation * allocation,
+ GSearchWindow * gsearch)
+{
+ if (gsearch->is_window_maximized == FALSE) {
+ gsearch->window_width = allocation->width;
+ gsearch->window_height = allocation->height;
+ }
+}
+
+static GtkWidget *
+gsearch_app_create (GSearchWindow * gsearch)
+{
+ gchar * locale_string;
+ gchar * utf8_string;
+ GtkWidget * hbox;
+ GtkWidget * vbox;
+ GtkWidget * entry;
+ GtkWidget * label;
+ GtkWidget * button;
+ GtkWidget * container;
+
+ gsearch->mate_search_tool_settings = g_settings_new ("org.mate.search-tool");
+ gsearch->mate_search_tool_select_settings = g_settings_new ("org.mate.search-tool.select");
+ gsearch->mate_desktop_interface_settings = g_settings_new ("org.mate.interface");
+
+ /* Check if caja schema is installed before trying to read caja settings */
+ gsearch->caja_schema_exists = FALSE;
+ GSettingsSchema *schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
+ CAJA_PREFERENCES_SCHEMA,
+ FALSE);
+
+ if (schema != NULL) {
+ gsearch->caja_schema_exists = TRUE;
+ g_settings_schema_unref (schema);
+ }
+
+ if (gsearch->caja_schema_exists) {
+ gsearch->caja_settings = g_settings_new (CAJA_PREFERENCES_SCHEMA);
+ } else {
+ gsearch->caja_settings = NULL;
+ }
+
+ gsearch->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gsearch->is_window_maximized = g_settings_get_boolean (gsearch->mate_search_tool_settings, "default-window-maximized");
+ g_signal_connect (G_OBJECT (gsearch->window), "size-allocate",
+ G_CALLBACK (gsearch_window_size_allocate),
+ gsearch);
+ gsearch->command_details = g_slice_new0 (GSearchCommandDetails);
+ gsearch->window_geometry.min_height = MINIMUM_WINDOW_HEIGHT;
+ gsearch->window_geometry.min_width = MINIMUM_WINDOW_WIDTH;
+
+ gtk_window_set_position (GTK_WINDOW (gsearch->window), GTK_WIN_POS_CENTER);
+ gtk_window_set_geometry_hints (GTK_WINDOW (gsearch->window), GTK_WIDGET (gsearch->window),
+ &gsearch->window_geometry, GDK_HINT_MIN_SIZE);
+
+ gsearchtool_get_stored_window_geometry (&gsearch->window_width,
+ &gsearch->window_height);
+ gtk_window_set_default_size (GTK_WINDOW (gsearch->window),
+ gsearch->window_width,
+ gsearch->window_height);
+
+ if (gsearch->is_window_maximized == TRUE) {
+ gtk_window_maximize (GTK_WINDOW (gsearch->window));
+ }
+
+ container = gtk_vbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (gsearch->window), container);
+ gtk_container_set_border_width (GTK_CONTAINER (container), 12);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (container), hbox, FALSE, FALSE, 0);
+
+ gsearch->name_and_folder_table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (gsearch->name_and_folder_table), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (gsearch->name_and_folder_table), 12);
+ gtk_container_add (GTK_CONTAINER (hbox), gsearch->name_and_folder_table);
+
+ label = gtk_label_new_with_mnemonic (_("_Name contains:"));
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+ g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
+
+ gtk_table_attach (GTK_TABLE (gsearch->name_and_folder_table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 1);
+
+ gsearch->name_contains_entry = gsearch_history_entry_new ("gsearchtool-file-entry", FALSE);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), gsearch->name_contains_entry);
+ gsearch_history_entry_set_history_length (GSEARCH_HISTORY_ENTRY (gsearch->name_contains_entry), 10);
+ gtk_table_attach (GTK_TABLE (gsearch->name_and_folder_table), gsearch->name_contains_entry, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0, 0);
+ entry = gsearch_history_entry_get_entry (GSEARCH_HISTORY_ENTRY (gsearch->name_contains_entry));
+
+ if (GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (gsearch->name_contains_entry))) {
+ gsearch->is_window_accessible = TRUE;
+ add_atk_namedesc (gsearch->name_contains_entry, NULL, _("Enter a filename or partial filename with or without wildcards."));
+ add_atk_namedesc (entry, _("Name contains"), _("Enter a filename or partial filename with or without wildcards."));
+ }
+ g_signal_connect (G_OBJECT (gsearch_history_entry_get_entry (GSEARCH_HISTORY_ENTRY (gsearch->name_contains_entry))), "activate",
+ G_CALLBACK (name_contains_activate_cb),
+ (gpointer) gsearch);
+
+ label = gtk_label_new_with_mnemonic (_("_Look in folder:"));
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+ g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
+
+ gtk_table_attach (GTK_TABLE (gsearch->name_and_folder_table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+
+ gsearch->look_in_folder_button = gtk_file_chooser_button_new (_("Browse"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (gsearch->look_in_folder_button));
+ gtk_table_attach (GTK_TABLE (gsearch->name_and_folder_table), gsearch->look_in_folder_button, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0, 0);
+
+ g_signal_connect (G_OBJECT (gsearch->look_in_folder_button), "current-folder-changed",
+ G_CALLBACK (look_in_folder_changed_cb),
+ (gpointer) gsearch);
+
+ if (gsearch->is_window_accessible) {
+ add_atk_namedesc (GTK_WIDGET (gsearch->look_in_folder_button), _("Look in folder"), _("Select the folder or device from which you want to begin the search."));
+ }
+
+ locale_string = g_settings_get_string (gsearch->mate_search_tool_settings, "look-in-folder");
+
+ if ((g_file_test (locale_string, G_FILE_TEST_EXISTS) == FALSE) ||
+ (g_file_test (locale_string, G_FILE_TEST_IS_DIR) == FALSE)) {
+ g_free (locale_string);
+ locale_string = g_get_current_dir ();
+ }
+
+ utf8_string = g_filename_to_utf8 (locale_string, -1, NULL, NULL, NULL);
+
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (gsearch->look_in_folder_button), utf8_string);
+
+ g_free (locale_string);
+ g_free (utf8_string);
+
+ gsearch->show_more_options_expander = gtk_expander_new_with_mnemonic (_("Select more _options"));
+ gtk_box_pack_start (GTK_BOX (container), gsearch->show_more_options_expander, FALSE, FALSE, 0);
+ g_signal_connect (G_OBJECT (gsearch->show_more_options_expander), "notify::expanded",
+ G_CALLBACK (click_expander_cb), (gpointer) gsearch);
+
+ create_additional_constraint_section (gsearch);
+ gtk_box_pack_start (GTK_BOX (container), GTK_WIDGET (gsearch->available_options_vbox), FALSE, FALSE, 0);
+
+ if (gsearch->is_window_accessible) {
+ add_atk_namedesc (GTK_WIDGET (gsearch->show_more_options_expander), _("Select more options"), _("Click to expand or collapse the list of available options."));
+ add_atk_relation (GTK_WIDGET (gsearch->available_options_vbox), GTK_WIDGET (gsearch->show_more_options_expander), ATK_RELATION_CONTROLLED_BY);
+ add_atk_relation (GTK_WIDGET (gsearch->show_more_options_expander), GTK_WIDGET (gsearch->available_options_vbox), ATK_RELATION_CONTROLLER_FOR);
+ }
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (container), vbox, TRUE, TRUE, 0);
+
+ gsearch->search_results_vbox = create_search_results_section (gsearch);
+ gtk_widget_set_sensitive (GTK_WIDGET (gsearch->search_results_vbox), FALSE);
+ gtk_box_pack_start (GTK_BOX (vbox), gsearch->search_results_vbox, TRUE, TRUE, 0);
+
+ hbox = gtk_hbutton_box_new ();
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+ gtk_box_set_spacing (GTK_BOX (hbox), 6);
+ button = gtk_button_new_from_stock (GTK_STOCK_HELP);
+ gtk_widget_set_can_default (button, TRUE);
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (hbox), button, TRUE);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (click_help_cb), (gpointer) gsearch->window);
+ if (gsearch->is_window_accessible) {
+ add_atk_namedesc (GTK_WIDGET (button), NULL, _("Click to display the help manual."));
+ }
+
+ button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
+ gtk_widget_set_can_default (button, TRUE);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (click_close_cb), (gpointer) gsearch);
+ if (gsearch->is_window_accessible) {
+ add_atk_namedesc (GTK_WIDGET (button), NULL, _("Click to close \"Search for Files\"."));
+ }
+
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ /* Find and Stop buttons... */
+ gsearch->find_button = gtk_button_new_from_stock (GTK_STOCK_FIND);
+ gsearch->stop_button = gtk_button_new_from_stock (GTK_STOCK_STOP);
+
+ gtk_widget_set_can_default (gsearch->find_button, TRUE);
+ gtk_widget_set_can_default (gsearch->stop_button, TRUE);
+
+ gtk_box_pack_end (GTK_BOX (hbox), gsearch->stop_button, FALSE, FALSE, 0);
+ gtk_box_pack_end (GTK_BOX (hbox), gsearch->find_button, FALSE, FALSE, 0);
+
+ gtk_widget_set_sensitive (gsearch->stop_button, FALSE);
+ gtk_widget_set_sensitive (gsearch->find_button, TRUE);
+
+ g_signal_connect (G_OBJECT (gsearch->find_button), "clicked",
+ G_CALLBACK (click_find_cb), (gpointer) gsearch);
+ g_signal_connect (G_OBJECT (gsearch->find_button), "size_allocate",
+ G_CALLBACK (size_allocate_cb), (gpointer) gsearch->available_options_add_button);
+ g_signal_connect (G_OBJECT (gsearch->stop_button), "clicked",
+ G_CALLBACK (click_stop_cb), (gpointer) gsearch);
+
+ if (gsearch->is_window_accessible) {
+ add_atk_namedesc (GTK_WIDGET (gsearch->find_button), NULL, _("Click to perform a search."));
+ add_atk_namedesc (GTK_WIDGET (gsearch->stop_button), NULL, _("Click to stop a search."));
+ }
+
+ gtk_widget_show_all (container);
+ gtk_widget_hide (gsearch->available_options_vbox);
+ gtk_widget_hide (gsearch->progress_spinner);
+ gtk_widget_hide (gsearch->stop_button);
+
+ gtk_window_set_focus (GTK_WINDOW (gsearch->window),
+ GTK_WIDGET (gsearch_history_entry_get_entry (GSEARCH_HISTORY_ENTRY (gsearch->name_contains_entry))));
+
+ gtk_window_set_default (GTK_WINDOW (gsearch->window), gsearch->find_button);
+
+ return gsearch->window;
+}
+
+static void
+gsearch_window_finalize (GObject * object)
+{
+ parent_class->finalize (object);
+}
+
+static void
+gsearch_window_class_init (GSearchWindowClass * klass)
+{
+ GObjectClass * object_class = (GObjectClass *) klass;
+
+ object_class->finalize = gsearch_window_finalize;
+ parent_class = g_type_class_peek_parent (klass);
+}
+
+GType
+gsearch_window_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GSearchWindowClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gsearch_window_class_init,
+ NULL,
+ NULL,
+ sizeof (GSearchWindow),
+ 0,
+ (GInstanceInitFunc) gsearch_app_create
+ };
+ object_type = g_type_register_static (GTK_TYPE_WINDOW, "GSearchWindow", &object_info, 0);
+ }
+ return object_type;
+}
+
+static void
+gsearchtool_setup_gsettings_notifications (GSearchWindow * gsearch)
+
+{
+ gchar * click_to_activate_pref;
+
+ /* Use the default double click behavior if caja isn't installed */
+ if (gsearch->caja_schema_exists == FALSE) {
+ gsearch->is_search_results_single_click_to_activate = FALSE;
+ return;
+ }
+
+ g_signal_connect (gsearch->caja_settings,
+ "changed::click-policy",
+ G_CALLBACK (single_click_to_activate_key_changed_cb),
+ gsearch);
+
+ /* Get value of caja click behavior (single or double click to activate items) */
+ click_to_activate_pref = g_settings_get_string (gsearch->caja_settings, "click-policy");
+
+ gsearch->is_search_results_single_click_to_activate =
+ (strncmp (click_to_activate_pref, "single", 6) == 0) ? TRUE : FALSE;
+
+ g_free (click_to_activate_pref);
+}
+
+int
+main (int argc,
+ char * argv[])
+{
+ GSearchWindow * gsearch;
+ GOptionContext * context;
+ GtkWidget * window;
+ GError * error = NULL;
+ EggSMClient * client;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ context = g_option_context_new (N_("- the MATE Search Tool"));
+ g_option_context_set_translation_domain(context, GETTEXT_PACKAGE);
+ gsearch_setup_goption_descriptions ();
+ g_option_context_add_main_entries (context, GSearchGOptionEntries, GETTEXT_PACKAGE);
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+ g_option_context_add_group (context, egg_sm_client_get_option_group ());
+ g_option_context_parse (context, &argc, &argv, &error);
+
+ if (error) {
+ g_printerr (_("Failed to parse command line arguments: %s\n"), error->message);
+ return (-1);
+ }
+
+ g_option_context_free (context);
+
+ g_set_application_name (_("Search for Files"));
+ gtk_window_set_default_icon_name (MATE_SEARCH_TOOL_ICON);
+
+ gsearchtool_init_stock_icons ();
+
+ window = g_object_new (GSEARCH_TYPE_WINDOW, NULL);
+ gsearch = GSEARCH_WINDOW (window);
+
+ gtk_window_set_wmclass (GTK_WINDOW (gsearch->window), "mate-search-tool", "mate-search-tool");
+ gtk_window_set_resizable (GTK_WINDOW (gsearch->window), TRUE);
+
+ g_signal_connect (G_OBJECT (gsearch->window), "delete_event",
+ G_CALLBACK (quit_cb),
+ (gpointer) gsearch);
+ g_signal_connect (G_OBJECT (gsearch->window), "key_press_event",
+ G_CALLBACK (key_press_cb),
+ (gpointer) gsearch);
+ g_signal_connect (G_OBJECT (gsearch->window), "window_state_event",
+ G_CALLBACK (window_state_event_cb),
+ (gpointer) gsearch);
+
+ if ((client = egg_sm_client_get ()) != NULL) {
+ g_signal_connect (client, "save_state",
+ G_CALLBACK (save_session_cb),
+ (gpointer) gsearch);
+ g_signal_connect (client, "quit",
+ G_CALLBACK (quit_session_cb),
+ (gpointer) gsearch);
+ }
+
+ gtk_widget_show (gsearch->window);
+
+ gsearchtool_setup_gsettings_notifications (gsearch);
+
+ if (handle_goption_args (gsearch) == FALSE) {
+ handle_gsettings_settings (gsearch);
+ }
+
+ gtk_main ();
+ return 0;
+}
diff --git a/gsearchtool/src/gsearchtool.h b/gsearchtool/src/gsearchtool.h
new file mode 100644
index 00000000..f48c13f2
--- /dev/null
+++ b/gsearchtool/src/gsearchtool.h
@@ -0,0 +1,243 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * MATE Search Tool
+ *
+ * File: gsearchtool.h
+ *
+ * (C) 1998,2002 the Free Software Foundation
+ *
+ * Authors: Dennis Cranston <[email protected]>
+ * George Lebl
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _GSEARCHTOOL_H_
+#define _GSEARCHTOOL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif
+
+#include <gtk/gtk.h>
+
+#define GSEARCH_TYPE_WINDOW gsearch_window_get_type()
+#define GSEARCH_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSEARCH_TYPE_WINDOW, GSearchWindow))
+#define GSEARCH_WINDOW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GSEARCH_TYPE_WINDOW, GSearchWindowClass))
+#define GSEARCH_IS_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSEARCH_TYPE_WINDOW))
+#define GSEARCH_IS_WINDOW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GSEARCH_TYPE_WINDOW))
+#define GSEARCH_WINDOW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GSEARCH_TYPE_WINDOW, GSearchWindowClass))
+
+#define MATE_SEARCH_TOOL_ICON "system-search"
+#define MINIMUM_WINDOW_WIDTH 420
+#define MINIMUM_WINDOW_HEIGHT 310
+#define DEFAULT_WINDOW_WIDTH 554
+#define DEFAULT_WINDOW_HEIGHT 350
+#define WINDOW_HEIGHT_STEP 35
+#define NUM_VISIBLE_COLUMNS 5
+#define CAJA_PREFERENCES_SCHEMA "org.mate.caja.preferences"
+
+typedef enum {
+ STOPPED,
+ ABORTED,
+ RUNNING,
+ MAKE_IT_STOP,
+ MAKE_IT_QUIT
+} GSearchCommandStatus;
+
+typedef enum {
+ SPEED_TRADEOFF_ALWAYS = 0,
+ SPEED_TRADEOFF_LOCAL_ONLY,
+ SPEED_TRADEOFF_NEVER
+} CajaSpeedTradeoff;
+
+typedef enum {
+ CAJA_DATE_FORMAT_LOCALE = 0,
+ CAJA_DATE_FORMAT_ISO,
+ CAJA_DATE_FORMAT_INFORMAL
+} CajaDateFormat;
+
+typedef enum {
+ COLUMN_ICON,
+ COLUMN_NAME,
+ COLUMN_RELATIVE_PATH,
+ COLUMN_LOCALE_FILE,
+ COLUMN_READABLE_SIZE,
+ COLUMN_SIZE,
+ COLUMN_TYPE,
+ COLUMN_READABLE_DATE,
+ COLUMN_DATE,
+ COLUMN_MONITOR,
+ COLUMN_NO_FILES_FOUND,
+ NUM_COLUMNS
+} GSearchResultColumns;
+
+typedef struct _GSearchWindow GSearchWindow;
+typedef struct _GSearchWindowClass GSearchWindowClass;
+typedef struct _GSearchCommandDetails GSearchCommandDetails;
+typedef struct _GSearchConstraint GSearchConstraint;
+typedef struct _GSearchMonitor GSearchMonitor;
+
+struct _GSearchWindow {
+ GtkWindow parent_instance;
+
+ GtkWidget * window;
+ GtkUIManager * window_ui_manager;
+ GdkGeometry window_geometry;
+ gint window_width;
+ gint window_height;
+ gboolean is_window_maximized;
+ gboolean is_window_accessible;
+
+ GtkWidget * name_contains_entry;
+ GtkWidget * look_in_folder_button;
+ GtkWidget * name_and_folder_table;
+ GtkWidget * progress_spinner;
+ GtkWidget * find_button;
+ GtkWidget * stop_button;
+ GtkWidget * focus;
+
+ GtkWidget * show_more_options_expander;
+ GtkWidget * available_options_vbox;
+ GtkWidget * available_options_label;
+ GtkWidget * available_options_combo_box;
+ GtkWidget * available_options_add_button;
+ GtkSizeGroup * available_options_button_size_group;
+ GList * available_options_selected_list;
+
+ GtkWidget * files_found_label;
+ GtkWidget * search_results_vbox;
+ GtkWidget * search_results_popup_menu;
+ GtkWidget * search_results_popup_submenu;
+ GtkWidget * search_results_save_results_as_item;
+ GtkTreeView * search_results_tree_view;
+ GtkTreeViewColumn * search_results_folder_column;
+ GtkTreeViewColumn * search_results_size_column;
+ GtkTreeViewColumn * search_results_type_column;
+ GtkTreeViewColumn * search_results_date_column;
+ GtkListStore * search_results_list_store;
+ GtkCellRenderer * search_results_name_cell_renderer;
+ GtkTreeSelection * search_results_selection;
+ GtkTreeIter search_results_iter;
+ GtkTreePath * search_results_hover_path;
+ GHashTable * search_results_filename_hash_table;
+ GHashTable * search_results_pixbuf_hash_table;
+ CajaDateFormat search_results_date_format;
+ gint show_thumbnails_file_size_limit;
+ gboolean show_thumbnails;
+ gboolean is_search_results_single_click_to_activate;
+ gboolean is_locate_database_check_finished;
+ gboolean is_locate_database_available;
+
+ gchar * save_results_as_default_filename;
+
+ GSettings * mate_search_tool_settings;
+ GSettings * mate_search_tool_select_settings;
+ GSettings * mate_desktop_interface_settings;
+ GSettings * caja_settings;
+ gboolean caja_schema_exists;
+
+ GSearchCommandDetails * command_details;
+};
+
+struct _GSearchCommandDetails {
+ pid_t command_pid;
+ GSearchCommandStatus command_status;
+
+ gchar * name_contains_pattern_string;
+ gchar * name_contains_regex_string;
+ gchar * look_in_folder_string;
+
+ gboolean is_command_first_pass;
+ gboolean is_command_using_quick_mode;
+ gboolean is_command_second_pass_enabled;
+ gboolean is_command_show_hidden_files_enabled;
+ gboolean is_command_regex_matching_enabled;
+ gboolean is_command_timeout_enabled;
+};
+
+struct _GSearchConstraint {
+ gint constraint_id;
+ union {
+ gchar * text;
+ gint time;
+ gint number;
+ } data;
+};
+
+struct _GSearchWindowClass {
+ GtkWindowClass parent_class;
+};
+
+struct _GSearchMonitor {
+ GSearchWindow * gsearch;
+ GtkTreeRowReference * reference;
+ GFileMonitor * handle;
+};
+
+GType
+gsearch_window_get_type (void);
+
+gchar *
+build_search_command (GSearchWindow * gsearch,
+ gboolean first_pass);
+void
+spawn_search_command (GSearchWindow * gsearch,
+ gchar * command);
+void
+add_constraint (GSearchWindow * gsearch,
+ gint constraint_id,
+ gchar * value,
+ gboolean show_constraint);
+void
+update_constraint_info (GSearchConstraint * constraint,
+ gchar * info);
+void
+remove_constraint (gint constraint_id);
+
+void
+set_constraint_gsettings_boolean (gint constraint_id,
+ gboolean flag);
+void
+set_constraint_selected_state (GSearchWindow * gsearch,
+ gint constraint_id,
+ gboolean state);
+void
+set_clone_command (GSearchWindow * gsearch,
+ gint * argcp,
+ gchar *** argvp,
+ gpointer client_data,
+ gboolean escape_values);
+void
+update_search_counts (GSearchWindow * gsearch);
+
+gboolean
+tree_model_iter_free_monitor (GtkTreeModel * model,
+ GtkTreePath * path,
+ GtkTreeIter * iter,
+ gpointer data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GSEARCHTOOL_H_ */