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