PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/gnome-search-tool-3.4.0/src/gsearchtool-support.c

#
C | 1828 lines | 1390 code | 316 blank | 122 comment | 306 complexity | e65f539990d3f39d2913b5d6a6ac46ce MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
  2. /*
  3. * GNOME Search Tool
  4. *
  5. * File: gsearchtool-support.c
  6. *
  7. * (C) 2002 the Free Software Foundation
  8. *
  9. * Authors: Dennis Cranston <dennis_cranston@yahoo.com>
  10. * George Lebl
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
  25. *
  26. */
  27. #ifdef HAVE_CONFIG_H
  28. # include <config.h>
  29. #endif
  30. #include <string.h>
  31. #include <glib/gi18n.h>
  32. #include <glib.h>
  33. #include <regex.h>
  34. #include <stdlib.h>
  35. #include <gdk/gdkx.h>
  36. #include <gio/gio.h>
  37. #include <gio/gdesktopappinfo.h>
  38. #include "gsearchtool.h"
  39. #include "gsearchtool-callbacks.h"
  40. #include "gsearchtool-support.h"
  41. #define C_STANDARD_STRFTIME_CHARACTERS "aAbBcdHIjmMpSUwWxXyYZ"
  42. #define C_STANDARD_NUMERIC_STRFTIME_CHARACTERS "dHIjmMSUwWyY"
  43. #define SUS_EXTENDED_STRFTIME_MODIFIERS "EO"
  44. #define BINARY_EXEC_MIME_TYPE "application/x-executable"
  45. #define GSEARCH_DATE_FORMAT_LOCALE "locale"
  46. #define GSEARCH_DATE_FORMAT_ISO "iso"
  47. GtkTreeViewColumn *
  48. gsearchtool_gtk_tree_view_get_column_with_sort_column_id (GtkTreeView * treeview,
  49. gint id);
  50. /* START OF THE GCONF FUNCTIONS */
  51. static gboolean
  52. gsearchtool_gconf_handle_error (GError ** error)
  53. {
  54. if (error != NULL) {
  55. if (*error != NULL) {
  56. g_warning (_("GConf error:\n %s"), (*error)->message);
  57. g_error_free (*error);
  58. *error = NULL;
  59. return TRUE;
  60. }
  61. }
  62. return FALSE;
  63. }
  64. static GConfClient *
  65. gsearchtool_gconf_client_get_global (void)
  66. {
  67. static GConfClient * global_gconf_client = NULL;
  68. /* Initialize gconf if needed */
  69. if (!gconf_is_initialized ()) {
  70. char *argv[] = { "gsearchtool-preferences", NULL };
  71. GError *error = NULL;
  72. if (!gconf_init (1, argv, &error)) {
  73. if (gsearchtool_gconf_handle_error (&error)) {
  74. return NULL;
  75. }
  76. }
  77. }
  78. if (global_gconf_client == NULL) {
  79. global_gconf_client = gconf_client_get_default ();
  80. }
  81. return global_gconf_client;
  82. }
  83. char *
  84. gsearchtool_gconf_get_string (const gchar * key)
  85. {
  86. GConfClient * client;
  87. GError * error = NULL;
  88. gchar * result;
  89. g_return_val_if_fail (key != NULL, NULL);
  90. client = gsearchtool_gconf_client_get_global ();
  91. g_return_val_if_fail (client != NULL, NULL);
  92. result = gconf_client_get_string (client, key, &error);
  93. if (gsearchtool_gconf_handle_error (&error)) {
  94. result = g_strdup ("");
  95. }
  96. return result;
  97. }
  98. void
  99. gsearchtool_gconf_set_string (const gchar * key,
  100. const gchar * value)
  101. {
  102. GConfClient * client;
  103. GError * error = NULL;
  104. g_return_if_fail (key != NULL);
  105. client = gsearchtool_gconf_client_get_global ();
  106. g_return_if_fail (client != NULL);
  107. gconf_client_set_string (client, key, value, &error);
  108. gsearchtool_gconf_handle_error (&error);
  109. }
  110. GSList *
  111. gsearchtool_gconf_get_list (const gchar * key,
  112. GConfValueType list_type)
  113. {
  114. GConfClient * client;
  115. GError * error = NULL;
  116. GSList * result;
  117. g_return_val_if_fail (key != NULL, FALSE);
  118. client = gsearchtool_gconf_client_get_global ();
  119. g_return_val_if_fail (client != NULL, NULL);
  120. result = gconf_client_get_list (client, key, list_type, &error);
  121. if (gsearchtool_gconf_handle_error (&error)) {
  122. result = NULL;
  123. }
  124. return result;
  125. }
  126. void
  127. gsearchtool_gconf_set_list (const gchar * key,
  128. GSList * list,
  129. GConfValueType list_type)
  130. {
  131. GConfClient * client;
  132. GError * error = NULL;
  133. g_return_if_fail (key != NULL);
  134. client = gsearchtool_gconf_client_get_global ();
  135. g_return_if_fail (client != NULL);
  136. gconf_client_set_list (client, key, list_type, list, &error);
  137. gsearchtool_gconf_handle_error (&error);
  138. }
  139. gint
  140. gsearchtool_gconf_get_int (const gchar * key)
  141. {
  142. GConfClient * client;
  143. GError * error = NULL;
  144. gint result;
  145. g_return_val_if_fail (key != NULL, FALSE);
  146. client = gsearchtool_gconf_client_get_global ();
  147. g_return_val_if_fail (client != NULL, FALSE);
  148. result = gconf_client_get_int (client, key, &error);
  149. if (gsearchtool_gconf_handle_error (&error)) {
  150. result = 0;
  151. }
  152. return result;
  153. }
  154. void
  155. gsearchtool_gconf_set_int (const gchar * key,
  156. const gint value)
  157. {
  158. GConfClient * client;
  159. GError * error = NULL;
  160. g_return_if_fail (key != NULL);
  161. client = gsearchtool_gconf_client_get_global ();
  162. g_return_if_fail (client != NULL);
  163. gconf_client_set_int (client, key, value, &error);
  164. gsearchtool_gconf_handle_error (&error);
  165. }
  166. gboolean
  167. gsearchtool_gconf_get_boolean (const gchar * key)
  168. {
  169. GConfClient * client;
  170. GError * error = NULL;
  171. gboolean result;
  172. g_return_val_if_fail (key != NULL, FALSE);
  173. client = gsearchtool_gconf_client_get_global ();
  174. g_return_val_if_fail (client != NULL, FALSE);
  175. result = gconf_client_get_bool (client, key, &error);
  176. if (gsearchtool_gconf_handle_error (&error)) {
  177. result = FALSE;
  178. }
  179. return result;
  180. }
  181. void
  182. gsearchtool_gconf_set_boolean (const gchar * key,
  183. const gboolean flag)
  184. {
  185. GConfClient * client;
  186. GError * error = NULL;
  187. g_return_if_fail (key != NULL);
  188. client = gsearchtool_gconf_client_get_global ();
  189. g_return_if_fail (client != NULL);
  190. gconf_client_set_bool (client, key, flag, &error);
  191. gsearchtool_gconf_handle_error (&error);
  192. }
  193. void
  194. gsearchtool_gconf_add_dir (const gchar * dir)
  195. {
  196. GConfClient * client;
  197. GError * error = NULL;
  198. g_return_if_fail (dir != NULL);
  199. client = gsearchtool_gconf_client_get_global ();
  200. g_return_if_fail (client != NULL);
  201. gconf_client_add_dir (client,
  202. dir,
  203. GCONF_CLIENT_PRELOAD_RECURSIVE,
  204. &error);
  205. gsearchtool_gconf_handle_error (&error);
  206. }
  207. void
  208. gsearchtool_gconf_watch_key (const gchar * dir,
  209. const gchar * key,
  210. GConfClientNotifyFunc callback,
  211. gpointer user_data)
  212. {
  213. GConfClient * client;
  214. GError * error = NULL;
  215. g_return_if_fail (key != NULL);
  216. g_return_if_fail (dir != NULL);
  217. client = gsearchtool_gconf_client_get_global ();
  218. g_return_if_fail (client != NULL);
  219. gconf_client_add_dir (client,
  220. dir,
  221. GCONF_CLIENT_PRELOAD_NONE,
  222. &error);
  223. gsearchtool_gconf_handle_error (&error);
  224. gconf_client_notify_add (client,
  225. key,
  226. callback,
  227. user_data,
  228. NULL,
  229. &error);
  230. gsearchtool_gconf_handle_error (&error);
  231. }
  232. /* START OF GENERIC GNOME-SEARCH-TOOL FUNCTIONS */
  233. gboolean
  234. is_path_hidden (const gchar * path)
  235. {
  236. gint results = FALSE;
  237. gchar * sub_str;
  238. gchar * hidden_path_substr = g_strconcat (G_DIR_SEPARATOR_S, ".", NULL);
  239. sub_str = g_strstr_len (path, strlen (path), hidden_path_substr);
  240. if (sub_str != NULL) {
  241. gchar * gnome_desktop_str;
  242. gnome_desktop_str = g_strconcat (G_DIR_SEPARATOR_S, ".gnome-desktop", G_DIR_SEPARATOR_S, NULL);
  243. /* exclude the .gnome-desktop folder */
  244. if (strncmp (sub_str, gnome_desktop_str, strlen (gnome_desktop_str)) == 0) {
  245. sub_str++;
  246. results = (g_strstr_len (sub_str, strlen (sub_str), hidden_path_substr) != NULL);
  247. }
  248. else {
  249. results = TRUE;
  250. }
  251. g_free (gnome_desktop_str);
  252. }
  253. g_free (hidden_path_substr);
  254. return results;
  255. }
  256. gboolean
  257. is_quick_search_excluded_path (const gchar * path)
  258. {
  259. GSList * exclude_path_list;
  260. GSList * tmp_list;
  261. gchar * dir;
  262. gboolean results = FALSE;
  263. dir = g_strdup (path);
  264. /* Remove trailing G_DIR_SEPARATOR. */
  265. if ((strlen (dir) > 1) && (g_str_has_suffix (dir, G_DIR_SEPARATOR_S) == TRUE)) {
  266. dir[strlen (dir) - 1] = '\0';
  267. }
  268. /* Always exclude a path that is symbolic link. */
  269. if (g_file_test (dir, G_FILE_TEST_IS_SYMLINK)) {
  270. g_free (dir);
  271. return TRUE;
  272. }
  273. g_free (dir);
  274. /* Check path against the Quick-Search-Excluded-Paths list. */
  275. exclude_path_list = gsearchtool_gconf_get_list ("/apps/gnome-search-tool/quick_search_excluded_paths",
  276. GCONF_VALUE_STRING);
  277. for (tmp_list = exclude_path_list; tmp_list; tmp_list = tmp_list->next) {
  278. /* Skip empty or null values. */
  279. if ((tmp_list->data == NULL) || (strlen (tmp_list->data) == 0)) {
  280. continue;
  281. }
  282. dir = g_strdup (tmp_list->data);
  283. /* Wild-card comparisons. */
  284. if (g_strstr_len (dir, strlen (dir), "*") != NULL) {
  285. if (g_pattern_match_simple (dir, path) == TRUE) {
  286. results = TRUE;
  287. g_free (dir);
  288. break;
  289. }
  290. }
  291. /* Non-wild-card comparisons. */
  292. else {
  293. /* Add a trailing G_DIR_SEPARATOR. */
  294. if (g_str_has_suffix (dir, G_DIR_SEPARATOR_S) == FALSE) {
  295. gchar *tmp;
  296. tmp = dir;
  297. dir = g_strconcat (dir, G_DIR_SEPARATOR_S, NULL);
  298. g_free (tmp);
  299. }
  300. if (strcmp (path, dir) == 0) {
  301. results = TRUE;
  302. g_free (dir);
  303. break;
  304. }
  305. }
  306. g_free (dir);
  307. }
  308. for (tmp_list = exclude_path_list; tmp_list; tmp_list = tmp_list->next) {
  309. g_free (tmp_list->data);
  310. }
  311. g_slist_free (exclude_path_list);
  312. return results;
  313. }
  314. gboolean
  315. is_second_scan_excluded_path (const gchar * path)
  316. {
  317. GSList * exclude_path_list;
  318. GSList * tmp_list;
  319. gchar * dir;
  320. gboolean results = FALSE;
  321. dir = g_strdup (path);
  322. /* Remove trailing G_DIR_SEPARATOR. */
  323. if ((strlen (dir) > 1) && (g_str_has_suffix (dir, G_DIR_SEPARATOR_S) == TRUE)) {
  324. dir[strlen (dir) - 1] = '\0';
  325. }
  326. /* Always exclude a path that is symbolic link. */
  327. if (g_file_test (dir, G_FILE_TEST_IS_SYMLINK)) {
  328. g_free (dir);
  329. return TRUE;
  330. }
  331. g_free (dir);
  332. /* Check path against the Quick-Search-Excluded-Paths list. */
  333. exclude_path_list = gsearchtool_gconf_get_list ("/apps/gnome-search-tool/quick_search_second_scan_excluded_paths",
  334. GCONF_VALUE_STRING);
  335. for (tmp_list = exclude_path_list; tmp_list; tmp_list = tmp_list->next) {
  336. /* Skip empty or null values. */
  337. if ((tmp_list->data == NULL) || (strlen (tmp_list->data) == 0)) {
  338. continue;
  339. }
  340. dir = g_strdup (tmp_list->data);
  341. /* Wild-card comparisons. */
  342. if (g_strstr_len (dir, strlen (dir), "*") != NULL) {
  343. if (g_pattern_match_simple (dir, path) == TRUE) {
  344. results = TRUE;
  345. g_free (dir);
  346. break;
  347. }
  348. }
  349. /* Non-wild-card comparisons. */
  350. else {
  351. /* Add a trailing G_DIR_SEPARATOR. */
  352. if (g_str_has_suffix (dir, G_DIR_SEPARATOR_S) == FALSE) {
  353. gchar *tmp;
  354. tmp = dir;
  355. dir = g_strconcat (dir, G_DIR_SEPARATOR_S, NULL);
  356. g_free (tmp);
  357. }
  358. if (strcmp (path, dir) == 0) {
  359. results = TRUE;
  360. g_free (dir);
  361. break;
  362. }
  363. }
  364. g_free (dir);
  365. }
  366. for (tmp_list = exclude_path_list; tmp_list; tmp_list = tmp_list->next) {
  367. g_free (tmp_list->data);
  368. }
  369. g_slist_free (exclude_path_list);
  370. return results;
  371. }
  372. gboolean
  373. compare_regex (const gchar * regex,
  374. const gchar * string)
  375. {
  376. regex_t regexec_pattern;
  377. if (regex == NULL) {
  378. return TRUE;
  379. }
  380. if (!regcomp (&regexec_pattern, regex, REG_EXTENDED|REG_NOSUB)) {
  381. if (regexec (&regexec_pattern, string, 0, 0, 0) != REG_NOMATCH) {
  382. regfree (&regexec_pattern);
  383. return TRUE;
  384. }
  385. regfree (&regexec_pattern);
  386. }
  387. return FALSE;
  388. }
  389. gboolean
  390. limit_string_to_x_lines (GString * string,
  391. gint x)
  392. {
  393. int i;
  394. int count = 0;
  395. for (i = 0; string->str[i] != '\0'; i++) {
  396. if (string->str[i] == '\n') {
  397. count++;
  398. if (count == x) {
  399. g_string_truncate (string, i);
  400. return TRUE;
  401. }
  402. }
  403. }
  404. return FALSE;
  405. }
  406. static gint
  407. count_of_char_in_string (const gchar * string,
  408. const gchar c)
  409. {
  410. int cnt = 0;
  411. for(; *string; string++) {
  412. if (*string == c) cnt++;
  413. }
  414. return cnt;
  415. }
  416. gchar *
  417. escape_single_quotes (const gchar * string)
  418. {
  419. GString * gs;
  420. if (string == NULL) {
  421. return NULL;
  422. }
  423. if (count_of_char_in_string (string, '\'') == 0) {
  424. return g_strdup(string);
  425. }
  426. gs = g_string_new ("");
  427. for(; *string; string++) {
  428. if (*string == '\'') {
  429. g_string_append(gs, "'\\''");
  430. }
  431. else {
  432. g_string_append_c(gs, *string);
  433. }
  434. }
  435. return g_string_free (gs, FALSE);
  436. }
  437. gchar *
  438. escape_double_quotes (const gchar * string)
  439. {
  440. GString * gs;
  441. if (string == NULL) {
  442. return NULL;
  443. }
  444. if (count_of_char_in_string (string, '\"') == 0) {
  445. return g_strdup(string);
  446. }
  447. gs = g_string_new ("");
  448. for(; *string; string++) {
  449. if (*string == '\"') {
  450. g_string_append(gs, "\\\"");
  451. }
  452. else {
  453. g_string_append_c(gs, *string);
  454. }
  455. }
  456. return g_string_free (gs, FALSE);
  457. }
  458. gchar *
  459. backslash_backslash_characters (const gchar * string)
  460. {
  461. GString * gs;
  462. if (string == NULL) {
  463. return NULL;
  464. }
  465. if (count_of_char_in_string (string, '\\') == 0){
  466. return g_strdup(string);
  467. }
  468. gs = g_string_new ("");
  469. for(; *string; string++) {
  470. if (*string == '\\') {
  471. g_string_append(gs, "\\\\");
  472. }
  473. else {
  474. g_string_append_c(gs, *string);
  475. }
  476. }
  477. return g_string_free (gs, FALSE);
  478. }
  479. gchar *
  480. backslash_special_characters (const gchar * string)
  481. {
  482. GString * gs;
  483. if (string == NULL) {
  484. return NULL;
  485. }
  486. if ((count_of_char_in_string (string, '\\') == 0) &&
  487. (count_of_char_in_string (string, '-') == 0)) {
  488. return g_strdup(string);
  489. }
  490. gs = g_string_new ("");
  491. for(; *string; string++) {
  492. if (*string == '\\') {
  493. g_string_append(gs, "\\\\");
  494. }
  495. else if (*string == '-') {
  496. g_string_append(gs, "\\-");
  497. }
  498. else {
  499. g_string_append_c(gs, *string);
  500. }
  501. }
  502. return g_string_free (gs, FALSE);
  503. }
  504. gchar *
  505. remove_mnemonic_character (const gchar * string)
  506. {
  507. GString * gs;
  508. gboolean first_mnemonic = TRUE;
  509. if (string == NULL) {
  510. return NULL;
  511. }
  512. gs = g_string_new ("");
  513. for(; *string; string++) {
  514. if ((first_mnemonic) && (*string == '_')) {
  515. first_mnemonic = FALSE;
  516. continue;
  517. }
  518. g_string_append_c(gs, *string);
  519. }
  520. return g_string_free (gs, FALSE);
  521. }
  522. gchar *
  523. get_readable_date (const gchar * format_string,
  524. const time_t file_time_raw)
  525. {
  526. struct tm * file_time;
  527. gchar * format;
  528. GDate * today;
  529. GDate * file_date;
  530. guint32 file_date_age;
  531. gchar * readable_date;
  532. file_time = localtime (&file_time_raw);
  533. /* Base format of date column on nautilus date_format key */
  534. if (format_string != NULL) {
  535. if (strcmp(format_string, GSEARCH_DATE_FORMAT_LOCALE) == 0) {
  536. return gsearchtool_strdup_strftime ("%c", file_time);
  537. } else if (strcmp (format_string, GSEARCH_DATE_FORMAT_ISO) == 0) {
  538. return gsearchtool_strdup_strftime ("%Y-%m-%d %H:%M:%S", file_time);
  539. }
  540. }
  541. file_date = g_date_new_dmy (file_time->tm_mday,
  542. file_time->tm_mon + 1,
  543. file_time->tm_year + 1900);
  544. today = g_date_new ();
  545. g_date_set_time_t (today, time (NULL));
  546. file_date_age = g_date_get_julian (today) - g_date_get_julian (file_date);
  547. g_date_free (today);
  548. g_date_free (file_date);
  549. if (file_date_age == 0) {
  550. /* Translators: Below are the strings displayed in the 'Date Modified'
  551. column of the list view. The format of this string can vary depending
  552. on age of a file. Please modify the format of the timestamp to match
  553. your locale. For example, to display 24 hour time replace the '%-I'
  554. with '%-H' and remove the '%p'. (See bugzilla report #120434.) */
  555. format = g_strdup(_("today at %-I:%M %p"));
  556. } else if (file_date_age == 1) {
  557. format = g_strdup(_("yesterday at %-I:%M %p"));
  558. } else if (file_date_age < 7) {
  559. format = g_strdup(_("%A, %B %-d %Y at %-I:%M:%S %p"));
  560. } else {
  561. format = g_strdup(_("%A, %B %-d %Y at %-I:%M:%S %p"));
  562. }
  563. readable_date = gsearchtool_strdup_strftime (format, file_time);
  564. g_free (format);
  565. return readable_date;
  566. }
  567. gchar *
  568. gsearchtool_strdup_strftime (const gchar * format,
  569. struct tm * time_pieces)
  570. {
  571. /* This function is borrowed from eel's eel_strdup_strftime() */
  572. GString * string;
  573. const char * remainder, * percent;
  574. char code[4], buffer[512];
  575. char * piece, * result, * converted;
  576. size_t string_length;
  577. gboolean strip_leading_zeros, turn_leading_zeros_to_spaces;
  578. char modifier;
  579. int i;
  580. /* Format could be translated, and contain UTF-8 chars,
  581. * so convert to locale encoding which strftime uses */
  582. converted = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
  583. g_return_val_if_fail (converted != NULL, NULL);
  584. string = g_string_new ("");
  585. remainder = converted;
  586. /* Walk from % character to % character. */
  587. for (;;) {
  588. percent = strchr (remainder, '%');
  589. if (percent == NULL) {
  590. g_string_append (string, remainder);
  591. break;
  592. }
  593. g_string_append_len (string, remainder,
  594. percent - remainder);
  595. /* Handle the "%" character. */
  596. remainder = percent + 1;
  597. switch (*remainder) {
  598. case '-':
  599. strip_leading_zeros = TRUE;
  600. turn_leading_zeros_to_spaces = FALSE;
  601. remainder++;
  602. break;
  603. case '_':
  604. strip_leading_zeros = FALSE;
  605. turn_leading_zeros_to_spaces = TRUE;
  606. remainder++;
  607. break;
  608. case '%':
  609. g_string_append_c (string, '%');
  610. remainder++;
  611. continue;
  612. case '\0':
  613. g_warning ("Trailing %% passed to gsearchtool_strdup_strftime");
  614. g_string_append_c (string, '%');
  615. continue;
  616. default:
  617. strip_leading_zeros = FALSE;
  618. turn_leading_zeros_to_spaces = FALSE;
  619. break;
  620. }
  621. modifier = 0;
  622. if (strchr (SUS_EXTENDED_STRFTIME_MODIFIERS, *remainder) != NULL) {
  623. modifier = *remainder;
  624. remainder++;
  625. if (*remainder == 0) {
  626. g_warning ("Unfinished %%%c modifier passed to gsearchtool_strdup_strftime", modifier);
  627. break;
  628. }
  629. }
  630. if (strchr (C_STANDARD_STRFTIME_CHARACTERS, *remainder) == NULL) {
  631. g_warning ("gsearchtool_strdup_strftime does not support "
  632. "non-standard escape code %%%c",
  633. *remainder);
  634. }
  635. /* Convert code to strftime format. We have a fixed
  636. * limit here that each code can expand to a maximum
  637. * of 512 bytes, which is probably OK. There's no
  638. * limit on the total size of the result string.
  639. */
  640. i = 0;
  641. code[i++] = '%';
  642. if (modifier != 0) {
  643. #ifdef HAVE_STRFTIME_EXTENSION
  644. code[i++] = modifier;
  645. #endif
  646. }
  647. code[i++] = *remainder;
  648. code[i++] = '\0';
  649. string_length = strftime (buffer, sizeof (buffer),
  650. code, time_pieces);
  651. if (string_length == 0) {
  652. /* We could put a warning here, but there's no
  653. * way to tell a successful conversion to
  654. * empty string from a failure.
  655. */
  656. buffer[0] = '\0';
  657. }
  658. /* Strip leading zeros if requested. */
  659. piece = buffer;
  660. if (strip_leading_zeros || turn_leading_zeros_to_spaces) {
  661. if (strchr (C_STANDARD_NUMERIC_STRFTIME_CHARACTERS, *remainder) == NULL) {
  662. g_warning ("gsearchtool_strdup_strftime does not support "
  663. "modifier for non-numeric escape code %%%c%c",
  664. remainder[-1],
  665. *remainder);
  666. }
  667. if (*piece == '0') {
  668. do {
  669. piece++;
  670. } while (*piece == '0');
  671. if (!g_ascii_isdigit (*piece)) {
  672. piece--;
  673. }
  674. }
  675. if (turn_leading_zeros_to_spaces) {
  676. memset (buffer, ' ', piece - buffer);
  677. piece = buffer;
  678. }
  679. }
  680. remainder++;
  681. /* Add this piece. */
  682. g_string_append (string, piece);
  683. }
  684. /* Convert the string back into utf-8. */
  685. result = g_locale_to_utf8 (string->str, -1, NULL, NULL, NULL);
  686. g_string_free (string, TRUE);
  687. g_free (converted);
  688. return result;
  689. }
  690. gchar *
  691. get_file_type_description (const gchar * file,
  692. GFileInfo * file_info)
  693. {
  694. const char * content_type = NULL;
  695. gchar * desc;
  696. if (file != NULL) {
  697. content_type = g_file_info_get_content_type (file_info);
  698. }
  699. if (content_type == NULL || g_content_type_is_unknown (content_type) == TRUE) {
  700. return g_strdup (g_content_type_get_description ("application/octet-stream"));
  701. }
  702. desc = g_strdup (g_content_type_get_description (content_type));
  703. if (g_file_info_get_is_symlink (file_info) == TRUE) {
  704. const gchar * symlink_target;
  705. gchar * absolute_symlink = NULL;
  706. gchar * str = NULL;
  707. symlink_target = g_file_info_get_symlink_target (file_info);
  708. if (g_path_is_absolute (symlink_target) != TRUE) {
  709. gchar *dirname;
  710. dirname = g_path_get_dirname (file);
  711. absolute_symlink = g_strconcat (dirname, G_DIR_SEPARATOR_S, symlink_target, NULL);
  712. g_free (dirname);
  713. }
  714. else {
  715. absolute_symlink = g_strdup (symlink_target);
  716. }
  717. if (g_file_test (absolute_symlink, G_FILE_TEST_EXISTS) != TRUE) {
  718. if ((g_ascii_strcasecmp (content_type, "x-special/socket") != 0) &&
  719. (g_ascii_strcasecmp (content_type, "x-special/fifo") != 0)) {
  720. g_free (absolute_symlink);
  721. g_free (desc);
  722. return g_strdup (_("link (broken)"));
  723. }
  724. }
  725. str = g_strdup_printf (_("link to %s"), (desc != NULL) ? desc : content_type);
  726. g_free (absolute_symlink);
  727. g_free (desc);
  728. return str;
  729. }
  730. return desc;
  731. }
  732. static gchar *
  733. gsearchtool_pixmap_file (const gchar * partial_path)
  734. {
  735. gchar * path;
  736. path = g_build_filename (DATADIR "/pixmaps/gsearchtool", partial_path, NULL);
  737. if (g_file_test (path, G_FILE_TEST_EXISTS)) {
  738. return path;
  739. }
  740. g_free (path);
  741. return NULL;
  742. }
  743. static GdkPixbuf *
  744. gsearchtool_load_thumbnail_frame (void)
  745. {
  746. GdkPixbuf * pixbuf = NULL;
  747. gchar * image_path;
  748. image_path = gsearchtool_pixmap_file ("thumbnail_frame.png");
  749. if (image_path != NULL) {
  750. pixbuf = gdk_pixbuf_new_from_file (image_path, NULL);
  751. }
  752. g_free (image_path);
  753. return pixbuf;
  754. }
  755. static void
  756. gsearchtool_draw_frame_row (GdkPixbuf * frame_image,
  757. gint target_width,
  758. gint source_width,
  759. gint source_v_position,
  760. gint dest_v_position,
  761. GdkPixbuf * result_pixbuf,
  762. gint left_offset,
  763. gint height)
  764. {
  765. gint remaining_width;
  766. gint h_offset;
  767. gint slab_width;
  768. remaining_width = target_width;
  769. h_offset = 0;
  770. while (remaining_width > 0) {
  771. slab_width = remaining_width > source_width ? source_width : remaining_width;
  772. gdk_pixbuf_copy_area (frame_image, left_offset, source_v_position, slab_width,
  773. height, result_pixbuf, left_offset + h_offset, dest_v_position);
  774. remaining_width -= slab_width;
  775. h_offset += slab_width;
  776. }
  777. }
  778. static void
  779. gsearchtool_draw_frame_column (GdkPixbuf * frame_image,
  780. gint target_height,
  781. gint source_height,
  782. gint source_h_position,
  783. gint dest_h_position,
  784. GdkPixbuf * result_pixbuf,
  785. gint top_offset,
  786. gint width)
  787. {
  788. gint remaining_height;
  789. gint v_offset;
  790. gint slab_height;
  791. remaining_height = target_height;
  792. v_offset = 0;
  793. while (remaining_height > 0) {
  794. slab_height = remaining_height > source_height ? source_height : remaining_height;
  795. gdk_pixbuf_copy_area (frame_image, source_h_position, top_offset, width, slab_height,
  796. result_pixbuf, dest_h_position, top_offset + v_offset);
  797. remaining_height -= slab_height;
  798. v_offset += slab_height;
  799. }
  800. }
  801. static GdkPixbuf *
  802. gsearchtool_stretch_frame_image (GdkPixbuf *frame_image,
  803. gint left_offset,
  804. gint top_offset,
  805. gint right_offset,
  806. gint bottom_offset,
  807. gint dest_width,
  808. gint dest_height,
  809. gboolean fill_flag)
  810. {
  811. GdkPixbuf * result_pixbuf;
  812. gint frame_width, frame_height;
  813. gint target_width, target_frame_width;
  814. gint target_height, target_frame_height;
  815. frame_width = gdk_pixbuf_get_width (frame_image);
  816. frame_height = gdk_pixbuf_get_height (frame_image);
  817. if (fill_flag) {
  818. result_pixbuf = gdk_pixbuf_scale_simple (frame_image, dest_width, dest_height, GDK_INTERP_NEAREST);
  819. } else {
  820. result_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, dest_width, dest_height);
  821. }
  822. /* clear the new pixbuf */
  823. if (fill_flag == FALSE) {
  824. gdk_pixbuf_fill (result_pixbuf, 0xffffffff);
  825. }
  826. target_width = dest_width - left_offset - right_offset;
  827. target_frame_width = frame_width - left_offset - right_offset;
  828. target_height = dest_height - top_offset - bottom_offset;
  829. target_frame_height = frame_height - top_offset - bottom_offset;
  830. /* Draw the left top corner and top row */
  831. gdk_pixbuf_copy_area (frame_image, 0, 0, left_offset, top_offset, result_pixbuf, 0, 0);
  832. gsearchtool_draw_frame_row (frame_image, target_width, target_frame_width, 0, 0,
  833. result_pixbuf, left_offset, top_offset);
  834. /* Draw the right top corner and left column */
  835. gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, 0, right_offset, top_offset,
  836. result_pixbuf, dest_width - right_offset, 0);
  837. gsearchtool_draw_frame_column (frame_image, target_height, target_frame_height, 0, 0,
  838. result_pixbuf, top_offset, left_offset);
  839. /* Draw the bottom right corner and bottom row */
  840. gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, frame_height - bottom_offset,
  841. right_offset, bottom_offset, result_pixbuf, dest_width - right_offset,
  842. dest_height - bottom_offset);
  843. gsearchtool_draw_frame_row (frame_image, target_width, target_frame_width,
  844. frame_height - bottom_offset, dest_height - bottom_offset,
  845. result_pixbuf, left_offset, bottom_offset);
  846. /* Draw the bottom left corner and the right column */
  847. gdk_pixbuf_copy_area (frame_image, 0, frame_height - bottom_offset, left_offset, bottom_offset,
  848. result_pixbuf, 0, dest_height - bottom_offset);
  849. gsearchtool_draw_frame_column (frame_image, target_height, target_frame_height,
  850. frame_width - right_offset, dest_width - right_offset,
  851. result_pixbuf, top_offset, right_offset);
  852. return result_pixbuf;
  853. }
  854. static GdkPixbuf *
  855. gsearchtool_embed_image_in_frame (GdkPixbuf * source_image,
  856. GdkPixbuf * frame_image,
  857. gint left_offset,
  858. gint top_offset,
  859. gint right_offset,
  860. gint bottom_offset)
  861. {
  862. GdkPixbuf * result_pixbuf;
  863. gint source_width, source_height;
  864. gint dest_width, dest_height;
  865. source_width = gdk_pixbuf_get_width (source_image);
  866. source_height = gdk_pixbuf_get_height (source_image);
  867. dest_width = source_width + left_offset + right_offset;
  868. dest_height = source_height + top_offset + bottom_offset;
  869. result_pixbuf = gsearchtool_stretch_frame_image (frame_image, left_offset, top_offset, right_offset, bottom_offset,
  870. dest_width, dest_height, FALSE);
  871. gdk_pixbuf_copy_area (source_image, 0, 0, source_width, source_height, result_pixbuf, left_offset, top_offset);
  872. return result_pixbuf;
  873. }
  874. static void
  875. gsearchtool_thumbnail_frame_image (GdkPixbuf ** pixbuf)
  876. {
  877. GdkPixbuf * pixbuf_with_frame;
  878. GdkPixbuf * frame;
  879. frame = gsearchtool_load_thumbnail_frame ();
  880. if (frame == NULL) {
  881. return;
  882. }
  883. pixbuf_with_frame = gsearchtool_embed_image_in_frame (*pixbuf, frame, 3, 3, 6, 6);
  884. g_object_unref (*pixbuf);
  885. g_object_unref (frame);
  886. *pixbuf = pixbuf_with_frame;
  887. }
  888. static GdkPixbuf *
  889. gsearchtool_get_thumbnail_image (const gchar * thumbnail)
  890. {
  891. GdkPixbuf * pixbuf = NULL;
  892. if (thumbnail != NULL) {
  893. if (g_file_test (thumbnail, G_FILE_TEST_EXISTS)) {
  894. GdkPixbuf * thumbnail_pixbuf = NULL;
  895. gfloat scale_factor_x = 1.0;
  896. gfloat scale_factor_y = 1.0;
  897. gint scale_x;
  898. gint scale_y;
  899. thumbnail_pixbuf = gdk_pixbuf_new_from_file (thumbnail, NULL);
  900. gsearchtool_thumbnail_frame_image (&thumbnail_pixbuf);
  901. if (gdk_pixbuf_get_width (thumbnail_pixbuf) > ICON_SIZE) {
  902. scale_factor_x = (gfloat) ICON_SIZE / (gfloat) gdk_pixbuf_get_width (thumbnail_pixbuf);
  903. }
  904. if (gdk_pixbuf_get_height (thumbnail_pixbuf) > ICON_SIZE) {
  905. scale_factor_y = (gfloat) ICON_SIZE / (gfloat) gdk_pixbuf_get_height (thumbnail_pixbuf);
  906. }
  907. if (gdk_pixbuf_get_width (thumbnail_pixbuf) > gdk_pixbuf_get_height (thumbnail_pixbuf)) {
  908. scale_x = ICON_SIZE;
  909. scale_y = (gint) (gdk_pixbuf_get_height (thumbnail_pixbuf) * scale_factor_x);
  910. }
  911. else {
  912. scale_x = (gint) (gdk_pixbuf_get_width (thumbnail_pixbuf) * scale_factor_y);
  913. scale_y = ICON_SIZE;
  914. }
  915. pixbuf = gdk_pixbuf_scale_simple (thumbnail_pixbuf, scale_x, scale_y, GDK_INTERP_BILINEAR);
  916. g_object_unref (thumbnail_pixbuf);
  917. }
  918. }
  919. return pixbuf;
  920. }
  921. static GdkPixbuf *
  922. get_themed_icon_pixbuf (GThemedIcon * icon,
  923. int size,
  924. GtkIconTheme * icon_theme)
  925. {
  926. char ** icon_names;
  927. GtkIconInfo * icon_info;
  928. GdkPixbuf * pixbuf;
  929. GError * error = NULL;
  930. g_object_get (icon, "names", &icon_names, NULL);
  931. icon_info = gtk_icon_theme_choose_icon (icon_theme, (const char **)icon_names, size, 0);
  932. if (icon_info == NULL) {
  933. icon_info = gtk_icon_theme_lookup_icon (icon_theme, "text-x-generic", size, GTK_ICON_LOOKUP_USE_BUILTIN);
  934. }
  935. pixbuf = gtk_icon_info_load_icon (icon_info, &error);
  936. if (pixbuf == NULL) {
  937. g_warning ("Could not load icon pixbuf: %s\n", error->message);
  938. g_clear_error (&error);
  939. }
  940. gtk_icon_info_free (icon_info);
  941. g_strfreev (icon_names);
  942. return pixbuf;
  943. }
  944. GdkPixbuf *
  945. get_file_pixbuf (GSearchWindow * gsearch,
  946. GFileInfo * file_info)
  947. {
  948. GdkPixbuf * pixbuf;
  949. GIcon * icon = NULL;
  950. const gchar * thumbnail_path = NULL;
  951. if (file_info == NULL) {
  952. return NULL;
  953. }
  954. icon = g_file_info_get_icon (file_info);
  955. if (gsearch->show_thumbnails == TRUE) {
  956. thumbnail_path = g_file_info_get_attribute_byte_string (file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
  957. }
  958. if (thumbnail_path != NULL) {
  959. pixbuf = gsearchtool_get_thumbnail_image (thumbnail_path);
  960. }
  961. else {
  962. gchar * icon_string;
  963. icon_string = g_icon_to_string (icon);
  964. pixbuf = (GdkPixbuf *) g_hash_table_lookup (gsearch->search_results_filename_hash_table, icon_string);
  965. if (pixbuf == NULL) {
  966. pixbuf = get_themed_icon_pixbuf (G_THEMED_ICON (icon), ICON_SIZE, gtk_icon_theme_get_default ());
  967. g_hash_table_insert (gsearch->search_results_filename_hash_table, g_strdup (icon_string), pixbuf);
  968. }
  969. g_free (icon_string);
  970. }
  971. return pixbuf;
  972. }
  973. gboolean
  974. open_file_with_filemanager (GtkWidget * window,
  975. const gchar * file,
  976. gboolean open_parent)
  977. {
  978. GDesktopAppInfo * d_app_info;
  979. GKeyFile * key_file;
  980. GdkAppLaunchContext * ctx = NULL;
  981. GList * list = NULL;
  982. GAppInfo * g_app_info;
  983. GFile * g_file;
  984. gchar * command;
  985. gchar * contents;
  986. gchar * uri;
  987. gboolean result = TRUE;
  988. if (open_parent == TRUE && g_file_test (file, G_FILE_TEST_IS_DIR)) {
  989. gchar * folder = g_path_get_dirname (file);
  990. uri = g_filename_to_uri (folder, NULL, NULL);
  991. g_free (folder);
  992. }
  993. else {
  994. uri = g_filename_to_uri (file, NULL, NULL);
  995. }
  996. list = g_list_prepend (list, uri);
  997. g_file = g_file_new_for_path (g_path_get_dirname (file));
  998. g_app_info = g_file_query_default_handler (g_file, NULL, NULL);
  999. if (strcmp (g_app_info_get_executable (g_app_info), "nautilus") == 0) {
  1000. command = g_strconcat ("nautilus ",
  1001. "--no-desktop ",
  1002. "--no-default-window ",
  1003. NULL);
  1004. }
  1005. else {
  1006. command = g_strconcat (g_app_info_get_executable (g_app_info),
  1007. " ", NULL);
  1008. }
  1009. contents = g_strdup_printf ("[Desktop Entry]\n"
  1010. "Name=Nautilus\n"
  1011. "Icon=file-manager\n"
  1012. "Exec=%s\n"
  1013. "Terminal=false\n"
  1014. "StartupNotify=true\n"
  1015. "Type=Application\n",
  1016. command);
  1017. key_file = g_key_file_new ();
  1018. g_key_file_load_from_data (key_file, contents, strlen(contents), G_KEY_FILE_NONE, NULL);
  1019. d_app_info = g_desktop_app_info_new_from_keyfile (key_file);
  1020. if (d_app_info != NULL) {
  1021. ctx = gdk_app_launch_context_new ();
  1022. gdk_app_launch_context_set_screen (ctx, gtk_widget_get_screen (window));
  1023. result = g_app_info_launch_uris (G_APP_INFO (d_app_info), list, G_APP_LAUNCH_CONTEXT (ctx), NULL);
  1024. }
  1025. else {
  1026. result = FALSE;
  1027. }
  1028. g_object_unref (g_app_info);
  1029. g_object_unref (d_app_info);
  1030. g_object_unref (g_file);
  1031. g_object_unref (ctx);
  1032. g_key_file_free (key_file);
  1033. g_list_free (list);
  1034. g_free (contents);
  1035. g_free (command);
  1036. g_free (uri);
  1037. return result;
  1038. }
  1039. gboolean
  1040. open_file_with_application (GtkWidget * window,
  1041. const gchar * file,
  1042. GAppInfo * app)
  1043. {
  1044. GdkAppLaunchContext * context;
  1045. GdkScreen * screen;
  1046. gboolean result;
  1047. if (g_file_test (file, G_FILE_TEST_IS_DIR) == TRUE) {
  1048. return FALSE;
  1049. }
  1050. context = gdk_app_launch_context_new ();
  1051. screen = gtk_widget_get_screen (window);
  1052. gdk_app_launch_context_set_screen (context, screen);
  1053. if (app == NULL) {
  1054. gchar * uri;
  1055. uri = g_filename_to_uri (file, NULL, NULL);
  1056. result = g_app_info_launch_default_for_uri (uri, (GAppLaunchContext *) context, NULL);
  1057. g_free (uri);
  1058. }
  1059. else {
  1060. GList * g_file_list = NULL;
  1061. GFile * g_file = NULL;
  1062. g_file = g_file_new_for_path (file);
  1063. if (g_file == NULL) {
  1064. result = FALSE;
  1065. }
  1066. else {
  1067. g_file_list = g_list_prepend (g_file_list, g_file);
  1068. result = g_app_info_launch (app, g_file_list, (GAppLaunchContext *) context, NULL);
  1069. g_list_free (g_file_list);
  1070. g_object_unref (g_file);
  1071. }
  1072. }
  1073. return result;
  1074. }
  1075. gboolean
  1076. launch_file (const gchar * file)
  1077. {
  1078. const char * content_type = g_content_type_guess (file, NULL, 0, NULL);
  1079. gboolean result = FALSE;
  1080. if ((g_file_test (file, G_FILE_TEST_IS_EXECUTABLE)) &&
  1081. (g_ascii_strcasecmp (content_type, BINARY_EXEC_MIME_TYPE) == 0)) {
  1082. result = g_spawn_command_line_async (file, NULL);
  1083. }
  1084. return result;
  1085. }
  1086. gchar *
  1087. gsearchtool_get_unique_filename (const gchar * path,
  1088. const gchar * suffix)
  1089. {
  1090. const gint num_of_words = 12;
  1091. gchar * words[] = {
  1092. "foo",
  1093. "bar",
  1094. "blah",
  1095. "cranston",
  1096. "frobate",
  1097. "hadjaha",
  1098. "greasy",
  1099. "hammer",
  1100. "eek",
  1101. "larry",
  1102. "curly",
  1103. "moe",
  1104. NULL};
  1105. gchar * retval = NULL;
  1106. gboolean exists = TRUE;
  1107. while (exists) {
  1108. gchar * file;
  1109. gint rnd;
  1110. gint word;
  1111. rnd = rand ();
  1112. word = rand () % num_of_words;
  1113. file = g_strdup_printf ("%s-%010x%s",
  1114. words [word],
  1115. (guint) rnd,
  1116. suffix);
  1117. g_free (retval);
  1118. retval = g_strconcat (path, G_DIR_SEPARATOR_S, file, NULL);
  1119. exists = g_file_test (retval, G_FILE_TEST_EXISTS);
  1120. g_free (file);
  1121. }
  1122. return retval;
  1123. }
  1124. GtkWidget *
  1125. gsearchtool_button_new_with_stock_icon (const gchar * string,
  1126. const gchar * stock_id)
  1127. {
  1128. GtkWidget * align;
  1129. GtkWidget * button;
  1130. GtkWidget * hbox;
  1131. GtkWidget * image;
  1132. GtkWidget * label;
  1133. button = gtk_button_new ();
  1134. label = gtk_label_new_with_mnemonic (string);
  1135. gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
  1136. image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
  1137. hbox = gtk_hbox_new (FALSE, 2);
  1138. align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  1139. gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
  1140. gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  1141. gtk_container_add (GTK_CONTAINER (button), align);
  1142. gtk_container_add (GTK_CONTAINER (align), hbox);
  1143. gtk_widget_show_all (align);
  1144. return button;
  1145. }
  1146. GSList *
  1147. gsearchtool_get_columns_order (GtkTreeView * treeview)
  1148. {
  1149. GSList *order = NULL;
  1150. GList * columns;
  1151. GList * col;
  1152. columns = gtk_tree_view_get_columns (treeview);
  1153. for (col = columns; col; col = col->next) {
  1154. gint id;
  1155. id = gtk_tree_view_column_get_sort_column_id (col->data);
  1156. order = g_slist_prepend (order, GINT_TO_POINTER (id));
  1157. }
  1158. g_list_free (columns);
  1159. order = g_slist_reverse (order);
  1160. return order;
  1161. }
  1162. GtkTreeViewColumn *
  1163. gsearchtool_gtk_tree_view_get_column_with_sort_column_id (GtkTreeView * treeview,
  1164. gint id)
  1165. {
  1166. GtkTreeViewColumn * col = NULL;
  1167. GList * columns;
  1168. GList * it;
  1169. columns = gtk_tree_view_get_columns (treeview);
  1170. for (it = columns; it; it = it->next) {
  1171. if (gtk_tree_view_column_get_sort_column_id (it->data) == id) {
  1172. col = it->data;
  1173. break;
  1174. }
  1175. }
  1176. g_list_free (columns);
  1177. return col;
  1178. }
  1179. void
  1180. gsearchtool_set_columns_order (GtkTreeView * treeview)
  1181. {
  1182. GtkTreeViewColumn * last = NULL;
  1183. GSList * order;
  1184. GSList * it;
  1185. order = gsearchtool_gconf_get_list ("/apps/gnome-search-tool/columns_order", GCONF_VALUE_INT);
  1186. for (it = order; it; it = it->next) {
  1187. GtkTreeViewColumn * cur;
  1188. gint id;
  1189. id = GPOINTER_TO_INT (it->data);
  1190. if (id >= 0 && id < NUM_COLUMNS) {
  1191. cur = gsearchtool_gtk_tree_view_get_column_with_sort_column_id (treeview, id);
  1192. if (cur && cur != last) {
  1193. gtk_tree_view_move_column_after (treeview, cur, last);
  1194. last = cur;
  1195. }
  1196. }
  1197. }
  1198. g_slist_free (order);
  1199. }
  1200. void
  1201. gsearchtool_get_stored_window_geometry (gint * width,
  1202. gint * height)
  1203. {
  1204. gint saved_width;
  1205. gint saved_height;
  1206. if (width == NULL || height == NULL) {
  1207. return;
  1208. }
  1209. saved_width = gsearchtool_gconf_get_int ("/apps/gnome-search-tool/default_window_width");
  1210. saved_height = gsearchtool_gconf_get_int ("/apps/gnome-search-tool/default_window_height");
  1211. if (saved_width == -1) {
  1212. saved_width = DEFAULT_WINDOW_WIDTH;
  1213. }
  1214. if (saved_height == -1) {
  1215. saved_height = DEFAULT_WINDOW_HEIGHT;
  1216. }
  1217. *width = MAX (saved_width, MINIMUM_WINDOW_WIDTH);
  1218. *height = MAX (saved_height, MINIMUM_WINDOW_HEIGHT);
  1219. }
  1220. /* START OF NAUTILUS/EEL FUNCTIONS: USED FOR HANDLING OF DUPLICATE FILENAMES */
  1221. /* Localizers:
  1222. * Feel free to leave out the st, nd, rd and th suffix or
  1223. * make some or all of them match.
  1224. */
  1225. /* localizers: tag used to detect the first copy of a file */
  1226. static const char untranslated_copy_duplicate_tag[] = N_(" (copy)");
  1227. /* localizers: tag used to detect the second copy of a file */
  1228. static const char untranslated_another_copy_duplicate_tag[] = N_(" (another copy)");
  1229. /* localizers: tag used to detect the x11th copy of a file */
  1230. static const char untranslated_x11th_copy_duplicate_tag[] = N_("th copy)");
  1231. /* localizers: tag used to detect the x12th copy of a file */
  1232. static const char untranslated_x12th_copy_duplicate_tag[] = N_("th copy)");
  1233. /* localizers: tag used to detect the x13th copy of a file */
  1234. static const char untranslated_x13th_copy_duplicate_tag[] = N_("th copy)");
  1235. /* localizers: tag used to detect the x1st copy of a file */
  1236. static const char untranslated_st_copy_duplicate_tag[] = N_("st copy)");
  1237. /* localizers: tag used to detect the x2nd copy of a file */
  1238. static const char untranslated_nd_copy_duplicate_tag[] = N_("nd copy)");
  1239. /* localizers: tag used to detect the x3rd copy of a file */
  1240. static const char untranslated_rd_copy_duplicate_tag[] = N_("rd copy)");
  1241. /* localizers: tag used to detect the xxth copy of a file */
  1242. static const char untranslated_th_copy_duplicate_tag[] = N_("th copy)");
  1243. #define COPY_DUPLICATE_TAG _(untranslated_copy_duplicate_tag)
  1244. #define ANOTHER_COPY_DUPLICATE_TAG _(untranslated_another_copy_duplicate_tag)
  1245. #define X11TH_COPY_DUPLICATE_TAG _(untranslated_x11th_copy_duplicate_tag)
  1246. #define X12TH_COPY_DUPLICATE_TAG _(untranslated_x12th_copy_duplicate_tag)
  1247. #define X13TH_COPY_DUPLICATE_TAG _(untranslated_x13th_copy_duplicate_tag)
  1248. #define ST_COPY_DUPLICATE_TAG _(untranslated_st_copy_duplicate_tag)
  1249. #define ND_COPY_DUPLICATE_TAG _(untranslated_nd_copy_duplicate_tag)
  1250. #define RD_COPY_DUPLICATE_TAG _(untranslated_rd_copy_duplicate_tag)
  1251. #define TH_COPY_DUPLICATE_TAG _(untranslated_th_copy_duplicate_tag)
  1252. /* localizers: appended to first file copy */
  1253. static const char untranslated_first_copy_duplicate_format[] = N_("%s (copy)%s");
  1254. /* localizers: appended to second file copy */
  1255. static const char untranslated_second_copy_duplicate_format[] = N_("%s (another copy)%s");
  1256. /* localizers: appended to x11th file copy */
  1257. static const char untranslated_x11th_copy_duplicate_format[] = N_("%s (%dth copy)%s");
  1258. /* localizers: appended to x12th file copy */
  1259. static const char untranslated_x12th_copy_duplicate_format[] = N_("%s (%dth copy)%s");
  1260. /* localizers: appended to x13th file copy */
  1261. static const char untranslated_x13th_copy_duplicate_format[] = N_("%s (%dth copy)%s");
  1262. /* localizers: appended to x1st file copy */
  1263. static const char untranslated_st_copy_duplicate_format[] = N_("%s (%dst copy)%s");
  1264. /* localizers: appended to x2nd file copy */
  1265. static const char untranslated_nd_copy_duplicate_format[] = N_("%s (%dnd copy)%s");
  1266. /* localizers: appended to x3rd file copy */
  1267. static const char untranslated_rd_copy_duplicate_format[] = N_("%s (%drd copy)%s");
  1268. /* localizers: appended to xxth file copy */
  1269. static const char untranslated_th_copy_duplicate_format[] = N_("%s (%dth copy)%s");
  1270. #define FIRST_COPY_DUPLICATE_FORMAT _(untranslated_first_copy_duplicate_format)
  1271. #define SECOND_COPY_DUPLICATE_FORMAT _(untranslated_second_copy_duplicate_format)
  1272. #define X11TH_COPY_DUPLICATE_FORMAT _(untranslated_x11th_copy_duplicate_format)
  1273. #define X12TH_COPY_DUPLICATE_FORMAT _(untranslated_x12th_copy_duplicate_format)
  1274. #define X13TH_COPY_DUPLICATE_FORMAT _(untranslated_x13th_copy_duplicate_format)
  1275. #define ST_COPY_DUPLICATE_FORMAT _(untranslated_st_copy_duplicate_format)
  1276. #define ND_COPY_DUPLICATE_FORMAT _(untranslated_nd_copy_duplicate_format)
  1277. #define RD_COPY_DUPLICATE_FORMAT _(untranslated_rd_copy_duplicate_format)
  1278. #define TH_COPY_DUPLICATE_FORMAT _(untranslated_th_copy_duplicate_format)
  1279. static gchar *
  1280. make_valid_utf8 (const gchar * name)
  1281. {
  1282. GString *string;
  1283. const char *remainder, *invalid;
  1284. int remaining_bytes, valid_bytes;
  1285. string = NULL;
  1286. remainder = name;
  1287. remaining_bytes = strlen (name);
  1288. while (remaining_bytes != 0) {
  1289. if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
  1290. break;
  1291. }
  1292. valid_bytes = invalid - remainder;
  1293. if (string == NULL) {
  1294. string = g_string_sized_new (remaining_bytes);
  1295. }
  1296. g_string_append_len (string, remainder, valid_bytes);
  1297. g_string_append_c (string, '?');
  1298. remaining_bytes -= valid_bytes + 1;
  1299. remainder = invalid + 1;
  1300. }
  1301. if (string == NULL) {
  1302. return g_strdup (name);
  1303. }
  1304. g_string_append (string, remainder);
  1305. g_string_append (string, _(" (invalid Unicode)"));
  1306. g_assert (g_utf8_validate (string->str, -1, NULL));
  1307. return g_string_free (string, FALSE);
  1308. }
  1309. static gchar *
  1310. extract_string_until (const gchar * original,
  1311. const gchar * until_substring)
  1312. {
  1313. gchar * result;
  1314. g_assert ((gint) strlen (original) >= until_substring - original);
  1315. g_assert (until_substring - original >= 0);
  1316. result = g_malloc (until_substring - original + 1);
  1317. strncpy (result, original, until_substring - original);
  1318. result[until_substring - original] = '\0';
  1319. return result;
  1320. }
  1321. /* Dismantle a file name, separating the base name, the file suffix and removing any
  1322. * (xxxcopy), etc. string. Figure out the count that corresponds to the given
  1323. * (xxxcopy) substring.
  1324. */
  1325. static void
  1326. parse_previous_duplicate_name (const gchar * name,
  1327. gchar ** name_base,
  1328. const gchar ** suffix,
  1329. gint * count)
  1330. {
  1331. const gchar * tag;
  1332. g_assert (name[0] != '\0');
  1333. *suffix = strchr (name + 1, '.');
  1334. if (*suffix == NULL || (*suffix)[1] == '\0') {
  1335. /* no suffix */
  1336. *suffix = "";
  1337. }
  1338. tag = strstr (name, COPY_DUPLICATE_TAG);
  1339. if (tag != NULL) {
  1340. if (tag > *suffix) {
  1341. /* handle case "foo. (copy)" */
  1342. *suffix = "";
  1343. }
  1344. *name_base = extract_string_until (name, tag);
  1345. *count = 1;
  1346. return;
  1347. }
  1348. tag = strstr (name, ANOTHER_COPY_DUPLICATE_TAG);
  1349. if (tag != NULL) {
  1350. if (tag > *suffix) {
  1351. /* handle case "foo. (another copy)" */
  1352. *suffix = "";
  1353. }
  1354. *name_base = extract_string_until (name, tag);
  1355. *count = 2;
  1356. return;
  1357. }
  1358. /* Check to see if we got one of st, nd, rd, th. */
  1359. tag = strstr (name, X11TH_COPY_DUPLICATE_TAG);
  1360. if (tag == NULL) {
  1361. tag = strstr (name, X12TH_COPY_DUPLICATE_TAG);
  1362. }
  1363. if (tag == NULL) {
  1364. tag = strstr (name, X13TH_COPY_DUPLICATE_TAG);
  1365. }
  1366. if (tag == NULL) {
  1367. tag = strstr (name, ST_COPY_DUPLICATE_TAG);
  1368. }
  1369. if (tag == NULL) {
  1370. tag = strstr (name, ND_COPY_DUPLICATE_TAG);
  1371. }
  1372. if (tag == NULL) {
  1373. tag = strstr (name, RD_COPY_DUPLICATE_TAG);
  1374. }
  1375. if (tag == NULL) {
  1376. tag = strstr (name, TH_COPY_DUPLICATE_TAG);
  1377. }
  1378. /* If we got one of st, nd, rd, th, fish out the duplicate number. */
  1379. if (tag != NULL) {
  1380. /* localizers: opening parentheses to match the "th copy)" string */
  1381. tag = strstr (name, _(" ("));
  1382. if (tag != NULL) {
  1383. if (tag > *suffix) {
  1384. /* handle case "foo. (22nd copy)" */
  1385. *suffix = "";
  1386. }
  1387. *name_base = extract_string_until (name, tag);
  1388. /* localizers: opening parentheses of the "th copy)" string */
  1389. if (sscanf (tag, _(" (%d"), count) == 1) {
  1390. if (*count < 1 || *count > 1000000) {
  1391. /* keep the count within a reasonable range */
  1392. *count = 0;
  1393. }
  1394. return;
  1395. }
  1396. *count = 0;
  1397. return;
  1398. }
  1399. }
  1400. *count = 0;
  1401. if (**suffix != '\0') {
  1402. *name_base = extract_string_until (name, *suffix);
  1403. } else {
  1404. *name_base = g_strdup (name);
  1405. }
  1406. }
  1407. static gchar *
  1408. make_next_duplicate_name (const gchar *base,
  1409. const gchar *suffix,
  1410. gint count)
  1411. {
  1412. const gchar * format;
  1413. gchar * result;
  1414. if (count < 1) {
  1415. g_warning ("bad count %d in make_next_duplicate_name()", count);
  1416. count = 1;
  1417. }
  1418. if (count <= 2) {
  1419. /* Handle special cases for low numbers.
  1420. * Perhaps for some locales we will need to add more.
  1421. */
  1422. switch (count) {
  1423. default:
  1424. g_assert_not_reached ();
  1425. /* fall through */
  1426. case 1:
  1427. format = FIRST_COPY_DUPLICATE_FORMAT;
  1428. break;
  1429. case 2:
  1430. format = SECOND_COPY_DUPLICATE_FORMAT;
  1431. break;
  1432. }
  1433. result = g_strdup_printf (format, base, suffix);
  1434. } else {
  1435. /* Handle special cases for the first few numbers of each ten.
  1436. * For locales where getting this exactly right is difficult,
  1437. * these can just be made all the same as the general case below.
  1438. */
  1439. /* Handle special cases for x11th - x20th.
  1440. */
  1441. switch (count % 100) {
  1442. case 11:
  1443. format = X11TH_COPY_DUPLICATE_FORMAT;
  1444. break;
  1445. case 12:
  1446. format = X12TH_COPY_DUPLICATE_FORMAT;
  1447. break;
  1448. case 13:
  1449. format = X13TH_COPY_DUPLICATE_FORMAT;
  1450. break;
  1451. default:
  1452. format = NULL;
  1453. break;
  1454. }
  1455. if (format == NULL) {
  1456. switch (count % 10) {
  1457. case 1:
  1458. format = ST_COPY_DUPLICATE_FORMAT;
  1459. break;
  1460. case 2:
  1461. format = ND_COPY_DUPLICATE_FORMAT;
  1462. break;
  1463. case 3:
  1464. format = RD_COPY_DUPLICATE_FORMAT;
  1465. break;
  1466. default:
  1467. /* The general case. */
  1468. format = TH_COPY_DUPLICATE_FORMAT;
  1469. break;
  1470. }
  1471. }
  1472. result = g_strdup_printf (format, base, count, suffix);
  1473. }
  1474. return result;
  1475. }
  1476. static gchar *
  1477. get_duplicate_name (const gchar *name)
  1478. {
  1479. const gchar * suffix;
  1480. gchar * name_base;
  1481. gchar * result;
  1482. gint count;
  1483. parse_previous_duplicate_name (name, &name_base, &suffix, &count);
  1484. result = make_next_duplicate_name (name_base, suffix, count + 1);
  1485. g_free (name_base);
  1486. return result;
  1487. }
  1488. gchar *
  1489. gsearchtool_get_next_duplicate_name (const gchar * basename)
  1490. {
  1491. gchar * utf8_name;
  1492. gchar * utf8_result;
  1493. gchar * result;
  1494. utf8_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
  1495. if (utf8_name == NULL) {
  1496. /* Couldn't convert to utf8 - probably
  1497. * G_BROKEN_FILENAMES not set when it should be.
  1498. * Try converting from the locale */
  1499. utf8_name = g_locale_to_utf8 (basename, -1, NULL, NULL, NULL);
  1500. if (utf8_name == NULL) {
  1501. utf8_name = make_valid_utf8 (basename);
  1502. }
  1503. }
  1504. utf8_result = get_duplicate_name (utf8_name);
  1505. g_free (utf8_name);
  1506. result = g_filename_from_utf8 (utf8_result, -1, NULL, NULL, NULL);
  1507. g_free (utf8_result);
  1508. return result;
  1509. }