1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * Copyright (C) 2004,2005 Johan Dahlin
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <Python.h>
25 #define NO_IMPORT_PYGOBJECT //To avoid a multiple definition, nautilus-python-object.c also includes and does the import.
26 #include <pygobject.h>
27 #include <gmodule.h>
28 #include <gtk/gtk.h>
29
30 #include "nautilus-python.h"
31 #include "nautilus-python-object.h"
32
33 #include <nautilus-extension.h>
34
35 static const GDebugKey nautilus_python_debug_keys[] = {
36 {"misc", NAUTILUS_PYTHON_DEBUG_MISC},
37 };
38 static const guint nautilus_python_ndebug_keys = sizeof (nautilus_python_debug_keys) / sizeof (GDebugKey);
39 NautilusPythonDebug nautilus_python_debug;
40
41 static gboolean nautilus_python_init_python(void);
42
43 static GArray *all_types = NULL;
44
45 PyTypeObject *_PyGtkWidget_Type;
46 PyTypeObject *_PyNautilusColumn_Type;
47 PyTypeObject *_PyNautilusColumnProvider_Type;
48 PyTypeObject *_PyNautilusInfoProvider_Type;
49 PyTypeObject *_PyNautilusLocationWidgetProvider_Type;
50 PyTypeObject *_PyNautilusMenu_Type;
51 PyTypeObject *_PyNautilusMenuItem_Type;
52 PyTypeObject *_PyNautilusMenuProvider_Type;
53 PyTypeObject *_PyNautilusPropertyPage_Type;
54 PyTypeObject *_PyNautilusPropertyPageProvider_Type;
55 PyTypeObject *_PyNautilusOperationHandle_Type;
56
57 static inline gboolean
np_init_pygobject(void)58 np_init_pygobject(void) {
59 PyObject *gobject = pygobject_init (PYGOBJECT_MAJOR_VERSION, PYGOBJECT_MINOR_VERSION, PYGOBJECT_MICRO_VERSION);
60
61 if (gobject == NULL) {
62 PyErr_Print ();
63 return FALSE;
64 }
65
66 return TRUE;
67 }
68
69 static void
nautilus_python_load_file(GTypeModule * type_module,const gchar * filename)70 nautilus_python_load_file(GTypeModule *type_module,
71 const gchar *filename) {
72 PyObject *main_module, *main_locals, *locals, *key, *value;
73 PyObject *module;
74 GType gtype;
75 Py_ssize_t pos = 0;
76
77 debug_enter_args("filename=%s", filename);
78
79 main_module = PyImport_AddModule("__main__");
80 if (main_module == NULL) {
81 g_warning("Could not get __main__.");
82 return;
83 }
84
85 main_locals = PyModule_GetDict(main_module);
86 module = PyImport_ImportModuleEx((char *) filename, main_locals, main_locals, NULL);
87 if (!module) {
88 PyErr_Print();
89 return;
90 }
91
92 locals = PyModule_GetDict(module);
93
94 while (PyDict_Next(locals, &pos, &key, &value)) {
95 if (!PyType_Check(value))
96 continue;
97
98 if (PyObject_IsSubclass(value, (PyObject*)&PyNautilusColumnProvider_Type) ||
99 PyObject_IsSubclass(value, (PyObject*)&PyNautilusInfoProvider_Type) ||
100 PyObject_IsSubclass(value, (PyObject*)&PyNautilusLocationWidgetProvider_Type) ||
101 PyObject_IsSubclass(value, (PyObject*)&PyNautilusMenuProvider_Type) ||
102 PyObject_IsSubclass(value, (PyObject*)&PyNautilusPropertyPageProvider_Type)) {
103 gtype = nautilus_python_object_get_type(type_module, value);
104 g_array_append_val(all_types, gtype);
105 }
106 }
107
108 debug("Loaded python modules");
109 }
110
111 static void
nautilus_python_load_dir(GTypeModule * module,const char * dirname)112 nautilus_python_load_dir (GTypeModule *module,
113 const char *dirname) {
114 GDir *dir;
115 const char *name;
116 gboolean initialized = FALSE;
117
118 debug_enter_args("dirname=%s", dirname);
119
120 dir = g_dir_open(dirname, 0, NULL);
121 if (!dir)
122 return;
123
124 while ((name = g_dir_read_name(dir))) {
125 if (g_str_has_suffix(name, ".py")) {
126 char *modulename;
127 int len;
128
129 len = strlen(name) - 3;
130 modulename = g_new0(char, len + 1 );
131 strncpy(modulename, name, len);
132
133 if (!initialized) {
134 PyObject *sys_path, *py_path;
135
136 /* n-p python part is initialized on demand (or not
137 * at all if no extensions are found) */
138 if (!nautilus_python_init_python()) {
139 g_warning("nautilus_python_init_python failed");
140 g_dir_close(dir);
141 break;
142 }
143
144 /* sys.path.insert(0, dirname) */
145 sys_path = PySys_GetObject("path");
146 #if PY_MAJOR_VERSION >= 3
147 py_path = PyUnicode_FromString(dirname);
148 #else
149 py_path = PyString_FromString(dirname);
150 #endif
151 PyList_Insert(sys_path, 0, py_path);
152 Py_DECREF(py_path);
153 }
154
155 nautilus_python_load_file(module, modulename);
156 }
157 }
158 }
159
160 static gboolean
nautilus_python_init_python(void)161 nautilus_python_init_python (void) {
162 PyObject *nautilus;
163 GModule *libpython;
164
165 if (Py_IsInitialized())
166 return TRUE;
167
168 debug("g_module_open " PY_LIB_LOC "/lib" PY_LIB_NAME "." G_MODULE_SUFFIX ".1.0");
169 libpython = g_module_open (PY_LIB_LOC "/lib" PY_LIB_NAME "." G_MODULE_SUFFIX ".1.0", 0);
170 if (!libpython)
171 g_warning("g_module_open libpython failed: %s", g_module_error());
172
173 debug("Py_Initialize");
174 Py_Initialize();
175 if (PyErr_Occurred()) {
176 PyErr_Print();
177 return FALSE;
178 }
179
180 debug("PySys_SetArgv");
181 #if PY_MAJOR_VERSION >= 3
182 wchar_t *argv[] = { L"nautilus", NULL };
183 #else
184 char *argv[] = { "nautilus", NULL };
185 #endif
186 PySys_SetArgv(1, argv);
187 if (PyErr_Occurred()) {
188 PyErr_Print();
189 return FALSE;
190 }
191
192 debug("Sanitize the python search path");
193 PyRun_SimpleString("import sys; sys.path = [path for path in sys.path if path]");
194 if (PyErr_Occurred()) {
195 PyErr_Print();
196 return FALSE;
197 }
198
199 /* import gobject */
200 debug("init_pygobject");
201 if (!np_init_pygobject()) {
202 g_warning("pygobject initialization failed");
203 return FALSE;
204 }
205
206 /* import nautilus */
207 g_setenv("INSIDE_NAUTILUS_PYTHON", "", FALSE);
208 debug("import nautilus");
209 PyRun_SimpleString("import gi; gi.require_version('Nautilus', '3.0')");
210 nautilus = PyImport_ImportModule("gi.repository.Nautilus");
211 if (!nautilus) {
212 PyErr_Print();
213 return FALSE;
214 }
215
216 _PyGtkWidget_Type = pygobject_lookup_class(GTK_TYPE_WIDGET);
217 g_assert(_PyGtkWidget_Type != NULL);
218
219 #define IMPORT(x, y) \
220 _PyNautilus##x##_Type = (PyTypeObject *)PyObject_GetAttrString(nautilus, y); \
221 if (_PyNautilus##x##_Type == NULL) { \
222 PyErr_Print(); \
223 return FALSE; \
224 }
225
226 IMPORT(Column, "Column");
227 IMPORT(ColumnProvider, "ColumnProvider");
228 IMPORT(InfoProvider, "InfoProvider");
229 IMPORT(LocationWidgetProvider, "LocationWidgetProvider");
230 IMPORT(Menu, "Menu");
231 IMPORT(MenuItem, "MenuItem");
232 IMPORT(MenuProvider, "MenuProvider");
233 IMPORT(PropertyPage, "PropertyPage");
234 IMPORT(PropertyPageProvider, "PropertyPageProvider");
235 IMPORT(OperationHandle, "OperationHandle");
236
237 #undef IMPORT
238
239 return TRUE;
240 }
241
242
243 static void
nautilus_python_check_all_directories(GTypeModule * module)244 nautilus_python_check_all_directories(GTypeModule *module) {
245 gchar *extensions_dir = NULL;
246
247 GList *dirs = NULL;
248
249 // Check ~/.local/share first
250 dirs = g_list_append(dirs, g_build_filename(g_get_user_data_dir(),
251 "nautilus-python", "extensions", NULL));
252
253 // If nautilus is built in a non-standard prefix
254 // Check nautilus prefix's DATADIR
255 gchar *prefix_extension_dir = DATADIR "/nautilus-python/extensions";
256 dirs = g_list_append(dirs, prefix_extension_dir);
257
258 // Check all system data dirs
259 const gchar *const *temp = g_get_system_data_dirs();
260 while (*temp != NULL) {
261 gchar *dir = g_build_filename(*temp,
262 "nautilus-python", "extensions", NULL);
263 if (g_strcmp0(dir, prefix_extension_dir) != 0) {
264 dirs = g_list_append(dirs, dir);
265 }
266
267 temp++;
268 }
269
270 dirs = g_list_first(dirs);
271 while (dirs != NULL) {
272 gchar *dir = dirs->data;
273 nautilus_python_load_dir(module, dir);
274 dirs = dirs->next;
275 }
276
277 g_list_free(dirs);
278 }
279
280 void
nautilus_module_initialize(GTypeModule * module)281 nautilus_module_initialize(GTypeModule *module) {
282 gchar *user_extensions_dir;
283 const gchar *env_string;
284
285 env_string = g_getenv("NAUTILUS_PYTHON_DEBUG");
286 if (env_string != NULL) {
287 nautilus_python_debug = g_parse_debug_string(env_string,
288 nautilus_python_debug_keys,
289 nautilus_python_ndebug_keys);
290 env_string = NULL;
291 }
292
293 debug_enter();
294
295 all_types = g_array_new(FALSE, FALSE, sizeof(GType));
296
297 nautilus_python_check_all_directories(module);
298 }
299
300 void
nautilus_module_shutdown(void)301 nautilus_module_shutdown(void) {
302 debug_enter();
303
304 if (Py_IsInitialized())
305 Py_Finalize();
306
307 g_array_free(all_types, TRUE);
308 }
309
310 void
nautilus_module_list_types(const GType ** types,int * num_types)311 nautilus_module_list_types(const GType **types,
312 int *num_types) {
313 debug_enter();
314
315 *types = (GType*)all_types->data;
316 *num_types = all_types->len;
317 }
318