]> Pileus Git - ~andy/gtk/blob - gtk/gtksearchenginesimple.c
Updated galician translations
[~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 <gdk/gdk.h>
38
39 #include "gtksearchenginesimple.h"
40 #include "gtkprivate.h"
41
42 #include <string.h>
43
44 #define BATCH_SIZE 500
45
46 typedef struct 
47 {
48   GtkSearchEngineSimple *engine;
49   
50   gchar *path;
51   gchar **words;
52   GList *found_list;
53   
54   gint n_processed_files;
55   GList *uri_hits;
56   
57   /* accessed on both threads: */
58   volatile gboolean cancelled;
59 } SearchThreadData;
60
61
62 struct _GtkSearchEngineSimplePrivate 
63 {
64   GtkQuery *query;
65   
66   SearchThreadData *active_search;
67   
68   gboolean query_finished;
69 };
70
71
72 G_DEFINE_TYPE (GtkSearchEngineSimple, _gtk_search_engine_simple, GTK_TYPE_SEARCH_ENGINE);
73
74 static void
75 gtk_search_engine_simple_dispose (GObject *object)
76 {
77   GtkSearchEngineSimple *simple;
78   GtkSearchEngineSimplePrivate *priv;
79   
80   simple = GTK_SEARCH_ENGINE_SIMPLE (object);
81   priv = simple->priv;
82   
83   if (priv->query) 
84     {
85       g_object_unref (priv->query);
86       priv->query = NULL;
87     }
88
89   if (priv->active_search)
90     {
91       priv->active_search->cancelled = TRUE;
92       priv->active_search = NULL;
93     }
94   
95   G_OBJECT_CLASS (_gtk_search_engine_simple_parent_class)->dispose (object);
96 }
97
98 static SearchThreadData *
99 search_thread_data_new (GtkSearchEngineSimple *engine,
100                         GtkQuery              *query)
101 {
102   SearchThreadData *data;
103   char *text, *lower, *uri;
104   
105   data = g_new0 (SearchThreadData, 1);
106   
107   data->engine = g_object_ref (engine);
108   uri = _gtk_query_get_location (query);
109   if (uri != NULL) 
110     {
111       data->path = g_filename_from_uri (uri, NULL, NULL);
112       g_free (uri);
113     }
114   if (data->path == NULL)
115     data->path = g_strdup (g_get_home_dir ());
116         
117   text = _gtk_query_get_text (query);
118   lower = g_ascii_strdown (text, -1);
119   data->words = g_strsplit (lower, " ", -1);
120   g_free (text);
121   g_free (lower);
122   
123   return data;
124 }
125
126 static void 
127 search_thread_data_free (SearchThreadData *data)
128 {
129   g_object_unref (data->engine);
130   g_free (data->path);
131   g_strfreev (data->words);
132   g_free (data);
133 }
134
135 static gboolean
136 search_thread_done_idle (gpointer user_data)
137 {
138   SearchThreadData *data;
139
140   data = user_data;
141   
142   if (!data->cancelled)
143     _gtk_search_engine_finished (GTK_SEARCH_ENGINE (data->engine));
144      
145   data->engine->priv->active_search = NULL;
146   search_thread_data_free (data);
147   
148   return FALSE;
149 }
150
151 typedef struct 
152 {
153   GList *uris;
154   SearchThreadData *thread_data;
155 } SearchHits;
156
157
158 static gboolean
159 search_thread_add_hits_idle (gpointer user_data)
160 {
161   SearchHits *hits;
162
163   hits = user_data;
164
165   if (!hits->thread_data->cancelled) 
166     {
167       _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (hits->thread_data->engine),
168                                     hits->uris);
169     }
170
171   g_list_foreach (hits->uris, (GFunc)g_free, NULL);
172   g_list_free (hits->uris);
173   g_free (hits);
174         
175   return FALSE;
176 }
177
178 static void
179 send_batch (SearchThreadData *data)
180 {
181   SearchHits *hits;
182   
183   data->n_processed_files = 0;
184   
185   if (data->uri_hits) 
186     {
187       hits = g_new (SearchHits, 1);
188       hits->uris = data->uri_hits;
189       hits->thread_data = data;
190       
191       gdk_threads_add_idle (search_thread_add_hits_idle, hits);
192     }
193
194   data->uri_hits = NULL;
195 }
196
197 static GStaticPrivate search_thread_data = G_STATIC_PRIVATE_INIT;
198
199 #ifdef HAVE_FTW_H
200 static int
201 search_visit_func (const char        *fpath,
202                    const struct stat *sb,
203                    int                typeflag,
204                    struct FTW        *ftwbuf)
205 {
206   SearchThreadData *data;
207   gint i;
208   const gchar *name; 
209   gchar *lower_name;
210   gchar *uri;
211   gboolean hit;
212   gboolean is_hidden;
213   
214   data = (SearchThreadData*)g_static_private_get (&search_thread_data);
215
216   if (data->cancelled)
217 #ifdef HAVE_GNU_FTW
218     return FTW_STOP;
219 #else
220     return 1;
221 #endif /* HAVE_GNU_FTW */
222
223   name = strrchr (fpath, '/');
224   if (name)
225     name++;
226   else
227     name = fpath;
228
229   is_hidden = *name == '.';
230         
231   hit = FALSE;
232   
233   if (!is_hidden) 
234     {
235       lower_name = g_ascii_strdown (name, -1);
236       
237       hit = TRUE;
238       for (i = 0; data->words[i] != NULL; i++) 
239         {
240           if (strstr (lower_name, data->words[i]) == NULL) 
241             {
242               hit = FALSE;
243               break;
244             }
245         }
246       g_free (lower_name);
247     }
248
249   if (hit) 
250     {
251       uri = g_filename_to_uri (fpath, NULL, NULL);
252       data->uri_hits = g_list_prepend (data->uri_hits, uri);
253     }
254
255   data->n_processed_files++;
256   
257   if (data->n_processed_files > BATCH_SIZE)
258     send_batch (data);
259
260 #ifdef HAVE_GNU_FTW
261   if (is_hidden)
262     return FTW_SKIP_SUBTREE;
263   else
264     return FTW_CONTINUE;
265 #else
266   return 0;
267 #endif /* HAVE_GNU_FTW */
268 }
269 #endif /* HAVE_FTW_H */
270
271 static gpointer 
272 search_thread_func (gpointer user_data)
273 {
274 #ifdef HAVE_FTW_H
275   SearchThreadData *data;
276   
277   data = user_data;
278   
279   g_static_private_set (&search_thread_data, data, NULL);
280
281   nftw (data->path, search_visit_func, 20,
282 #ifdef HAVE_GNU_FTW
283         FTW_ACTIONRETVAL |
284 #endif
285         FTW_PHYS);
286
287   send_batch (data);
288   
289   gdk_threads_add_idle (search_thread_done_idle, data);
290 #endif /* HAVE_FTW_H */
291   
292   return NULL;
293 }
294
295 static void
296 gtk_search_engine_simple_start (GtkSearchEngine *engine)
297 {
298   GtkSearchEngineSimple *simple;
299   SearchThreadData *data;
300   
301   simple = GTK_SEARCH_ENGINE_SIMPLE (engine);
302   
303   if (simple->priv->active_search != NULL)
304     return;
305   
306   if (simple->priv->query == NULL)
307     return;
308         
309   data = search_thread_data_new (simple, simple->priv->query);
310   
311   g_thread_create (search_thread_func, data, FALSE, NULL);
312   
313   simple->priv->active_search = data;
314 }
315
316 static void
317 gtk_search_engine_simple_stop (GtkSearchEngine *engine)
318 {
319   GtkSearchEngineSimple *simple;
320   
321   simple = GTK_SEARCH_ENGINE_SIMPLE (engine);
322   
323   if (simple->priv->active_search != NULL) 
324     {
325       simple->priv->active_search->cancelled = TRUE;
326       simple->priv->active_search = NULL;
327     }
328 }
329
330 static gboolean
331 gtk_search_engine_simple_is_indexed (GtkSearchEngine *engine)
332 {
333   return FALSE;
334 }
335
336 static void
337 gtk_search_engine_simple_set_query (GtkSearchEngine *engine, 
338                                     GtkQuery        *query)
339 {
340   GtkSearchEngineSimple *simple;
341   
342   simple = GTK_SEARCH_ENGINE_SIMPLE (engine);
343   
344   if (query)
345     g_object_ref (query);
346
347   if (simple->priv->query) 
348     g_object_unref (simple->priv->query);
349
350   simple->priv->query = query;
351 }
352
353 static void
354 _gtk_search_engine_simple_class_init (GtkSearchEngineSimpleClass *class)
355 {
356   GObjectClass *gobject_class;
357   GtkSearchEngineClass *engine_class;
358   
359   gobject_class = G_OBJECT_CLASS (class);
360   gobject_class->dispose = gtk_search_engine_simple_dispose;
361   
362   engine_class = GTK_SEARCH_ENGINE_CLASS (class);
363   engine_class->set_query = gtk_search_engine_simple_set_query;
364   engine_class->start = gtk_search_engine_simple_start;
365   engine_class->stop = gtk_search_engine_simple_stop;
366   engine_class->is_indexed = gtk_search_engine_simple_is_indexed;
367
368   g_type_class_add_private (gobject_class, sizeof (GtkSearchEngineSimplePrivate));
369 }
370
371 static void
372 _gtk_search_engine_simple_init (GtkSearchEngineSimple *engine)
373 {
374   engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, GTK_TYPE_SEARCH_ENGINE_SIMPLE, GtkSearchEngineSimplePrivate);
375 }
376
377 GtkSearchEngine *
378 _gtk_search_engine_simple_new (void)
379 {
380 #ifdef HAVE_FTW_H
381   return g_object_new (GTK_TYPE_SEARCH_ENGINE_SIMPLE, NULL);
382 #else
383   return NULL;
384 #endif
385 }