1 #if defined(HAVE_CONFIG_H) && !defined(GEANYPY_WINDOWS)
2 # include "config.h"
3 #endif
4 
5 #include "geanypy.h"
6 
7 
8 #define GOB_CHECK(pyobj, arg) \
9 	{ \
10 		if (!pyobj || pyobj == Py_None || !pygobject_check(pyobj, PyGObject_Type)) \
11 		{ \
12 			PyErr_SetString(PyExc_ValueError, \
13 				"argument " #arg " must inherit from a gobject.GObject type"); \
14 			return NULL; \
15 		} \
16 	}
17 
18 #define GOB_TYPE_CHECK(gob, gob_type, arg) \
19 	{ \
20 		if (!gob || !G_IS_OBJECT(gob) || \
21 			!g_type_is_a(G_TYPE_FROM_INSTANCE(gob), gob_type)) \
22 		{ \
23 			PyErr_SetString(PyExc_ValueError, \
24 				"argument " #arg " must inherit from a " #gob_type " type"); \
25 			return NULL; \
26 		} \
27 	}
28 
29 
30 static PyTypeObject *PyGObject_Type = NULL;
31 
32 
33 static PyObject *
UiUtils_hookup_widget(PyObject * module,PyObject * args,PyObject * kwargs)34 UiUtils_hookup_widget(PyObject *module, PyObject *args, PyObject *kwargs)
35 {
36 	PyObject *py_owner = NULL, *py_widget = NULL;
37 	const gchar *widget_name = NULL;
38 	GObject *owner = NULL, *widget = NULL;
39 	static gchar *kwlist[] = { "owner", "widget", "widget_name", NULL };
40 
41 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "OOs", kwlist,
42 		&py_owner, &py_widget, &widget_name))
43 	{
44 		GOB_CHECK(py_owner, 1);
45 		GOB_CHECK(py_widget, 2);
46 		owner = pygobject_get(py_owner);
47 		widget = pygobject_get(py_widget);
48 		ui_hookup_widget(owner, widget, widget_name);
49 	}
50 
51 	Py_RETURN_NONE;
52 }
53 
54 
55 static PyObject *
UiUtils_lookup_widget(PyObject * module,PyObject * args,PyObject * kwargs)56 UiUtils_lookup_widget(PyObject *module, PyObject *args, PyObject *kwargs)
57 {
58 	PyObject *py_widget = NULL;
59 	const gchar *widget_name = NULL;
60 	GObject *widget = NULL;
61 	GtkWidget *found_widget = NULL;
62 	static gchar *kwlist[] = { "widget", "widget_name", NULL };
63 
64 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "Os", kwlist,
65 		&py_widget, &widget_name))
66 	{
67 		GOB_CHECK(py_widget, 1);
68 		widget = pygobject_get(py_widget);
69 		GOB_TYPE_CHECK(widget, GTK_TYPE_WIDGET, 1);
70 		found_widget = ui_lookup_widget(GTK_WIDGET(widget), widget_name);
71 		if (GTK_IS_WIDGET(found_widget))
72 			return pygobject_new(G_OBJECT(found_widget));
73 	}
74 
75 	Py_RETURN_NONE;
76 }
77 
78 
79 static PyObject *
UiUtils_add_document_sensitive(PyObject * module,PyObject * args,PyObject * kwargs)80 UiUtils_add_document_sensitive(PyObject *module, PyObject *args, PyObject *kwargs)
81 {
82 	PyObject *py_widget = NULL;
83 	GObject *widget = NULL;
84 	static gchar *kwlist[] = { "widget", NULL };
85 
86 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &py_widget))
87 	{
88 		GOB_CHECK(py_widget, 1);
89 		widget = pygobject_get(py_widget);
90 		GOB_TYPE_CHECK(widget, GTK_TYPE_WIDGET, 1);
91 		ui_add_document_sensitive(GTK_WIDGET(widget));
92 	}
93 
94 	Py_RETURN_NONE;
95 }
96 
97 
98 static PyObject *
UiUtils_button_new_with_image(PyObject * module,PyObject * args,PyObject * kwargs)99 UiUtils_button_new_with_image(PyObject *module, PyObject *args, PyObject *kwargs)
100 {
101 	const gchar *stock_id = NULL, *text = NULL;
102 	GtkWidget *button = NULL;
103 	static gchar *kwlist[] = { "stock_id", "text", NULL };
104 
105 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &stock_id, &text))
106 	{
107 		button = ui_button_new_with_image(stock_id, text);
108 		if (GTK_IS_WIDGET(button))
109 			return pygobject_new(G_OBJECT(button));
110 	}
111 
112 	Py_RETURN_NONE;
113 }
114 
115 
116 static PyObject *
UiUtils_combo_box_add_to_history(PyObject * module,PyObject * args,PyObject * kwargs)117 UiUtils_combo_box_add_to_history(PyObject *module, PyObject *args, PyObject *kwargs)
118 {
119 	PyObject *py_cbo = NULL;
120 	const gchar *text = NULL;
121 	gint hist_len = 0;
122 	GObject *widget = NULL;
123 	static gchar *kwlist[] = { "combo_entry", "text", "history_len", NULL };
124 
125 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "Osi", kwlist,
126 		&py_cbo, &text, &hist_len))
127 	{
128 		GOB_CHECK(py_cbo, 1);
129 		widget = pygobject_get(py_cbo);
130 		GOB_TYPE_CHECK(widget, GTK_TYPE_COMBO_BOX_TEXT, 1);
131 		ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(widget), text, hist_len);
132 	}
133 
134 	Py_RETURN_NONE;
135 }
136 
137 
138 static PyObject *
UiUtils_dialog_vbox_new(PyObject * module,PyObject * args,PyObject * kwargs)139 UiUtils_dialog_vbox_new(PyObject *module, PyObject *args, PyObject *kwargs)
140 {
141 	PyObject *py_dlg;
142 	GObject *dlg;
143 	GtkWidget *widget;
144 	static gchar *kwlist[] = { "dialog", NULL };
145 
146 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &py_dlg))
147 	{
148 		GOB_CHECK(py_dlg, 1);
149 		dlg = pygobject_get(py_dlg);
150 		GOB_TYPE_CHECK(dlg, GTK_TYPE_DIALOG, 1);
151 		widget = ui_dialog_vbox_new(GTK_DIALOG(dlg));
152 		if (GTK_IS_WIDGET(widget))
153 			return pygobject_new(G_OBJECT(widget));
154 	}
155 
156 	Py_RETURN_NONE;
157 }
158 
159 
160 static PyObject *
UiUtils_entry_add_clear_icon(PyObject * module,PyObject * args,PyObject * kwargs)161 UiUtils_entry_add_clear_icon(PyObject *module, PyObject *args, PyObject *kwargs)
162 {
163 	PyObject *py_ent = NULL;
164 	GObject *ent;
165 	static gchar *kwlist[] = { "entry", NULL };
166 
167 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &py_ent))
168 	{
169 		GOB_CHECK(py_ent, 1);
170 		ent = pygobject_get(py_ent);
171 		GOB_TYPE_CHECK(ent, GTK_TYPE_ENTRY, 1);
172 		ui_entry_add_clear_icon(GTK_ENTRY(ent));
173 	}
174 
175 	Py_RETURN_NONE;
176 }
177 
178 
179 static PyObject *
UiUtils_frame_new_with_alignment(PyObject * module,PyObject * args,PyObject * kwargs)180 UiUtils_frame_new_with_alignment(PyObject *module, PyObject *args, PyObject *kwargs)
181 {
182 	const gchar *text = NULL;
183 	static gchar *kwlist[] = { "label_text", NULL };
184 	GtkWidget *alignment = NULL, *frame = NULL;
185 	PyObject *py_al = NULL, *py_fr = NULL, *ret;
186 
187 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &text))
188 	{
189 		frame = ui_frame_new_with_alignment(text, &alignment);
190 		py_al = (PyObject *) pygobject_new(G_OBJECT(frame));
191 		py_fr = (PyObject *) pygobject_new(G_OBJECT(alignment));
192 		ret = Py_BuildValue("OO", py_al, py_fr);
193 		Py_DECREF(py_al);
194 		Py_DECREF(py_fr);
195 		return ret;
196 	}
197 
198 	Py_RETURN_NONE;
199 }
200 
201 
202 static PyObject *
UiUtils_get_gtk_settings_integer(PyObject * module,PyObject * args,PyObject * kwargs)203 UiUtils_get_gtk_settings_integer(PyObject *module, PyObject *args, PyObject *kwargs)
204 {
205 	const gchar *prop_name = NULL;
206 	gint default_value = 0;
207 	static gchar *kwlist[] = { "property_name", "default_value", NULL };
208 
209 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "si", kwlist, &prop_name,
210 		&default_value))
211 	{
212 		return PyInt_FromLong(
213 				(glong) ui_get_gtk_settings_integer(prop_name, default_value));
214 	}
215 
216 	Py_RETURN_NONE;
217 }
218 
219 
220 static PyObject *
UiUtils_image_menu_item_new(PyObject * module,PyObject * args,PyObject * kwargs)221 UiUtils_image_menu_item_new(PyObject *module, PyObject *args, PyObject *kwargs)
222 {
223 	const gchar *stock_id = NULL, *label = NULL;
224 	GtkWidget *ret = NULL;
225 	static gchar *kwlist[] = { "stock_id", "label", NULL };
226 
227 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist,
228 		&stock_id, &label))
229 	{
230 		ret = ui_image_menu_item_new(stock_id, label);
231 		if (GTK_IS_WIDGET(ret))
232 			return pygobject_new(G_OBJECT(ret));
233 	}
234 
235 	Py_RETURN_NONE;
236 }
237 
238 
239 static PyObject *
UiUtils_is_keyval_enter_or_return(PyObject * module,PyObject * args,PyObject * kwargs)240 UiUtils_is_keyval_enter_or_return(PyObject *module, PyObject *args, PyObject *kwargs)
241 {
242 	guint kv;
243 	static gchar *kwlist[] = { "keyval", NULL };
244 
245 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "I", kwlist, &kv))
246 	{
247 		if (ui_is_keyval_enter_or_return(kv))
248 			Py_RETURN_TRUE;
249 		else
250 			Py_RETURN_FALSE;
251 	}
252 
253 	Py_RETURN_NONE;
254 }
255 
256 
257 /* FIXME: ui_menu_add_document_items() and ui_menu_add_document_items_sorted()
258  * skipped because I don't know how to pass GCallbacks between Python and C,
259  * if it's even possible. */
260 
261 
262  static PyObject *
UiUtils_path_box_new(PyObject * module,PyObject * args,PyObject * kwargs)263  UiUtils_path_box_new(PyObject *module, PyObject *args, PyObject *kwargs)
264  {
265 	 gint act;
266 	 PyObject *py_ent = NULL;
267 	 GObject *ent = NULL;
268 	 GtkWidget *pbox = NULL;
269 	 const gchar *title = NULL;
270 	 static gchar *kwlist[] = { "title", "action", "entry", NULL };
271 
272 	 if (PyArg_ParseTupleAndKeywords(args, kwargs, "ziO", kwlist,
273 		&title, &act, &py_ent))
274 	{
275 		GOB_CHECK(py_ent, 3);
276 		ent = pygobject_get(py_ent);
277 		GOB_TYPE_CHECK(ent, GTK_TYPE_ENTRY, 3);
278 		pbox = ui_path_box_new(title, (GtkFileChooserAction) act, GTK_ENTRY(ent));
279 		if (GTK_IS_WIDGET(pbox))
280 			return pygobject_new(G_OBJECT(pbox));
281 	}
282 
283 
284 	 Py_RETURN_NONE;
285  }
286 
287 
288  static PyObject *
UiUtils_progress_bar_start(PyObject * module,PyObject * args,PyObject * kwargs)289  UiUtils_progress_bar_start(PyObject *module, PyObject *args, PyObject *kwargs)
290  {
291 	 const gchar *text = NULL;
292 	 static gchar *kwlist[] = { "text", NULL };
293 
294 	 if (PyArg_ParseTupleAndKeywords(args, kwargs, "z", kwlist, &text))
295 		 ui_progress_bar_start(text);
296 
297 	 Py_RETURN_NONE;
298  }
299 
300 
301  static PyObject *
UiUtils_progress_bar_stop(PyObject * module)302  UiUtils_progress_bar_stop(PyObject *module)
303  {
304 	 ui_progress_bar_stop();
305 	 Py_RETURN_NONE;
306  }
307 
308 
309  static PyObject *
UiUtils_set_statusbar(PyObject * module,PyObject * args,PyObject * kwargs)310  UiUtils_set_statusbar(PyObject *module, PyObject *args, PyObject *kwargs)
311  {
312 	 gint log = 0;
313 	 const gchar *text = NULL;
314 	 static gchar *kwlist[] = { "text", "log", NULL };
315 
316 	 if (PyArg_ParseTupleAndKeywords(args, kwargs, "s|i", kwlist, &text, &log))
317 		 ui_set_statusbar((gboolean) log, "%s", text);
318 
319 	 Py_RETURN_NONE;
320  }
321 
322 
323  /* FIXME: ui_table_add_row() skipped since it's probably not useful and
324   * not well documented. */
325 
326 
327 static PyObject *
UiUtils_widget_modify_font_from_string(PyObject * module,PyObject * args,PyObject * kwargs)328 UiUtils_widget_modify_font_from_string(PyObject *module, PyObject *args, PyObject *kwargs)
329 {
330 	PyObject *py_widget = NULL;
331 	GObject *widget = NULL;
332 	const gchar *font_str = NULL;
333 	static gchar *kwlist[] = { "widget", "font_str", NULL };
334 
335 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "Os", kwlist, &py_widget, &font_str))
336 	{
337 		GOB_CHECK(py_widget, 1);
338 		widget = pygobject_get(py_widget);
339 		GOB_TYPE_CHECK(widget, GTK_TYPE_WIDGET, 1);
340 		ui_widget_modify_font_from_string(GTK_WIDGET(widget), font_str);
341 	}
342 
343 	Py_RETURN_NONE;
344 }
345 
346 
347 /* Deprecated in Geany 0.21 in favour of gtk_widget_set_tooltip_text() */
348 #if 0
349 static PyObject *
350 UiUtils_widget_set_tooltip_text(PyObject *module, PyObject *args, PyObject *kwargs)
351 {
352 	PyObject *py_widget = NULL;
353 	GObject *widget = NULL;
354 	const gchar *text = NULL;
355 	static gchar *kwlist[] = { "widget", "text", NULL };
356 
357 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "Os", kwlist, &py_widget, &text))
358 	{
359 		GOB_CHECK(py_widget, 1);
360 		widget = pygobject_get(py_widget);
361 		GOB_TYPE_CHECK(widget, GTK_TYPE_WIDGET, 1);
362 		gtk_widget_set_tooltip_text(GTK_WIDGET(widget), text);
363 	}
364 
365 	Py_RETURN_NONE;
366 }
367 #endif
368 
369 
370 static PyMethodDef UiUtilsModule_methods[] = {
371 	{ "hookup_widget", (PyCFunction) UiUtils_hookup_widget, METH_KEYWORDS,
372 		"Sets a name to lookup widget from owner." },
373 	{ "lookup_widget", (PyCFunction) UiUtils_lookup_widget, METH_KEYWORDS,
374 		"Returns a widget from a name in a component, usually created "
375 		"by Glade.  Call it with the toplevel widget in the component "
376 		"(ie. a window or dialog), or alternatively any widget in the "
377 		"component, and the name of the widget you want returned."},
378 	{ "add_document_sensitive", (PyCFunction) UiUtils_add_document_sensitive, METH_KEYWORDS,
379 		"Adds a widget to the list of widgets that should be set "
380 		"sensitive or insensitive depending if any documents are open." },
381 	{ "button_new_with_image", (PyCFunction) UiUtils_button_new_with_image, METH_KEYWORDS,
382 		"Creates a gtk.Button with custom text and a stock image similar "
383 		"to gtk.Button() initializer." },
384 	{ "combo_box_add_to_history", (PyCFunction) UiUtils_combo_box_add_to_history, METH_KEYWORDS,
385 		"Prepends text to the dropdown list, removing a duplicate element "
386 		"in the list if found.  Also ensures there are less than the "
387 		"specified number of elements in the history." },
388 	{ "dialog_vbox_new", (PyCFunction) UiUtils_dialog_vbox_new, METH_KEYWORDS,
389 		"Makes a fixed border for dialogs without increasing the button "
390 		"box border size." },
391 	{ "entry_add_clear_icon", (PyCFunction) UiUtils_entry_add_clear_icon, METH_KEYWORDS,
392 		"Adds a small clear icon to the right end of the passed in entry. "
393 		"A callback to clear the contents of the gtk.Entry is automatically "
394 		"added." },
395 	{ "frame_new_with_alignement", (PyCFunction) UiUtils_frame_new_with_alignment, METH_KEYWORDS,
396 		"Creates a GNOME HIG-style frame with no border and indented "
397 		"child alignment.  Returns a tuple with the gtk.Frame as the first "
398 		"element and the gtk.Alignment as the second element." },
399 	{ "get_gtk_settings_integer", (PyCFunction) UiUtils_get_gtk_settings_integer, METH_KEYWORDS,
400 		"Reads an integer from the GTK default settings registry." },
401 	{ "image_menu_item_new", (PyCFunction) UiUtils_image_menu_item_new, METH_KEYWORDS,
402 		"Creates a gtk.ImageMenuItem with a stock image and a custom label." },
403 	{ "is_keyval_enter_or_return", (PyCFunction) UiUtils_is_keyval_enter_or_return, METH_KEYWORDS,
404 		"Checks whether the passed in keyval is the Enter or Returns key. " },
405 	{ "path_box_new", (PyCFunction) UiUtils_path_box_new, METH_KEYWORDS,
406 		"Creates a gtk.HBox with entry packed into it and an open button "
407 		"which runs a file chooser, replacing entry text (if successful) "
408 		"with the path returned from the gtk.FileChooser." },
409 	{ "progress_bar_start", (PyCFunction) UiUtils_progress_bar_start, METH_KEYWORDS,
410 		"Starts a constantly pulsing progressbar in the right corner of "
411 		"the statusbar (if the status bar is visible)." },
412 	{ "progress_bar_stop", (PyCFunction) UiUtils_progress_bar_stop, METH_NOARGS,
413 		"Stops a running progress bar and hides the widget again." },
414 	{ "set_statusbar", (PyCFunction) UiUtils_set_statusbar, METH_KEYWORDS,
415 		"Displays text on the statusbar." },
416 	{ "widget_modify_font_from_string", (PyCFunction) UiUtils_widget_modify_font_from_string, METH_KEYWORDS,
417 		"Modifies the font of a widget using modify_font() automatically "
418 		"parsing the Pango font description string in font_str." },
419 	{ NULL },
420 };
421 
422 
initui_utils(void)423 PyMODINIT_FUNC initui_utils(void)
424 {
425 	PyObject *m;
426 
427 	init_pygobject();
428 	init_pygtk();
429 	m = PyImport_ImportModule("gobject");
430 
431 	if (m)
432 	{
433 		PyGObject_Type = (PyTypeObject *) PyObject_GetAttrString(m, "GObject");
434 		Py_XDECREF(m);
435 	}
436 
437 	InterfacePrefsType.tp_new = PyType_GenericNew;
438 	if (PyType_Ready(&InterfacePrefsType) < 0)
439 		return;
440 
441 	MainWidgetsType.tp_new = PyType_GenericNew;
442 	if (PyType_Ready(&MainWidgetsType) < 0)
443 		return;
444 
445 	m = Py_InitModule3("ui_utils", UiUtilsModule_methods,
446 			"User interface information and utilities.");
447 
448 	Py_INCREF(&InterfacePrefsType);
449 	PyModule_AddObject(m, "InterfacePrefs", (PyObject *) &InterfacePrefsType);
450 
451 	Py_INCREF(&MainWidgetsType);
452 	PyModule_AddObject(m, "MainWidgets", (PyObject *) &MainWidgetsType);
453 }
454