message-view: bgo #727634 - Cannot copy build output
[anjuta.git] / plugins / language-support-cpp-java / cpp-packages.c
blob131c5a4b68863d81a44a98b3eb4572f06cc092c5
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta
4 * Copyright (C) Johannes Schmid 2011 <jhs@Obelix>
5 *
6 * anjuta is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * anjuta is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "cpp-packages.h"
21 #include "plugin.h"
23 #include <libanjuta/interfaces/ianjuta-project-manager.h>
24 #include <libanjuta/interfaces/ianjuta-symbol-manager.h>
25 #include <libanjuta/anjuta-pkg-config.h>
26 #include <libanjuta/anjuta-pkg-scanner.h>
27 #include <libanjuta/anjuta-debug.h>
28 #include <libanjuta/anjuta-preferences.h>
30 #define PREF_PROJECT_PACKAGES "load-project-packages"
31 #define PREF_USER_PACKAGES "user-packages"
32 #define PREF_LIBC "load-libc"
34 #define PROJECT_LOADED "__cpp_packages_loaded"
35 #define USER_LOADED "__cpp_user_packages_loaded"
37 /**
38 * Standard files of the C library (according to
39 * https://secure.wikimedia.org/wikipedia/en/wiki/C_standard_library)
41 const gchar* libc_files[] =
43 "assert.h",
44 "complex.h",
45 "ctype.h",
46 "errno.h",
47 "fenv.h",
48 "float.h",
49 "inttypes.h",
50 "iso646.h",
51 "limits.h",
52 "locale.h",
53 "math.h",
54 "setjmp.h",
55 "signal.h",
56 "stdarg.h",
57 "stdbool.h",
58 "stddef.h",
59 "stdint.h",
60 "stdio.h",
61 "stdlib.h",
62 "string.h",
63 "tgmath.h",
64 "time.h",
65 "wchar.h",
66 "wctype.h",
67 NULL
70 /**
71 * Standard location of libc on UNIX systems
73 #define LIBC_LOCATION "/usr/include"
74 #define LIBC_VERSION "C99"
75 #define LIBC "libc"
77 enum
79 PROP_0,
80 PROP_PLUGIN
83 typedef struct
85 gchar* pkg;
86 gchar* version;
87 } PackageData;
89 static int
90 pkg_data_compare (gpointer data1, gpointer pkg2)
92 PackageData* pkg_data1 = data1;
94 return strcmp (pkg_data1->pkg, (const gchar*) pkg2);
97 static void
98 pkg_data_free (PackageData* data)
100 g_free (data->pkg);
101 g_free (data->version);
102 g_free (data);
106 G_DEFINE_TYPE (CppPackages, cpp_packages, G_TYPE_OBJECT);
108 static GList*
109 cpp_packages_activate_package (IAnjutaSymbolManager* sm, const gchar* pkg,
110 GList** packages_to_add)
112 gchar* name = g_strdup (pkg);
113 gchar* version;
114 gchar* c;
116 /* Clean package name */
117 for (c = name; *c != '\0'; c++)
119 if (g_ascii_isspace (*c))
121 *c = '\0';
122 break;
126 version = anjuta_pkg_config_get_version (name);
127 if (!version)
129 g_free (name);
130 return *packages_to_add;
133 /* Only query each package once */
134 if (g_list_find_custom (*packages_to_add,
135 name, (GCompareFunc) pkg_data_compare))
136 return *packages_to_add;
137 if (!ianjuta_symbol_manager_activate_package (sm, name, version, NULL))
139 GList* deps = anjuta_pkg_config_list_dependencies (name, NULL);
140 GList* dep;
141 PackageData* data = g_new0 (PackageData, 1);
142 for (dep = deps; dep != NULL; dep = g_list_next (dep))
144 cpp_packages_activate_package (sm, dep->data, packages_to_add);
146 anjuta_util_glist_strings_free (deps);
147 data->pkg = g_strdup (name);
148 data->version = g_strdup (version);
149 *packages_to_add = g_list_prepend (*packages_to_add,
150 data);
152 g_free (name);
153 return *packages_to_add;
156 static void
157 on_package_ready (AnjutaCommand* command,
158 gint return_code,
159 IAnjutaSymbolManager* sm)
161 AnjutaPkgScanner* scanner = ANJUTA_PKG_SCANNER (command);
162 if (g_list_length (anjuta_pkg_scanner_get_files (scanner)))
164 ianjuta_symbol_manager_add_package (sm,
165 anjuta_pkg_scanner_get_package (scanner),
166 anjuta_pkg_scanner_get_version (scanner),
167 anjuta_pkg_scanner_get_files (scanner),
168 NULL);
172 static void
173 on_queue_finished (AnjutaCommandQueue* queue, CppPackages* packages)
175 g_object_unref (queue);
176 packages->loading = FALSE;
177 g_object_unref (packages);
180 static void
181 cpp_packages_activate_libc (CppPackages* packages)
183 IAnjutaSymbolManager* sm =
184 anjuta_shell_get_interface (anjuta_plugin_get_shell (ANJUTA_PLUGIN(packages->plugin)),
185 IAnjutaSymbolManager, NULL);
187 if (!ianjuta_symbol_manager_activate_package (sm, LIBC, LIBC_VERSION, NULL))
189 /* Create file list*/
190 GList* files = NULL;
191 const gchar** file;
192 for (file = libc_files; *file != NULL; file++)
194 gchar* real_file = g_build_filename (LIBC_LOCATION, *file, NULL);
195 if (g_file_test (real_file, G_FILE_TEST_EXISTS))
196 files = g_list_append (files, real_file);
197 else
198 g_free (real_file);
201 /* Add package */
202 ianjuta_symbol_manager_add_package (sm,
203 LIBC,
204 LIBC_VERSION,
205 files,
206 NULL);
207 anjuta_util_glist_strings_free (files);
211 static void
212 on_load_libc (GSettings* settings,
213 gchar* key,
214 CppPackages* packages)
216 gboolean load =
217 g_settings_get_boolean (ANJUTA_PLUGIN_CPP_JAVA(packages->plugin)->settings,
218 key);
219 if (load)
221 cpp_packages_activate_libc (packages);
223 else
225 IAnjutaSymbolManager* sm =
226 anjuta_shell_get_interface (anjuta_plugin_get_shell (ANJUTA_PLUGIN(packages->plugin)),
227 IAnjutaSymbolManager, NULL);
228 ianjuta_symbol_manager_deactivate_package (sm, LIBC, LIBC_VERSION, NULL);
232 static void
233 cpp_packages_load_real (CppPackages* packages, GError* error, IAnjutaProjectManager* pm)
235 IAnjutaSymbolManager* sm =
236 anjuta_shell_get_interface (anjuta_plugin_get_shell (ANJUTA_PLUGIN(packages->plugin)),
237 IAnjutaSymbolManager, NULL);
238 GList* pkgs;
239 GList* pkg;
240 GList* packages_to_add = NULL;
242 if (!pm || !sm)
243 return;
245 ianjuta_symbol_manager_deactivate_all (sm, NULL);
246 pkgs = ianjuta_project_manager_get_packages (pm, NULL);
247 for (pkg = pkgs; pkg != NULL; pkg = g_list_next (pkg))
249 cpp_packages_activate_package (sm, pkg->data, &packages_to_add);
251 g_list_free (pkgs);
252 if (packages_to_add)
254 packages->loading = TRUE;
255 packages->queue = anjuta_command_queue_new (ANJUTA_COMMAND_QUEUE_EXECUTE_MANUAL);
256 for (pkg = packages_to_add; pkg != NULL; pkg = g_list_next (pkg))
258 PackageData* pkg_data = pkg->data;
259 AnjutaCommand* command =
260 anjuta_pkg_scanner_new (pkg_data->pkg, pkg_data->version);
261 g_signal_connect (command, "command-finished",
262 G_CALLBACK (on_package_ready), sm);
263 anjuta_command_queue_push (packages->queue, command);
265 g_list_foreach (packages_to_add, (GFunc) pkg_data_free, NULL);
266 g_list_free (packages_to_add);
268 g_signal_connect (packages->queue, "finished", G_CALLBACK (on_queue_finished), packages);
269 /* Make sure the pointer is valid when the queue finishes */
270 g_object_ref (packages);
271 anjuta_command_queue_start (packages->queue);
275 static void
276 cpp_packages_load_user (CppPackages* packages, gboolean force)
278 CppJavaPlugin* plugin = ANJUTA_PLUGIN_CPP_JAVA(packages->plugin);
279 AnjutaShell* shell = anjuta_plugin_get_shell (ANJUTA_PLUGIN (plugin));
280 IAnjutaSymbolManager* sm =
281 anjuta_shell_get_interface (shell, IAnjutaSymbolManager, NULL);
282 gboolean loaded = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (shell),
283 USER_LOADED));
285 if (!loaded || force)
287 gchar* packages_str = g_settings_get_string (plugin->settings,
288 PREF_USER_PACKAGES);
289 GStrv pkgs = g_strsplit (packages_str, ";", -1);
290 gchar** package;
291 GList* packages_to_add = NULL;
292 GList* pkg;
294 ianjuta_symbol_manager_deactivate_all (sm, NULL);
296 for (package = pkgs; *package != NULL; package++)
298 cpp_packages_activate_package (sm, *package, &packages_to_add);
300 g_strfreev (pkgs);
301 g_free (packages_str);
303 if (packages_to_add)
305 packages->loading = TRUE;
306 packages->queue = anjuta_command_queue_new (ANJUTA_COMMAND_QUEUE_EXECUTE_MANUAL);
307 for (pkg = packages_to_add; pkg != NULL; pkg = g_list_next (pkg))
309 PackageData* pkg_data = pkg->data;
310 AnjutaCommand* command =
311 anjuta_pkg_scanner_new (pkg_data->pkg, pkg_data->version);
312 g_signal_connect (command, "command-finished",
313 G_CALLBACK (on_package_ready), sm);
314 anjuta_command_queue_push (packages->queue, command);
316 g_list_foreach (packages_to_add, (GFunc) pkg_data_free, NULL);
317 g_list_free (packages_to_add);
319 g_object_set_data (G_OBJECT (shell),
320 USER_LOADED, GINT_TO_POINTER (TRUE));
322 g_signal_connect (packages->queue, "finished", G_CALLBACK (on_queue_finished), packages);
323 /* Make sure the pointer is valid when the queue finishes */
324 g_object_ref (packages);
325 anjuta_command_queue_start (packages->queue);
330 static gboolean
331 cpp_packages_idle_load_user (CppPackages* packages)
333 if (packages->loading)
334 return TRUE;
336 cpp_packages_load (packages, TRUE);
337 packages->idle_id = 0;
338 g_object_unref (packages);
340 return FALSE;
343 void
344 cpp_packages_load (CppPackages* packages, gboolean force)
346 CppJavaPlugin* plugin = ANJUTA_PLUGIN_CPP_JAVA(packages->plugin);
348 if (g_settings_get_boolean (plugin->settings,
349 PREF_PROJECT_PACKAGES))
351 IAnjutaProjectManager* pm =
352 anjuta_shell_get_interface (packages->plugin->shell, IAnjutaProjectManager, NULL);
353 IAnjutaProject* project;
355 g_signal_connect_swapped (pm, "project-loaded", G_CALLBACK (cpp_packages_load_real), packages);
357 project = ianjuta_project_manager_get_current_project (pm, NULL);
358 /* Only load the packages if necessary */
359 if (project && ianjuta_project_is_loaded (project, NULL))
361 gboolean loaded = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (project),
362 PROJECT_LOADED));
363 if (!loaded && !packages->loading)
365 cpp_packages_load_real (packages, NULL, pm);
366 g_object_set_data (G_OBJECT (project), PROJECT_LOADED, GINT_TO_POINTER (TRUE));
370 else
372 if (packages->loading)
374 if (!packages->idle_id)
376 packages->idle_id = g_idle_add ((GSourceFunc)cpp_packages_idle_load_user, packages);
377 g_object_ref (packages);
379 return;
381 else
383 cpp_packages_load_user (packages, force);
387 g_signal_connect (plugin->settings, "changed::PREF_LIBC",
388 G_CALLBACK (on_load_libc), packages);
389 on_load_libc (plugin->settings,
390 PREF_LIBC,
391 packages);
394 static void
395 cpp_packages_init (CppPackages *packages)
397 packages->loading = FALSE;
398 packages->idle_id = 0;
401 static void
402 cpp_packages_finalize (GObject* object)
404 CppPackages *packages = CPP_PACKAGES (object);
405 AnjutaShell* shell = packages->plugin->shell;
407 if (shell != NULL)
409 IAnjutaProjectManager* pm =
410 anjuta_shell_get_interface (shell, IAnjutaProjectManager, NULL);
412 if (pm != NULL)
413 g_signal_handlers_disconnect_by_func (pm, cpp_packages_load_real, packages);
416 G_OBJECT_CLASS (cpp_packages_parent_class)->finalize (object);
419 static void
420 cpp_packages_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
422 CppPackages* packages;
424 g_return_if_fail (CPP_IS_PACKAGES (object));
426 packages = CPP_PACKAGES (object);
428 switch (prop_id)
430 case PROP_PLUGIN:
431 packages->plugin = ANJUTA_PLUGIN (g_value_get_object (value));
432 break;
433 default:
434 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
435 break;
439 static void
440 cpp_packages_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
442 CppPackages* packages;
444 g_return_if_fail (CPP_IS_PACKAGES (object));
446 packages = CPP_PACKAGES (object);
448 switch (prop_id)
450 case PROP_PLUGIN:
451 g_value_set_object (value, G_OBJECT (packages->plugin));
452 break;
453 default:
454 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
455 break;
459 static void
460 cpp_packages_class_init (CppPackagesClass *klass)
462 GObjectClass* object_class = G_OBJECT_CLASS (klass);
464 object_class->finalize = cpp_packages_finalize;
465 object_class->set_property = cpp_packages_set_property;
466 object_class->get_property = cpp_packages_get_property;
468 g_object_class_install_property (object_class,
469 PROP_PLUGIN,
470 g_param_spec_object ("plugin",
471 "CppJavaPlugin",
472 "CppJavaPlugin",
473 ANJUTA_TYPE_PLUGIN,
474 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
477 CppPackages*
478 cpp_packages_new (AnjutaPlugin* plugin)
480 GObject* object =
481 g_object_new (CPP_TYPE_PACKAGES,
482 "plugin", plugin,
483 NULL);
484 return CPP_PACKAGES (object);