]> Pileus Git - ~andy/gtk/blob - gtk/gtksearchenginebeagle.c
gdk/x11: Add gdk_x11_device_manager_lookup()
[~andy/gtk] / gtk / gtksearchenginebeagle.c
1 /*
2  * Copyright (C) 2005 Novell, 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: Anders Carlsson <andersca@imendio.com>
19  *
20  * Based on nautilus-search-engine-beagle.c
21  */
22
23 #include "config.h"
24 #include <gmodule.h>
25 #include "gtksearchenginebeagle.h"
26
27 #if 0
28 #include <beagle/beagle.h>
29 #endif
30
31 /* We dlopen() all the following from libbeagle at runtime */
32
33 typedef struct _BeagleHit BeagleHit;
34 typedef struct _BeagleQuery BeagleQuery;
35 typedef struct _BeagleClient BeagleClient;
36 typedef struct _BeagleRequest BeagleRequest;
37 typedef struct _BeagleFinishedResponse BeagleFinishedResponse;
38 typedef struct _BeagleHitsAddedResponse BeagleHitsAddedResponse;
39 typedef struct _BeagleHitsSubtractedResponse BeagleHitsSubtractedResponse;
40 typedef struct _BeagleQueryPartProperty BeagleQueryPartProperty;
41 typedef struct _BeagleQueryPart BeagleQueryPart;
42
43 #define BEAGLE_HIT(x) ((BeagleHit *)(x))
44 #define BEAGLE_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), beagle_request_get_type(), BeagleRequest))
45 #define BEAGLE_QUERY_PART(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), beagle_query_part_get_type(), BeagleQueryPart))
46
47 typedef enum 
48 {
49   BEAGLE_QUERY_PART_LOGIC_REQUIRED   = 1,
50   BEAGLE_QUERY_PART_LOGIC_PROHIBITED = 2
51 } BeagleQueryPartLogic;
52
53 typedef enum 
54   {
55     BEAGLE_PROPERTY_TYPE_UNKNOWN = 0,
56     BEAGLE_PROPERTY_TYPE_TEXT    = 1,
57     BEAGLE_PROPERTY_TYPE_KEYWORD = 2,
58     BEAGLE_PROPERTY_TYPE_DATE    = 3,
59     BEAGLE_PROPERTY_TYPE_LAST    = 4
60 } BeaglePropertyType;
61
62 /* *static* wrapper function pointers */
63 static gboolean (*beagle_client_send_request_async) (BeagleClient   *client,
64                                                      BeagleRequest  *request,
65                                                      GError        **err) = NULL;
66 static const char *(*beagle_hit_get_uri) (BeagleHit *hit) = NULL;
67 static GSList *(*beagle_hits_added_response_get_hits) (BeagleHitsAddedResponse *response) = NULL;
68 static GSList *(*beagle_hits_subtracted_response_get_uris) (BeagleHitsSubtractedResponse *response) = NULL;
69 static BeagleQuery *(*beagle_query_new) (void) = NULL;
70 static void (*beagle_query_add_text) (BeagleQuery     *query,
71                                       const char      *str) = NULL;
72 static void (*beagle_query_set_max_hits) (BeagleQuery *query,
73                                           gint         max_hits) = NULL;
74 static BeagleQueryPartProperty *(*beagle_query_part_property_new) (void) = NULL;
75 static void (*beagle_query_part_set_logic) (BeagleQueryPart      *part, 
76                                             BeagleQueryPartLogic  logic) = NULL;
77 static void (*beagle_query_part_property_set_key) (BeagleQueryPartProperty *part, 
78                                                    const char              *key) = NULL;
79 static void (*beagle_query_part_property_set_value) (BeagleQueryPartProperty *part, 
80                                                      const char *             value) = NULL;
81 static void (*beagle_query_part_property_set_property_type) (BeagleQueryPartProperty *part, 
82                                                              BeaglePropertyType       prop_type) = NULL;
83 static void (*beagle_query_add_part) (BeagleQuery     *query, 
84                                       BeagleQueryPart *part) = NULL;
85 static GType (*beagle_request_get_type) (void) = NULL;
86 static GType (*beagle_query_part_get_type) (void) = NULL;
87 static gboolean (*beagle_util_daemon_is_running) (void) = NULL;
88 static BeagleClient *(*beagle_client_new) (const char *client_name) = NULL;
89
90 static struct BeagleDlMapping
91 {
92   const char *fn_name;
93   gpointer *fn_ptr_ref;
94 } beagle_dl_mapping[] =
95 {
96 #define MAP(a) { #a, (gpointer *)&a }
97   MAP (beagle_client_send_request_async),
98   MAP (beagle_hit_get_uri),
99   MAP (beagle_hits_added_response_get_hits),
100   MAP (beagle_hits_subtracted_response_get_uris),
101   MAP (beagle_query_new),
102   MAP (beagle_query_add_text),
103   MAP (beagle_query_set_max_hits),
104   MAP (beagle_query_part_property_new),
105   MAP (beagle_query_part_set_logic),
106   MAP (beagle_query_part_property_set_key),
107   MAP (beagle_query_part_property_set_value),
108   MAP (beagle_query_part_property_set_property_type),
109   MAP (beagle_query_add_part),
110   MAP (beagle_request_get_type),
111   MAP (beagle_query_part_get_type),
112   MAP (beagle_util_daemon_is_running),
113   MAP (beagle_client_new)
114 #undef MAP
115 };
116
117 static void 
118 open_libbeagle (void)
119 {
120   static gboolean done = FALSE;
121
122   if (!done)
123     {
124       int i;
125       GModule *beagle;
126       
127       done = TRUE;
128  
129       beagle = g_module_open ("libbeagle.so.1", G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
130       if (!beagle)
131         beagle = g_module_open ("libbeagle.so.0", G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
132
133       if (!beagle)
134         return;
135       
136       for (i = 0; i < G_N_ELEMENTS (beagle_dl_mapping); i++)
137         {
138           if (!g_module_symbol (beagle, beagle_dl_mapping[i].fn_name,
139                                 beagle_dl_mapping[i].fn_ptr_ref))
140             {
141               g_warning ("Missing symbol '%s' in libbeagle\n",
142                          beagle_dl_mapping[i].fn_name);
143               g_module_close (beagle);
144
145               for (i = 0; i < G_N_ELEMENTS (beagle_dl_mapping); i++)
146                 beagle_dl_mapping[i].fn_ptr_ref = NULL;
147
148               return;
149             }
150         }
151     }
152 }
153
154
155 struct _GtkSearchEngineBeaglePrivate 
156 {
157   BeagleClient *client;
158   GtkQuery *query;
159
160   BeagleQuery *current_query;
161   char *current_query_uri_prefix;
162   gboolean query_finished;
163 };
164
165
166 G_DEFINE_TYPE (GtkSearchEngineBeagle, _gtk_search_engine_beagle, GTK_TYPE_SEARCH_ENGINE);
167
168 static void
169 finalize (GObject *object)
170 {
171   GtkSearchEngineBeagle *beagle;
172   
173   beagle = GTK_SEARCH_ENGINE_BEAGLE (object);
174   
175   if (beagle->priv->current_query) 
176     {
177       g_object_unref (beagle->priv->current_query);
178       beagle->priv->current_query = NULL;
179       g_free (beagle->priv->current_query_uri_prefix);
180       beagle->priv->current_query_uri_prefix = NULL;
181     }
182
183   if (beagle->priv->query) 
184     {
185       g_object_unref (beagle->priv->query);
186       beagle->priv->query = NULL;
187     }
188
189   if (beagle->priv->client) 
190     {
191       g_object_unref (beagle->priv->client);
192       beagle->priv->client = NULL;
193     }
194
195   G_OBJECT_CLASS (_gtk_search_engine_beagle_parent_class)->finalize (object);
196 }
197
198 static void
199 beagle_hits_added (BeagleQuery             *query, 
200                    BeagleHitsAddedResponse *response, 
201                    GtkSearchEngineBeagle   *engine)
202 {
203   GSList *hits, *list;
204   GList *hit_uris;
205   const gchar *uri;
206   
207   hit_uris = NULL;
208   
209   hits = beagle_hits_added_response_get_hits (response);
210   
211   for (list = hits; list != NULL; list = list->next) 
212     {
213       BeagleHit *hit = BEAGLE_HIT (list->data);
214       
215       uri = beagle_hit_get_uri (hit);
216       
217       if (engine->priv->current_query_uri_prefix &&
218           !g_str_has_prefix (uri, engine->priv->current_query_uri_prefix)) 
219         continue;
220                 
221       hit_uris = g_list_prepend (hit_uris, (char *)uri);
222     }
223
224   _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (engine), hit_uris);
225   g_list_free (hit_uris);
226 }
227
228 static void
229 beagle_hits_subtracted (BeagleQuery                  *query, 
230                         BeagleHitsSubtractedResponse *response, 
231                         GtkSearchEngineBeagle        *engine)
232 {
233   GSList *uris, *list;
234   GList *hit_uris;
235   
236   hit_uris = NULL;
237   
238   uris = beagle_hits_subtracted_response_get_uris (response);
239   
240   for (list = uris; list != NULL; list = list->next) 
241     {
242       hit_uris = g_list_prepend (hit_uris, (char *)list->data);
243     }
244
245   _gtk_search_engine_hits_subtracted (GTK_SEARCH_ENGINE (engine), hit_uris);
246   g_list_free (hit_uris);
247 }
248
249 static void
250 beagle_finished (BeagleQuery            *query, 
251                  BeagleFinishedResponse *response,
252                  GtkSearchEngineBeagle  *engine)
253 {
254   /* For some reason we keep getting finished events,
255    * only emit finished once */
256   if (engine->priv->query_finished) 
257     return;
258   
259   engine->priv->query_finished = TRUE;
260   _gtk_search_engine_finished (GTK_SEARCH_ENGINE (engine));
261 }
262
263 static void
264 beagle_error (BeagleQuery           *query,
265               GError                *error,
266               GtkSearchEngineBeagle *engine)
267 {
268   _gtk_search_engine_error (GTK_SEARCH_ENGINE (engine), error->message);
269 }
270
271 static void
272 gtk_search_engine_beagle_start (GtkSearchEngine *engine)
273 {
274   GtkSearchEngineBeagle *beagle;
275   GError *error;
276   gchar *text;
277   gchar *query;
278
279   error = NULL;
280   beagle = GTK_SEARCH_ENGINE_BEAGLE (engine);
281   
282   g_return_if_fail (beagle->priv->query != NULL);
283
284   if (beagle->priv->current_query)
285     return;
286
287   beagle->priv->query_finished = FALSE;
288   beagle->priv->current_query = beagle_query_new ();
289   g_signal_connect (beagle->priv->current_query,
290                     "hits-added", G_CALLBACK (beagle_hits_added), engine);
291   g_signal_connect (beagle->priv->current_query,
292                     "hits-subtracted", G_CALLBACK (beagle_hits_subtracted), engine);
293   g_signal_connect (beagle->priv->current_query,
294                     "finished", G_CALLBACK (beagle_finished), engine);
295   g_signal_connect (beagle->priv->current_query,
296                     "error", G_CALLBACK (beagle_error), engine);
297   
298   /* We only want files */
299   
300  
301   text = _gtk_query_get_text (beagle->priv->query);
302   query = g_strconcat (text, " type:File", NULL);
303                           
304   beagle_query_set_max_hits (beagle->priv->current_query, 1000);
305   beagle_query_add_text (beagle->priv->current_query, query);
306   
307   beagle->priv->current_query_uri_prefix = _gtk_query_get_location (beagle->priv->query);
308   
309   if (!beagle_client_send_request_async (beagle->priv->client,
310                                          BEAGLE_REQUEST (beagle->priv->current_query), &error)) 
311     {
312       _gtk_search_engine_error (engine, error->message);
313       g_error_free (error);
314     }
315
316   /* These must live during the lifetime of the query */
317   g_free (text);
318   g_free (query);
319 }
320
321 static void
322 gtk_search_engine_beagle_stop (GtkSearchEngine *engine)
323 {
324   GtkSearchEngineBeagle *beagle;
325   
326   beagle = GTK_SEARCH_ENGINE_BEAGLE (engine);
327   
328   if (beagle->priv->current_query) 
329     {
330       g_object_unref (beagle->priv->current_query);
331       beagle->priv->current_query = NULL;
332
333       g_free (beagle->priv->current_query_uri_prefix);
334       beagle->priv->current_query_uri_prefix = NULL;
335     }
336 }
337
338 static gboolean
339 gtk_search_engine_beagle_is_indexed (GtkSearchEngine *engine)
340 {
341   return TRUE;
342 }
343
344 static void
345 gtk_search_engine_beagle_set_query (GtkSearchEngine *engine, 
346                                     GtkQuery        *query)
347 {
348   GtkSearchEngineBeagle *beagle;
349   
350   beagle = GTK_SEARCH_ENGINE_BEAGLE (engine);
351   
352   if (query)
353     g_object_ref (query);
354
355   if (beagle->priv->query)
356     g_object_unref (beagle->priv->query);
357
358   beagle->priv->query = query;
359 }
360
361 static void
362 _gtk_search_engine_beagle_class_init (GtkSearchEngineBeagleClass *class)
363 {
364   GObjectClass *gobject_class;
365   GtkSearchEngineClass *engine_class;
366   
367   gobject_class = G_OBJECT_CLASS (class);
368   gobject_class->finalize = finalize;
369   
370   engine_class = GTK_SEARCH_ENGINE_CLASS (class);
371   engine_class->set_query = gtk_search_engine_beagle_set_query;
372   engine_class->start = gtk_search_engine_beagle_start;
373   engine_class->stop = gtk_search_engine_beagle_stop;
374   engine_class->is_indexed = gtk_search_engine_beagle_is_indexed;
375
376   g_type_class_add_private (gobject_class, sizeof (GtkSearchEngineBeaglePrivate));
377 }
378
379 static void
380 _gtk_search_engine_beagle_init (GtkSearchEngineBeagle *engine)
381 {
382   engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, GTK_TYPE_SEARCH_ENGINE_BEAGLE, GtkSearchEngineBeaglePrivate);
383 }
384
385
386 GtkSearchEngine *
387 _gtk_search_engine_beagle_new (void)
388 {
389   GtkSearchEngineBeagle *engine;
390   BeagleClient *client;
391
392   open_libbeagle ();
393
394   if (!beagle_util_daemon_is_running)
395     return NULL;
396
397   /* check whether daemon is running as beagle_client_new
398    * doesn't fail when a stale socket file exists */
399   if (!beagle_util_daemon_is_running ()) 
400       return NULL;
401
402   client = beagle_client_new (NULL);
403   
404   if (client == NULL)
405     return NULL;
406         
407   engine = g_object_new (GTK_TYPE_SEARCH_ENGINE_BEAGLE, NULL);
408   
409   engine->priv->client = client;
410   
411   return GTK_SEARCH_ENGINE (engine);
412 }