]> Pileus Git - ~andy/gtk/blob - gtk/gtksearchenginequartz.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtksearchenginequartz.c
1 /*
2  * Copyright (C) 2007  Kristian Rietveld  <kris@gtk.org>
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, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <Cocoa/Cocoa.h>
19 #include <quartz/gdkquartz.h>
20
21 #include "gtksearchenginequartz.h"
22
23 /* This file is a mixture of an objective-C object and a GObject,
24  * so be careful to not confuse yourself.
25  */
26
27 #define QUARTZ_POOL_ALLOC NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]
28 #define QUARTZ_POOL_RELEASE [pool release]
29
30
31 /* Definition of objective-c object */
32 @interface ResultReceiver : NSObject
33 {
34   int submitted_hits;
35   GtkSearchEngine *engine;
36 }
37
38 - (void) setEngine:(GtkSearchEngine *)quartz_engine;
39
40 - (void) queryUpdate:(id)sender;
41 - (void) queryProgress:(id)sender;
42 - (void) queryFinished:(id)sender;
43
44 @end
45
46
47 /* Definition of GObject */
48 struct _GtkSearchEngineQuartzPrivate
49 {
50   GtkQuery *query;
51
52   ResultReceiver *receiver;
53   NSMetadataQuery *ns_query;
54
55   gboolean query_finished;
56 };
57
58 G_DEFINE_TYPE (GtkSearchEngineQuartz, _gtk_search_engine_quartz, GTK_TYPE_SEARCH_ENGINE);
59
60
61 /* Implementation of the objective-C object */
62 @implementation ResultReceiver
63
64 - (void) setEngine:(GtkSearchEngine *)quartz_engine
65 {
66   g_return_if_fail (GTK_IS_SEARCH_ENGINE (quartz_engine));
67
68   engine = quartz_engine;
69   submitted_hits = 0;
70 }
71
72 - (void) submitHits:(NSMetadataQuery *)ns_query
73 {
74   int i;
75   GList *hits = NULL;
76
77   /* Here we submit hits "submitted_hits" to "resultCount" */
78   for (i = submitted_hits; i < [ns_query resultCount]; i++)
79     {
80       id result = [ns_query resultAtIndex:i];
81       char *result_path;
82
83       result_path = g_strdup_printf ("file://%s", [[result valueForAttribute:@"kMDItemPath"] cString]);
84       hits = g_list_prepend (hits, result_path);
85     }
86
87   _gtk_search_engine_hits_added (engine, hits);
88   g_list_free (hits);
89
90   submitted_hits = [ns_query resultCount];
91
92   /* The beagle backend stops at 1000 hits, so guess we do so too here.
93    * It works pretty snappy on my MacBook, if we get rid of this limit
94    * we are almost definitely going to need some code to submit hits
95    * in batches.
96    */
97   if (submitted_hits > 1000)
98     [ns_query stopQuery];
99 }
100
101 - (void) queryUpdate:(id)sender
102 {
103   NSMetadataQuery *ns_query = [sender object];
104
105   [self submitHits:ns_query];
106 }
107
108 - (void) queryProgress:(id)sender
109 {
110   NSMetadataQuery *ns_query = [sender object];
111
112   [self submitHits:ns_query];
113 }
114
115 - (void) queryFinished:(id)sender
116 {
117   NSMetadataQuery *ns_query = [sender object];
118
119   [self submitHits:ns_query];
120
121   _gtk_search_engine_finished (engine);
122   submitted_hits = 0;
123 }
124
125 @end
126
127 /* Implementation of the GObject */
128
129 static void
130 gtk_search_engine_quartz_finalize (GObject *object)
131 {
132   GtkSearchEngineQuartz *quartz;
133
134   QUARTZ_POOL_ALLOC;
135
136   quartz = GTK_SEARCH_ENGINE_QUARTZ (object);
137
138   [[NSNotificationCenter defaultCenter] removeObserver:quartz->priv->receiver];
139
140   [quartz->priv->ns_query release];
141   [quartz->priv->receiver release];
142
143   QUARTZ_POOL_RELEASE;
144
145   if (quartz->priv->query)
146     {
147       g_object_unref (quartz->priv->query);
148       quartz->priv->query = NULL;
149     }
150
151   G_OBJECT_CLASS (_gtk_search_engine_quartz_parent_class)->finalize (object);
152 }
153
154 static void
155 gtk_search_engine_quartz_start (GtkSearchEngine *engine)
156 {
157   GtkSearchEngineQuartz *quartz;
158
159   QUARTZ_POOL_ALLOC;
160
161   quartz = GTK_SEARCH_ENGINE_QUARTZ (engine);
162
163   [quartz->priv->ns_query startQuery];
164
165   QUARTZ_POOL_RELEASE;
166 }
167
168 static void
169 gtk_search_engine_quartz_stop (GtkSearchEngine *engine)
170 {
171   GtkSearchEngineQuartz *quartz;
172
173   QUARTZ_POOL_ALLOC;
174
175   quartz = GTK_SEARCH_ENGINE_QUARTZ (engine);
176
177   [quartz->priv->ns_query stopQuery];
178
179   QUARTZ_POOL_RELEASE;
180 }
181
182 static gboolean
183 gtk_search_engine_quartz_is_indexed (GtkSearchEngine *engine)
184 {
185   return TRUE;
186 }
187
188 static void
189 gtk_search_engine_quartz_set_query (GtkSearchEngine *engine, 
190                                     GtkQuery        *query)
191 {
192   GtkSearchEngineQuartz *quartz;
193
194   QUARTZ_POOL_ALLOC;
195
196   quartz = GTK_SEARCH_ENGINE_QUARTZ (engine);
197
198   if (query)
199     g_object_ref (query);
200
201   if (quartz->priv->query)
202     g_object_unref (quartz->priv->query);
203
204   quartz->priv->query = query;
205
206   /* We create a query to look for ".*text.*" in the text contents of
207    * all indexed files.  (Should we also search for text in file and folder
208    * names?).
209    */
210   [quartz->priv->ns_query setPredicate:
211     [NSPredicate predicateWithFormat:
212       [NSString stringWithFormat:@"(kMDItemTextContent LIKE[cd] \"*%s*\")",
213                                  _gtk_query_get_text (query)]]];
214
215   QUARTZ_POOL_RELEASE;
216 }
217
218 static void
219 _gtk_search_engine_quartz_class_init (GtkSearchEngineQuartzClass *class)
220 {
221   GObjectClass *gobject_class;
222   GtkSearchEngineClass *engine_class;
223   
224   gobject_class = G_OBJECT_CLASS (class);
225   gobject_class->finalize = gtk_search_engine_quartz_finalize;
226   
227   engine_class = GTK_SEARCH_ENGINE_CLASS (class);
228   engine_class->set_query = gtk_search_engine_quartz_set_query;
229   engine_class->start = gtk_search_engine_quartz_start;
230   engine_class->stop = gtk_search_engine_quartz_stop;
231   engine_class->is_indexed = gtk_search_engine_quartz_is_indexed;
232
233   g_type_class_add_private (gobject_class, sizeof (GtkSearchEngineQuartzPrivate));
234 }
235
236 static void
237 _gtk_search_engine_quartz_init (GtkSearchEngineQuartz *engine)
238 {
239   QUARTZ_POOL_ALLOC;
240
241   engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, GTK_TYPE_SEARCH_ENGINE_QUARTZ, GtkSearchEngineQuartzPrivate);
242
243   engine->priv->ns_query = [[NSMetadataQuery alloc] init];
244   engine->priv->receiver = [[ResultReceiver alloc] init];
245
246   [engine->priv->receiver setEngine:GTK_SEARCH_ENGINE (engine)];
247
248   [[NSNotificationCenter defaultCenter] addObserver:engine->priv->receiver
249                                         selector:@selector(queryUpdate:)
250                                         name:@"NSMetadataQueryDidUpdateNotification"
251                                         object:engine->priv->ns_query];
252   [[NSNotificationCenter defaultCenter] addObserver:engine->priv->receiver
253                                         selector:@selector(queryFinished:)
254                                         name:@"NSMetadataQueryDidFinishGatheringNotification"
255                                         object:engine->priv->ns_query];
256
257   [[NSNotificationCenter defaultCenter] addObserver:engine->priv->receiver
258                                         selector:@selector(queryProgress:)
259                                         name:@"NSMetadataQueryGatheringProgressNotification"
260                                         object:engine->priv->ns_query];
261
262   QUARTZ_POOL_RELEASE;
263 }
264
265 GtkSearchEngine *
266 _gtk_search_engine_quartz_new (void)
267 {
268 #ifdef GDK_WINDOWING_QUARTZ
269   return g_object_new (GTK_TYPE_SEARCH_ENGINE_QUARTZ, NULL);
270 #else
271   return NULL;
272 #endif
273 }