]> Pileus Git - ~andy/gtk/blob - gtk/gtksearchenginesimple.c
GtkToolPalette: Change gtk_tool_palette_get_drop_group() return.
[~andy/gtk] / gtk / gtksearchenginesimple.c
1 /*
2  * Copyright (C) 2005 Red Hat, Inc
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  *
18  * Author: Alexander Larsson <alexl@redhat.com>
19  *
20  * Based on nautilus-search-engine-simple.c
21  */
22
23 #include "config.h"
24
25 /* these must be defined even when HAVE_GNU_FTW is not defined
26  * because (really) old versions of GNU libc have ftw.h but do
27  * export ftw() and friends only if _XOPEN_SOURCE and _GNU_SOURCE
28  * are defined. see bug #444097.
29  */
30 #define _XOPEN_SOURCE 500
31 #define _GNU_SOURCE 
32
33 #ifdef HAVE_FTW_H
34 #include <ftw.h>
35 #endif
36
37 #include "gtksearchenginesimple.h"
38 #include "gtkprivate.h"
39
40 #include <string.h>
41
42 #define BATCH_SIZE 500
43
44 typedef struct 
45 {
46   GtkSearchEngineSimple *engine;
47   
48   gchar *path;
49   gchar **words;
50   GList *found_list;
51   
52   gint n_processed_files;
53   GList *uri_hits;
54   
55   /* accessed on both threads: */
56   volatile gboolean cancelled;
57 } SearchThreadData;
58
59
60 struct _GtkSearchEngineSimplePrivate 
61 {
62   GtkQuery *query;
63   
64   SearchThreadData *active_search;
65   
66   gboolean query_finished;
67 };
68
69
70 G_DEFINE_TYPE (GtkSearchEngineSimple, _gtk_search_engine_simple, GTK_TYPE_SEARCH_ENGINE);
71
72 static void
73 gtk_search_engine_simple_dispose (GObject *object)
74 {
75   GtkSearchEngineSimple *simple;
76   GtkSearchEngineSimplePrivate *priv;
77   
78   simple = GTK_SEARCH_ENGINE_SIMPLE (object);
79   priv = simple->priv;
80   
81   if (priv->query) 
82     {
83       g_object_unref (priv->query);
84       priv->query = NULL;
85     }
86
87   if (priv->active_search)
88     {
89       priv->active_search->cancelled = TRUE;
90       priv->active_search = NULL;
91     }
92   
93   G_OBJECT_CLASS (_gtk_search_engine_simple_parent_class)->dispose (object);
94 }
95
96 static SearchThreadData *
97 search_thread_data_new (GtkSearchEngineSimple *engine,
98                         GtkQuery              *query)
99 {
100   SearchThreadData *data;
101   char *text, *lower, *uri;
102   
103   data = g_new0 (SearchThreadData, 1);
104   
105   data->engine = g_object_ref (engine);
106   uri = _gtk_query_get_location (query);
107   if (uri != NULL) 
108     {
109       data->path = g_filename_from_uri (uri, NULL, NULL);
110       g_free (uri);
111     }
112   if (data->path == NULL)
113     data->path = g_strdup (g_get_home_dir ());
114         
115   text = _gtk_query_get_text (query);
116   lower = g_ascii_strdown (text, -1);
117   data->words = g_strsplit (lower, " ", -1);
118   g_free (text);
119   g_free (lower);
120   
121   return data;
122 }
123
124 static void 
125 search_thread_data_free (SearchThreadData *data)
126 {
127   g_object_unref (data->engine);
128   g_free (data->path);
129   g_strfreev (data->words);
130   g_free (data);
131 }
132
133 static gboolean
134 search_thread_done_idle (gpointer user_data)
135 {
136   SearchThreadData *data;
137
138   data = user_data;
139   
140   if (!data->cancelled)
141     _gtk_search_engine_finished (GTK_SEARCH_ENGINE (data->engine));
142      
143   data->engine->priv->active_search = NULL;
144   search_thread_data_free (data);
145   
146   return FALSE;
147 }
148
149 typedef struct 
150 {
151   GList *uris;
152   SearchThreadData *thread_data;
153 } SearchHits;
154
155
156 static gboolean
157 search_thread_add_hits_idle (gpointer user_data)
158 {
159   SearchHits *hits;
160
161   hits = user_data;
162
163   if (!hits->thread_data->cancelled) 
164     {
165       _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (hits->thread_data->engine),
166                                     hits->uris);
167     }
168
169   g_list_foreach (hits->uris, (GFunc)g_free, NULL);
170   g_list_free (hits->uris);
171   g_free (hits);
172         
173   return FALSE;
174 }
175
176 static void
177 send_batch (SearchThreadData *data)
178 {
179   SearchHits *hits;
180   
181   data->n_processed_files = 0;
182   
183   if (data->uri_hits) 
184     {
185       hits = g_new (SearchHits, 1);
186       hits->uris = data->uri_hits;
187       hits->thread_data = data;
188       
189       gdk_threads_add_idle (search_thread_add_hits_idle, hits);
190     }
191   data->uri_hits = NULL;
192 }
193
194 static GStaticPrivate search_thread_data = G_STATIC_PRIVATE_INIT;
195
196 #ifdef HAVE_FTW_H
197 static int
198 search_visit_func (const char        *fpath,
199                    const struct stat *sb,
200                    int                typeflag,
201                    struct FTW        *ftwbuf)
202 {
203   SearchThreadData *data;
204   gint i;
205   const gchar *name; 
206   gchar *lower_name;
207   gchar *uri;
208   gboolean hit;
209   gboolean is_hidden;
210   
211   data = (SearchThreadData*)g_static_private_get (&search_thread_data);
212
213   if (data->cancelled)
214 #ifdef HAVE_GNU_FTW
215     return FTW_STOP;
216 #else
217     return 1;
218 #endif /* HAVE_GNU_FTW */
219
220   name = strrchr (fpath, '/');
221   if (name)
222     name++;
223   else
224     name = fpath;
225
226   is_hidden = *name == '.';
227         
228   hit = FALSE;
229   
230   if (!is_hidden) 
231     {
232       lower_name = g_ascii_strdown (name, -1);
233       
234       hit = TRUE;
235       for (i = 0; data->words[i] != NULL; i++) 
236         {
237           if (strstr (lower_name, data->words[i]) == NULL) 
238             {
239               hit = FALSE;
240               break;
241             }
242         }
243       g_free (lower_name);
244     }
245
246   if (hit) 
247     {
248       uri = g_filename_to_uri (fpath, NULL, NULL);
249       data->uri_hits = g_list_prepend (data->uri_hits, uri);
250     }
251
252   data->n_processed_files++;
253   
254   if (data->n_processed_files > BATCH_SIZE)
255     send_batch (data);
256
257 #ifdef HAVE_GNU_FTW
258   if (is_hidden)
259     return FTW_SKIP_SUBTREE;
260   else
261     return FTW_CONTINUE;
262 #else
263   return 0;
264 #endif /* HAVE_GNU_FTW */
265 }
266 #endif /* HAVE_FTW_H */
267
268 static gpointer 
269 search_thread_func (gpointer user_data)
270 {
271 #ifdef HAVE_FTW_H
272   SearchThreadData *data;
273   
274   data = user_data;
275   
276   g_static_private_set (&search_thread_data, data, NULL);
277
278   nftw (data->path, search_visit_func, 20,
279 #ifdef HAVE_GNU_FTW
280         FTW_ACTIONRETVAL |
281 #endif
282         FTW_PHYS);
283
284   send_batch (data);
285   
286   gdk_threads_add_idle (search_thread_done_idle, data);
287 #endif /* HAVE_FTW_H */
288   
289   return NULL;
290 }
291
292 static void
293 gtk_search_engine_simple_start (GtkSearchEngine *engine)
294 {
295   GtkSearchEngineSimple *simple;
296   SearchThreadData *data;
297   
298   simple = GTK_SEARCH_ENGINE_SIMPLE (engine);
299   
300   if (simple->priv->active_search != NULL)
301     return;
302   
303   if (simple->priv->query == NULL)
304     return;
305         
306   data = search_thread_data_new (simple, simple->priv->query);
307   
308   g_thread_create (search_thread_func, data, FALSE, NULL);
309   
310   simple->priv->active_search = data;
311 }
312
313 static void
314 gtk_search_engine_simple_stop (GtkSearchEngine *engine)
315 {
316   GtkSearchEngineSimple *simple;
317   
318   simple = GTK_SEARCH_ENGINE_SIMPLE (engine);
319   
320   if (simple->priv->active_search != NULL) 
321     {
322       simple->priv->active_search->cancelled = TRUE;
323       simple->priv->active_search = NULL;
324     }
325 }
326
327 static gboolean
328 gtk_search_engine_simple_is_indexed (GtkSearchEngine *engine)
329 {
330   return FALSE;
331 }
332
333 static void
334 gtk_search_engine_simple_set_query (GtkSearchEngine *engine, 
335                                     GtkQuery        *query)
336 {
337   GtkSearchEngineSimple *simple;
338   
339   simple = GTK_SEARCH_ENGINE_SIMPLE (engine);
340   
341   if (query)
342     g_object_ref (query);
343
344   if (simple->priv->query) 
345     g_object_unref (simple->priv->query);
346
347   simple->priv->query = query;
348 }
349
350 static void
351 _gtk_search_engine_simple_class_init (GtkSearchEngineSimpleClass *class)
352 {
353   GObjectClass *gobject_class;
354   GtkSearchEngineClass *engine_class;
355   
356   gobject_class = G_OBJECT_CLASS (class);
357   gobject_class->dispose = gtk_search_engine_simple_dispose;
358   
359   engine_class = GTK_SEARCH_ENGINE_CLASS (class);
360   engine_class->set_query = gtk_search_engine_simple_set_query;
361   engine_class->start = gtk_search_engine_simple_start;
362   engine_class->stop = gtk_search_engine_simple_stop;
363   engine_class->is_indexed = gtk_search_engine_simple_is_indexed;
364
365   g_type_class_add_private (gobject_class, sizeof (GtkSearchEngineSimplePrivate));
366 }
367
368 static void
369 _gtk_search_engine_simple_init (GtkSearchEngineSimple *engine)
370 {
371   engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, GTK_TYPE_SEARCH_ENGINE_SIMPLE, GtkSearchEngineSimplePrivate);
372 }
373
374 GtkSearchEngine *
375 _gtk_search_engine_simple_new (void)
376 {
377 #ifdef HAVE_FTW_H
378   return g_object_new (GTK_TYPE_SEARCH_ENGINE_SIMPLE, NULL);
379 #else
380   return NULL;
381 #endif
382 }