Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| /* -*- 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 <dennis_cranston@yahoo.com> | |
| * 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_box_new (GTK_ORIENTATION_HORIZONTAL, 0); | |
| 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_box_new (GTK_ORIENTATION_HORIZONTAL, 0); | |
| 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_box_new (GTK_ORIENTATION_HORIZONTAL, 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_box_new (GTK_ORIENTATION_HORIZONTAL, 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_box_new (GTK_ORIENTATION_VERTICAL, 6); | |
| hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 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_box_new (GTK_ORIENTATION_VERTICAL, 6); | |
| hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 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); | |
| 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_box_new (GTK_ORIENTATION_VERTICAL, 6); | |
| gtk_container_add (GTK_CONTAINER (gsearch->window), container); | |
| gtk_container_set_border_width (GTK_CONTAINER (container), 12); | |
| hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); | |
| gtk_box_pack_start (GTK_BOX (container), hbox, FALSE, FALSE, 0); | |
| gsearch->name_and_folder_table = gtk_grid_new (); | |
| gtk_grid_set_row_spacing (GTK_GRID (gsearch->name_and_folder_table), 6); | |
| gtk_grid_set_column_spacing (GTK_GRID (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_grid_attach (GTK_GRID (gsearch->name_and_folder_table), label, 0, 0, 1, 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_widget_set_hexpand (gsearch->name_contains_entry, TRUE); | |
| gtk_grid_attach (GTK_GRID (gsearch->name_and_folder_table), gsearch->name_contains_entry, 1, 0, 1, 1); | |
| 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_grid_attach (GTK_GRID (gsearch->name_and_folder_table), label, 0, 1, 1, 1); | |
| 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_widget_set_hexpand (gsearch->look_in_folder_button, TRUE); | |
| gtk_grid_attach (GTK_GRID (gsearch->name_and_folder_table), gsearch->look_in_folder_button, 1, 1, 1, 1); | |
| 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_box_new (GTK_ORIENTATION_VERTICAL, 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_button_box_new (GTK_ORIENTATION_HORIZONTAL); | |
| 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; | |
| } |