1 /* guile-gnome
2  * Copyright (C) 2003, 2010 Andy Wingo <wingo at pobox dot com>
3  *
4  * gtk-support.c: Customizations for guile-gtk
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, contact:
18  *
19  * Free Software Foundation           Voice:  +1-617-542-5942
20  * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652
21  * Boston, MA  02111-1307,  USA       gnu@gnu.org
22  *
23  * Based on work Copyright (C) 2003 James Henstridge <james@daa.com.au>
24  */
25 
26 #include <string.h>
27 #include "guile-support.h"
28 #include "gtk-support.h"
29 
30 
31 /* python-gtk defines a nice series of classes to access rows as elements of a
32    sequence and to access their fields via a sequence interface. I wish we could
33    do that in guile. Food for thought. */
34 
35 SCM
guile_gtk_tree_path_to_scm(GtkTreePath * path)36 guile_gtk_tree_path_to_scm (GtkTreePath *path)
37 {
38     gint len, i, *indices;
39     SCM ret;
40 
41     len = gtk_tree_path_get_depth(path);
42     indices = gtk_tree_path_get_indices(path);
43     ret = SCM_EOL;
44     for (i = len; i > 0; i--)
45 	ret = scm_cons (scm_from_int (indices[i-1]), ret);
46     return ret;
47 }
48 
49 GtkTreePath*
guile_gtk_scm_to_tree_path(SCM scm)50 guile_gtk_scm_to_tree_path (SCM scm)
51 #define FUNC_NAME "guile-gtk-scm-to-tree-path"
52 {
53     if (scm_is_string (scm)) {
54         GtkTreePath *ret;
55         scm_dynwind_begin (0);
56         ret = gtk_tree_path_new_from_string (scm_to_locale_string_dynwind (scm));
57         scm_dynwind_end ();
58         return ret;
59     } else if (scm_is_unsigned_integer (scm, 0, SCM_T_UINT32_MAX)) {
60         GtkTreePath *ret = gtk_tree_path_new ();
61         gtk_tree_path_append_index (ret, scm_to_uint (scm));
62         return ret;
63     } else if (SCM_EQ_P (scm, SCM_EOL)) {
64         return NULL;
65     } else if (SCM_NFALSEP (scm_list_p (scm))) {
66 	GtkTreePath *path = gtk_tree_path_new ();
67 
68         for (; !SCM_EQ_P (scm, SCM_EOL); scm = SCM_CDR (scm))
69             gtk_tree_path_append_index (path, scm_to_uint (scm_car (scm)));
70 
71 	return path;
72     }
73     return NULL;
74 }
75 #undef FUNC_NAME
76 
77 #define GET_ACTION_STR(var,n)\
78 do {\
79     if (n < l) {\
80         SCM x = scm_list_ref (entry, scm_from_uint16 (n));              \
81         SCM_ASSERT (scm_is_false (x) || scm_is_string (x), entry,\
82                     2, FUNC_NAME);\
83         var = scm_is_false (x) ? NULL : scm_to_locale_string_dynwind (x);\
84     } else {\
85         var = NULL;\
86     }\
87 }while (0)
88 #define GET_ACTION_BOOL(var,n)\
89 do {\
90     if (n < l) {\
91         var = SCM_NFALSEP (scm_list_ref (entry, scm_from_uint16 (n)));  \
92     } else {\
93         var = FALSE;\
94     }\
95 }while (0)
96 #define GET_ACTION_INT(var,n)\
97 do {\
98     if (n < l) {\
99         SCM x = scm_list_ref (entry, scm_from_uint16 (n));              \
100         SCM_ASSERT (scm_is_signed_integer (x, SCM_T_INT32_MIN,          \
101                                            SCM_T_INT32_MAX),            \
102                     entry, 2, FUNC_NAME);\
103         var = scm_to_int (x);\
104     } else {\
105         var = 0;\
106     }\
107 }while (0)
108 
109 void
_wrap_gtk_action_group_add_actions(GtkActionGroup * action_group,SCM entries)110 _wrap_gtk_action_group_add_actions (GtkActionGroup *action_group,
111                                     SCM entries)
112 #define FUNC_NAME "gtk-action-group-add-actions"
113 {
114     static SCM connect = SCM_BOOL_F;
115     SCM entry, x;
116     GtkAction *action;
117     char *name, *stock_id, *label, *accelerator, *tooltip;
118     gint l;
119 
120     SCM_VALIDATE_NONEMPTYLIST (1, entries);
121 
122     if (SCM_FALSEP (connect))
123         connect = SCM_VARIABLE_REF (scm_c_module_lookup
124                                     (scm_c_resolve_module ("gnome gobject"),
125                                      "gtype-instance-signal-connect"));
126 
127     scm_dynwind_begin (0);
128 
129     for (; SCM_NNULLP (entries); entries = SCM_CDR (entries)) {
130         entry = SCM_CAR (entries);
131         SCM_VALIDATE_NONEMPTYLIST (1, entry);
132         l = scm_ilength (entry);
133         SCM_ASSERT (l > 0 && l <= 6, entry, 2, FUNC_NAME);
134 
135         GET_ACTION_STR (name, 0);
136         SCM_ASSERT (name != NULL, entry, 2, FUNC_NAME);
137         GET_ACTION_STR (stock_id, 1);
138         GET_ACTION_STR (label, 2);
139         GET_ACTION_STR (accelerator, 3);
140         GET_ACTION_STR (tooltip, 4);
141 
142         action = g_object_new (GTK_TYPE_ACTION,
143                                "name", name, "label", label, "tooltip", tooltip,
144                                "stock_id", stock_id, NULL);
145 
146         if (5 < l && SCM_NFALSEP ((x = scm_list_ref (entry, scm_from_uint16 (5)))))
147             scm_call_3 (connect,
148                         scm_c_gtype_instance_to_scm ((GTypeInstance*)action),
149                         scm_from_locale_symbol ("activate"), x);
150 
151         gtk_action_group_add_action_with_accel (action_group, action, accelerator);
152         g_object_unref (action);
153     }
154 
155     scm_dynwind_end ();
156 }
157 #undef FUNC_NAME
158 
159 void
_wrap_gtk_action_group_add_toggle_actions(GtkActionGroup * action_group,SCM entries)160 _wrap_gtk_action_group_add_toggle_actions (GtkActionGroup *action_group,
161                                            SCM entries)
162 #define FUNC_NAME "gtk-action-group-add-toggle-actions"
163 {
164     static SCM connect = SCM_BOOL_F;
165     SCM entry, x;
166     GtkToggleAction *action;
167     char *name, *stock_id, *label, *accelerator, *tooltip;
168     gboolean is_active;
169     gint l;
170 
171     SCM_VALIDATE_NONEMPTYLIST (1, entries);
172 
173     if (SCM_FALSEP (connect))
174         connect = SCM_VARIABLE_REF (scm_c_module_lookup
175                                     (scm_c_resolve_module ("gnome gobject"),
176                                      "gtype-instance-signal-connect"));
177 
178     scm_dynwind_begin (0);
179 
180     for (; SCM_NNULLP (entries); entries = SCM_CDR (entries)) {
181         entry = SCM_CAR (entries);
182         SCM_VALIDATE_NONEMPTYLIST (1, entry);
183         l = scm_ilength (entry);
184         SCM_ASSERT (l > 0 && l <= 7, entry, 2, FUNC_NAME);
185 
186         GET_ACTION_STR (name, 0);
187         SCM_ASSERT (name != NULL, entry, 2, FUNC_NAME);
188         GET_ACTION_STR (stock_id, 1);
189         GET_ACTION_STR (label, 2);
190         GET_ACTION_STR (accelerator, 3);
191         GET_ACTION_STR (tooltip, 4);
192 
193         action = g_object_new (GTK_TYPE_TOGGLE_ACTION,
194                                "name", name, "label", label, "tooltip", tooltip,
195                                "stock_id", stock_id, NULL);
196 
197         if (5 < l && SCM_NFALSEP ((x = scm_list_ref (entry, scm_from_uint16 (5)))))
198             scm_call_3 (connect,
199                         scm_c_gtype_instance_to_scm ((GTypeInstance*)action),
200                         scm_from_locale_symbol ("activate"), x);
201 
202         GET_ACTION_BOOL (is_active, 6);
203         gtk_toggle_action_set_active (action, is_active);
204 
205         gtk_action_group_add_action_with_accel (action_group, GTK_ACTION (action), accelerator);
206         g_object_unref (action);
207     }
208 
209     scm_dynwind_end ();
210 }
211 #undef FUNC_NAME
212 
213 static void
action_group_radio_actions_callback(GtkAction * action,GtkRadioAction * current,gpointer user_data)214 action_group_radio_actions_callback(GtkAction *action,
215                                     GtkRadioAction *current,
216                                     gpointer user_data)
217 {
218     SCM proc;
219 
220     proc = GPOINTER_TO_SCM (user_data);
221 
222     scm_call_2 (proc,
223                 scm_c_gtype_instance_to_scm ((GTypeInstance*) action),
224                 scm_c_gtype_instance_to_scm ((GTypeInstance*) current));
225 
226 }
227 
228 void
_wrap_gtk_action_group_add_radio_actions(GtkActionGroup * action_group,SCM entries,gint value,SCM on_change)229 _wrap_gtk_action_group_add_radio_actions (GtkActionGroup *action_group,
230                                           SCM entries,
231                                           gint value,
232                                           SCM on_change)
233 #define FUNC_NAME "gtk-action-group-add-radio-actions"
234 {
235     GtkRadioActionEntry *raes;
236     SCM entry;
237     gint len, i, l;
238 
239     SCM_VALIDATE_NONEMPTYLIST (1, entries);
240     SCM_VALIDATE_PROC (4, on_change);
241 
242     len = scm_ilength (entries);
243     raes = g_new0 (GtkRadioActionEntry, len);
244 
245     scm_dynwind_begin (0);
246 
247     for (i=0; SCM_NNULLP (entries); entries = SCM_CDR (entries), i++) {
248         entry = SCM_CAR (entries);
249         SCM_VALIDATE_NONEMPTYLIST (1, entry);
250         l = scm_ilength (entry);
251         SCM_ASSERT (l == 6, entry, 2, FUNC_NAME);
252 
253         GET_ACTION_STR (raes[i].name, 0);
254         SCM_ASSERT (raes[i].name != NULL, entry, 2, FUNC_NAME);
255         GET_ACTION_STR (raes[i].stock_id, 1);
256         GET_ACTION_STR (raes[i].label, 2);
257         GET_ACTION_STR (raes[i].accelerator, 3);
258         GET_ACTION_STR (raes[i].tooltip, 4);
259         GET_ACTION_INT (raes[i].value, 5);
260     }
261 
262     gtk_action_group_add_radio_actions (action_group, raes, len, value,
263                                         G_CALLBACK (action_group_radio_actions_callback),
264                                         SCM_TO_GPOINTER (on_change));
265 
266     scm_dynwind_end ();
267 
268     g_free (raes);
269 }
270 #undef FUNC_NAME
271 
272 void
_wrap_gtk_clipboard_set_text(GtkClipboard * clipboard,const gchar * text)273 _wrap_gtk_clipboard_set_text (GtkClipboard *clipboard, const gchar *text)
274 {
275     gtk_clipboard_set_text (clipboard, text, strlen (text));
276 }
277 
278 gint
_wrap_gtk_editable_insert_text(GtkEditable * editable,const gchar * text,gint pos)279 _wrap_gtk_editable_insert_text (GtkEditable *editable, const gchar *text, gint pos)
280 {
281     gtk_editable_insert_text (editable, text, strlen (text), &pos);
282     return pos;
283 }
284 
285 GtkWidget*
_wrap_gtk_dialog_get_vbox(GtkDialog * dialog)286 _wrap_gtk_dialog_get_vbox (GtkDialog *dialog)
287 {
288     return dialog->vbox;
289 }
290 
291 GtkWidget*
_wrap_gtk_dialog_get_action_area(GtkDialog * dialog)292 _wrap_gtk_dialog_get_action_area (GtkDialog *dialog)
293 {
294     return dialog->action_area;
295 }
296 
297 GtkWidget*
_wrap_gtk_color_selection_dialog_get_colorsel(GtkColorSelectionDialog * dialog)298 _wrap_gtk_color_selection_dialog_get_colorsel (GtkColorSelectionDialog *dialog)
299 {
300     return dialog->colorsel;
301 }
302 
303 GtkWidget*
_wrap_gtk_color_selection_dialog_get_ok_button(GtkColorSelectionDialog * dialog)304 _wrap_gtk_color_selection_dialog_get_ok_button (GtkColorSelectionDialog *dialog)
305 {
306     return dialog->ok_button;
307 }
308 
309 GtkWidget*
_wrap_gtk_color_selection_dialog_get_cancel_button(GtkColorSelectionDialog * dialog)310 _wrap_gtk_color_selection_dialog_get_cancel_button (GtkColorSelectionDialog *dialog)
311 {
312     return dialog->cancel_button;
313 }
314 
315 GtkWidget*
_wrap_gtk_color_selection_dialog_get_help_button(GtkColorSelectionDialog * dialog)316 _wrap_gtk_color_selection_dialog_get_help_button (GtkColorSelectionDialog *dialog)
317 {
318     return dialog->help_button;
319 }
320 
321 GtkWidget*
_wrap_gtk_file_selection_get_ok_button(GtkFileSelection * selection)322 _wrap_gtk_file_selection_get_ok_button (GtkFileSelection* selection)
323 {
324     return selection->ok_button;
325 }
326 
327 GtkWidget*
_wrap_gtk_file_selection_get_cancel_button(GtkFileSelection * selection)328 _wrap_gtk_file_selection_get_cancel_button (GtkFileSelection* selection)
329 {
330     return selection->cancel_button;
331 }
332 
333 GtkListStore*
_wrap_gtk_list_store_new(SCM col_types)334 _wrap_gtk_list_store_new (SCM col_types)
335 #define FUNC_NAME "gtk-list-store-new"
336 {
337     GType *col_gtypes;
338     gint len, i;
339     GtkListStore *ret;
340 
341     SCM_VALIDATE_NONEMPTYLIST (1, col_types);
342     len = scm_ilength (col_types);
343     col_gtypes = g_new (GType, len);
344 
345     for (i=0; i<len; i++) {
346         SCM v = SCM_CAR (col_types);
347         SCM_VALIDATE_GTYPE_CLASS_COPY (1, v, col_gtypes[i]);
348         col_types = SCM_CDR (col_types);
349     }
350 
351     ret = gtk_list_store_newv (len, col_gtypes);
352     g_free (col_gtypes);
353     return ret;
354 }
355 #undef FUNC_NAME
356 
357 void
_wrap_gtk_list_store_set_value(GtkListStore * store,GtkTreeIter * iter,gint column,SCM scm)358 _wrap_gtk_list_store_set_value (GtkListStore *store, GtkTreeIter *iter,
359                                 gint column, SCM scm)
360 {
361     GValue *value;
362     GType type;
363 
364     SCM_ASSERT (column < gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)),
365                 scm_from_int (column), 3, "gtk-list-store-set-value");
366     type = gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), column);
367     value = scm_c_scm_to_gvalue (type, scm);
368 
369     gtk_list_store_set_value (store, iter, column, value);
370     g_value_unset (value);
371     g_free (value);
372 }
373 
374 GtkTreeIter*
_wrap_gtk_list_store_remove(GtkListStore * store,GtkTreeIter * iter)375 _wrap_gtk_list_store_remove (GtkListStore *store, GtkTreeIter *iter)
376 {
377     if (!gtk_list_store_remove (store, iter))
378         return NULL;
379     return gtk_tree_iter_copy (iter);
380 }
381 
382 GtkTreeIter*
_wrap_gtk_list_store_insert(GtkListStore * store,gint position)383 _wrap_gtk_list_store_insert (GtkListStore *store, gint position)
384 {
385     GtkTreeIter new;
386     gtk_list_store_insert (store, &new, position);
387     return gtk_tree_iter_copy (&new);
388 }
389 
390 GtkTreeIter*
_wrap_gtk_list_store_insert_before(GtkListStore * store,GtkTreeIter * sibling)391 _wrap_gtk_list_store_insert_before (GtkListStore *store, GtkTreeIter *sibling)
392 {
393     GtkTreeIter new;
394     gtk_list_store_insert_before (store, &new, sibling);
395     return gtk_tree_iter_copy (&new);
396 }
397 
398 GtkTreeIter*
_wrap_gtk_list_store_insert_after(GtkListStore * store,GtkTreeIter * sibling)399 _wrap_gtk_list_store_insert_after (GtkListStore *store, GtkTreeIter *sibling)
400 {
401     GtkTreeIter new;
402     gtk_list_store_insert_after (store, &new, sibling);
403     return gtk_tree_iter_copy (&new);
404 }
405 
406 GtkTreeIter*
_wrap_gtk_list_store_prepend(GtkListStore * store)407 _wrap_gtk_list_store_prepend (GtkListStore *store)
408 {
409     GtkTreeIter new;
410     gtk_list_store_prepend (store, &new);
411     return gtk_tree_iter_copy (&new);
412 }
413 
414 GtkTreeIter*
_wrap_gtk_list_store_append(GtkListStore * store)415 _wrap_gtk_list_store_append (GtkListStore *store)
416 {
417     GtkTreeIter new;
418     gtk_list_store_append (store, &new);
419     return gtk_tree_iter_copy (&new);
420 }
421 
422 static void
menu_position_fn(GtkMenu * menu,gint * x,gint * y,gboolean * push_in,gpointer data)423 menu_position_fn (GtkMenu *menu, gint *x, gint *y, gboolean *push_in,
424                   gpointer data)
425 {
426     SCM ret, proc = GPOINTER_TO_SCM (data);
427 
428     ret = scm_call_1 (proc, scm_c_gtype_instance_to_scm (menu));
429 
430     *x = scm_to_int32 (scm_car (ret));
431     *y = scm_to_int32 (scm_cadr (ret));
432     *push_in = scm_is_true (scm_caddr (ret));
433 }
434 
435 void
_wrap_gtk_menu_popup(GtkMenu * menu,GtkWidget * parent_menu_shell,GtkWidget * parent_menu_item,SCM func,guint button,guint32 activate_time)436 _wrap_gtk_menu_popup (GtkMenu *menu, GtkWidget *parent_menu_shell,
437                       GtkWidget *parent_menu_item, SCM func,
438                       guint button, guint32 activate_time)
439 {
440     if (scm_is_true (func))
441         gtk_menu_popup (menu, parent_menu_shell, parent_menu_item,
442                         menu_position_fn, SCM_TO_GPOINTER (func),
443                         button, activate_time);
444     else
445         gtk_menu_popup (menu, parent_menu_shell, parent_menu_item,
446                         NULL, NULL, button, activate_time);
447 }
448 
449 /* FIXME: is this still necessary? */
450 SCM
_wrap_gtk_message_dialog_new(GtkWindow * parent,GtkDialogFlags flags,GtkMessageType type,GtkButtonsType buttons,const gchar * text)451 _wrap_gtk_message_dialog_new (GtkWindow* parent, GtkDialogFlags flags, GtkMessageType type,
452                               GtkButtonsType buttons, const gchar *text)
453 {
454     GtkWidget *w = gtk_message_dialog_new (parent, flags, type, buttons, "%s", text);
455     g_object_ref (w); /* the initial ref belongs to GTK+ */
456     return scm_c_gtype_instance_to_scm (w);
457 }
458 
459 gchar*
_gtk_selection_data_get_as_string(GtkSelectionData * data)460 _gtk_selection_data_get_as_string (GtkSelectionData *data)
461 {
462     return g_strndup ((gchar *)data->data, data->length);
463 }
464 
465 void
_wrap_gtk_stock_add(SCM items)466 _wrap_gtk_stock_add (SCM items)
467 #define FUNC_NAME "gtk-stock-add"
468 {
469     int len, i;
470     GtkStockItem *stockitems;
471 
472     SCM_ASSERT (SCM_NIMP (items) && SCM_CONSP (items) && SCM_NNULLP (items),
473                 items, 1, FUNC_NAME);
474 
475     len = scm_ilength (items);
476 
477     stockitems = g_new0 (GtkStockItem, len);
478 
479     scm_dynwind_begin (0);
480 
481     for (i = 0; i < len ; i++) {
482         SCM item = SCM_CAR(items);
483 
484         SCM_ASSERT (SCM_NIMP (item) && SCM_CONSP (item) &&
485                     scm_ilength(item) == 5 &&
486                     scm_is_string (SCM_CAR (item)) &&
487                     scm_is_string (SCM_CADR (item)) &&
488                     scm_is_unsigned_integer (SCM_CADDR (item), 0, SCM_T_UINT32_MAX) &&
489                     scm_is_unsigned_integer (SCM_CADDDR (item), 0, SCM_T_UINT32_MAX),
490                     item, 1, FUNC_NAME);
491 
492         stockitems[i].stock_id = scm_to_locale_string_dynwind (SCM_CAR (item));
493         stockitems[i].label    = scm_to_locale_string_dynwind (SCM_CADR (item));
494         stockitems[i].modifier = scm_to_uint (SCM_CADDR (item));
495         stockitems[i].keyval   = scm_to_uint (SCM_CADDDR (item));
496         stockitems[i].translation_domain =
497             scm_is_string (SCM_CADDDR (SCM_CDR (item))) ?
498             scm_to_locale_string_dynwind (SCM_CADDDR (SCM_CDR (item))) : NULL;
499 
500         items = SCM_CDR(items);
501     }
502 
503     gtk_stock_add (stockitems, len);
504     scm_dynwind_end ();
505     g_free(stockitems);
506 }
507 #undef FUNC_NAME
508 
509 SCM
_wrap_gtk_stock_lookup(const gchar * stock_id)510 _wrap_gtk_stock_lookup (const gchar *stock_id)
511 #define FUNC_NAME "gtk-stock-add"
512 {
513     GtkStockItem item;
514 
515     if (gtk_stock_lookup (stock_id, &item)) {
516         return SCM_LIST5 (scm_from_locale_string (item.stock_id),
517                           scm_from_locale_string (item.label),
518                           scm_from_uint (item.modifier),
519                           scm_from_uint (item.keyval),
520                           scm_from_locale_string (item.translation_domain));
521     }
522 
523     return SCM_BOOL_F;
524 
525 }
526 #undef FUNC_NAME
527 
528 void
_wrap_gtk_text_buffer_set_text(GtkTextBuffer * buf,SCM stext)529 _wrap_gtk_text_buffer_set_text (GtkTextBuffer *buf, SCM stext)
530 #define FUNC_NAME "gtk-text-buffer-set-text"
531 {
532     char *utf8_text;
533     size_t utf8_len;
534 
535     SCM_VALIDATE_STRING (2, stext);
536     scm_dynwind_begin (0);
537     utf8_text = scm_to_utf8_stringn_dynwind (stext, &utf8_len);
538     gtk_text_buffer_set_text (buf, utf8_text, utf8_len);
539     scm_dynwind_end ();
540 }
541 #undef FUNC_NAME
542 
543 void
_wrap_gtk_text_buffer_insert(GtkTextBuffer * buf,GtkTextIter * iter,SCM stext)544 _wrap_gtk_text_buffer_insert (GtkTextBuffer *buf, GtkTextIter* iter, SCM stext)
545 #define FUNC_NAME "gtk-text-buffer-insert"
546 {
547     char *utf8_text;
548     size_t utf8_len;
549 
550     SCM_VALIDATE_STRING (3, stext);
551     scm_dynwind_begin (0);
552     utf8_text = scm_to_utf8_stringn_dynwind (stext, &utf8_len);
553     gtk_text_buffer_insert (buf, iter, utf8_text, utf8_len);
554     scm_dynwind_end ();
555 }
556 #undef FUNC_NAME
557 
558 void
_wrap_gtk_text_buffer_insert_at_cursor(GtkTextBuffer * buf,SCM stext)559 _wrap_gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buf, SCM stext)
560 #define FUNC_NAME "gtk-text-buffer-insert-at-cursor"
561 {
562     char *utf8_text;
563     size_t utf8_len;
564 
565     SCM_VALIDATE_STRING (2, stext);
566     scm_dynwind_begin (0);
567     utf8_text = scm_to_utf8_stringn_dynwind (stext, &utf8_len);
568     gtk_text_buffer_insert_at_cursor (buf, utf8_text, utf8_len);
569     scm_dynwind_end ();
570 }
571 #undef FUNC_NAME
572 
573 gboolean
_wrap_gtk_text_buffer_insert_interactive(GtkTextBuffer * buf,GtkTextIter * iter,SCM stext,gboolean default_editable)574 _wrap_gtk_text_buffer_insert_interactive (GtkTextBuffer *buf, GtkTextIter* iter,
575                                                    SCM stext, gboolean default_editable)
576 #define FUNC_NAME "gtk-text-buffer-insert-interactive"
577 {
578     char *utf8_text;
579     size_t utf8_len;
580     gboolean ret;
581 
582     SCM_VALIDATE_STRING (3, stext);
583     scm_dynwind_begin (0);
584     utf8_text = scm_to_utf8_stringn_dynwind (stext, &utf8_len);
585     ret = gtk_text_buffer_insert_interactive (buf, iter, utf8_text, utf8_len,
586 					      default_editable);
587     scm_dynwind_end ();
588     return ret;
589 }
590 #undef FUNC_NAME
591 
592 gboolean
_wrap_gtk_text_buffer_insert_interactive_at_cursor(GtkTextBuffer * buf,SCM stext,gboolean default_editable)593 _wrap_gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buf, SCM stext,
594                                                     gboolean default_editable)
595 #define FUNC_NAME "gtk-text-buffer-insert-interactive-at-cursor"
596 {
597     char *utf8_text;
598     size_t utf8_len;
599     gboolean ret;
600 
601     SCM_VALIDATE_STRING (2, stext);
602     scm_dynwind_begin (0);
603     utf8_text = scm_to_utf8_stringn_dynwind (stext, &utf8_len);
604     ret = gtk_text_buffer_insert_interactive_at_cursor (buf, utf8_text, utf8_len,
605                                                         default_editable);
606     scm_dynwind_end ();
607     return ret;
608 }
609 #undef FUNC_NAME
610 
611 void
_wrap_gtk_text_buffer_insert_with_tags(GtkTextBuffer * buf,GtkTextIter * iter,SCM stext,GList * tag_list)612 _wrap_gtk_text_buffer_insert_with_tags (GtkTextBuffer *buf, GtkTextIter* iter,
613                                         SCM stext, GList* tag_list)
614 #define FUNC_NAME "gtk-text-buffer-insert-with-tags"
615 {
616     char *utf8_text;
617     size_t utf8_len;
618     GtkTextIter start;
619     GList *walk;
620     gint start_offset;
621 
622     /* based on gtktextbuffer.c (LGPL) */
623 
624     SCM_VALIDATE_STRING (3, stext);
625     scm_dynwind_begin (0);
626     start_offset = gtk_text_iter_get_offset (iter);
627     utf8_text = scm_to_utf8_stringn_dynwind (stext, &utf8_len);
628     gtk_text_buffer_insert (buf, iter, utf8_text, utf8_len);
629     gtk_text_buffer_get_iter_at_offset (buf, &start, start_offset);
630 
631     for (walk = tag_list; walk; walk = walk->next)
632         gtk_text_buffer_apply_tag (buf, (GtkTextTag*)walk->data, &start, iter);
633     g_list_free (tag_list);
634     scm_dynwind_end ();
635 }
636 #undef FUNC_NAME
637 
638 void
_wrap_gtk_text_buffer_insert_with_tags_by_name(GtkTextBuffer * buf,GtkTextIter * iter,SCM stext,GList * tag_list)639 _wrap_gtk_text_buffer_insert_with_tags_by_name (GtkTextBuffer *buf, GtkTextIter* iter,
640                                                 SCM stext, GList* tag_list)
641 #define FUNC_NAME "gtk-text-buffer-insert-with-tags-by-name"
642 {
643     char *utf8_text;
644     size_t utf8_len;
645     GtkTextIter start;
646     GList *walk;
647     gint start_offset;
648 
649     /* based on gtktextbuffer.c (LGPL) */
650 
651     SCM_VALIDATE_STRING (3, stext);
652     scm_dynwind_begin (0);
653     start_offset = gtk_text_iter_get_offset (iter);
654     utf8_text = scm_to_utf8_stringn_dynwind (stext, &utf8_len);
655     gtk_text_buffer_insert (buf, iter, utf8_text, utf8_len);
656     gtk_text_buffer_get_iter_at_offset (buf, &start, start_offset);
657 
658     for (walk = tag_list; walk; walk = walk->next)
659         gtk_text_buffer_apply_tag (buf,
660                                    gtk_text_tag_table_lookup (buf->tag_table,
661                                                               (gchar*)walk->data),
662                                    &start, iter);
663     g_list_free (tag_list);
664     scm_dynwind_end ();
665 }
666 #undef FUNC_NAME
667 
668 GtkTextIter*
_wrap_gtk_text_buffer_get_iter_at_line_offset(GtkTextBuffer * buf,gint line_number,gint char_offset)669 _wrap_gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buf, gint line_number,
670                                                gint char_offset)
671 {
672     GtkTextIter iter;
673     gtk_text_buffer_get_iter_at_line_offset (buf, &iter, line_number, char_offset);
674     return gtk_text_iter_copy (&iter);
675 }
676 
677 GtkTextIter*
_wrap_gtk_text_buffer_get_iter_at_line_index(GtkTextBuffer * buf,gint line_number,gint byte_index)678 _wrap_gtk_text_buffer_get_iter_at_line_index (GtkTextBuffer *buf, gint line_number,
679                                               gint byte_index)
680 {
681     GtkTextIter iter;
682     gtk_text_buffer_get_iter_at_line_index (buf, &iter, line_number, byte_index);
683     return gtk_text_iter_copy (&iter);
684 }
685 
686 GtkTextIter*
_wrap_gtk_text_buffer_get_iter_at_offset(GtkTextBuffer * buf,gint char_offset)687 _wrap_gtk_text_buffer_get_iter_at_offset (GtkTextBuffer *buf, gint char_offset)
688 {
689     GtkTextIter iter;
690     gtk_text_buffer_get_iter_at_offset (buf, &iter, char_offset);
691     return gtk_text_iter_copy (&iter);
692 }
693 
694 GtkTextIter*
_wrap_gtk_text_buffer_get_iter_at_line(GtkTextBuffer * buf,gint line_number)695 _wrap_gtk_text_buffer_get_iter_at_line (GtkTextBuffer *buf, gint line_number)
696 {
697     GtkTextIter iter;
698     gtk_text_buffer_get_iter_at_line (buf, &iter, line_number);
699     return gtk_text_iter_copy (&iter);
700 }
701 
702 GtkTextIter*
_wrap_gtk_text_buffer_get_start_iter(GtkTextBuffer * buf)703 _wrap_gtk_text_buffer_get_start_iter (GtkTextBuffer *buf)
704 {
705     GtkTextIter iter;
706     gtk_text_buffer_get_start_iter (buf, &iter);
707     return gtk_text_iter_copy (&iter);
708 }
709 
710 GtkTextIter*
_wrap_gtk_text_buffer_get_end_iter(GtkTextBuffer * buf)711 _wrap_gtk_text_buffer_get_end_iter (GtkTextBuffer *buf)
712 {
713     GtkTextIter iter;
714     gtk_text_buffer_get_end_iter (buf, &iter);
715     return gtk_text_iter_copy (&iter);
716 }
717 
718 SCM
_wrap_gtk_text_buffer_get_bounds(GtkTextBuffer * buf)719 _wrap_gtk_text_buffer_get_bounds (GtkTextBuffer *buf)
720 {
721     GtkTextIter start, end;
722     SCM sstart, send;
723 
724     gtk_text_buffer_get_bounds (buf, &start, &end);
725     sstart = scm_c_gvalue_new_from_boxed (GTK_TYPE_TEXT_ITER, &start);
726     send = scm_c_gvalue_new_from_boxed (GTK_TYPE_TEXT_ITER, &end);
727     return scm_values (SCM_LIST2 (sstart, send));
728 }
729 
730 SCM
_wrap_gtk_text_buffer_get_selection_bounds(GtkTextBuffer * buf)731 _wrap_gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buf)
732 {
733     GtkTextIter start, end;
734     SCM sstart, send;
735 
736     if (gtk_text_buffer_get_selection_bounds (buf, &start, &end)) {
737         sstart = scm_c_gvalue_new_from_boxed (GTK_TYPE_TEXT_ITER, &start);
738         send = scm_c_gvalue_new_from_boxed (GTK_TYPE_TEXT_ITER, &end);
739         return scm_values (SCM_LIST2 (sstart, send));
740     }
741     return scm_values (SCM_LIST2 (SCM_BOOL_F, SCM_BOOL_F));
742 }
743 
744 GtkTextIter*
_wrap_gtk_text_buffer_get_iter_at_mark(GtkTextBuffer * buf,GtkTextMark * mark)745 _wrap_gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buf, GtkTextMark* mark)
746 {
747     GtkTextIter iter;
748     gtk_text_buffer_get_iter_at_mark (buf, &iter, mark);
749     return gtk_text_iter_copy (&iter);
750 }
751 
752 GtkTextIter*
_wrap_gtk_text_buffer_get_iter_at_child_anchor(GtkTextBuffer * buf,GtkTextChildAnchor * anchor)753 _wrap_gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer *buf,
754                                                 GtkTextChildAnchor* anchor)
755 {
756     GtkTextIter iter;
757     gtk_text_buffer_get_iter_at_child_anchor (buf, &iter, anchor);
758     return gtk_text_iter_copy (&iter);
759 }
760 
761 GtkTreeIter*
_wrap_gtk_tree_model_get_iter(GtkTreeModel * model,GtkTreePath * path)762 _wrap_gtk_tree_model_get_iter (GtkTreeModel *model, GtkTreePath *path)
763 {
764     GtkTreeIter new;
765 
766     if (gtk_tree_model_get_iter (model, &new, path))
767         return gtk_tree_iter_copy (&new);
768     return NULL;
769 }
770 
771 GtkTreeIter*
_wrap_gtk_tree_model_get_iter_first(GtkTreeModel * model)772 _wrap_gtk_tree_model_get_iter_first (GtkTreeModel *model)
773 {
774     GtkTreeIter new;
775 
776     if (gtk_tree_model_get_iter_first (model, &new))
777         return gtk_tree_iter_copy (&new);
778     return NULL;
779 }
780 
781 SCM
_wrap_gtk_tree_model_get_value(GtkTreeModel * model,GtkTreeIter * iter,gint column)782 _wrap_gtk_tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter, gint column)
783 {
784     GValue value = { 0, };
785 
786     gtk_tree_model_get_value (model, iter, column, &value);
787 
788     return scm_c_gvalue_to_scm (&value);
789 }
790 
791 GtkTreeIter*
_wrap_gtk_tree_model_iter_next(GtkTreeModel * model,GtkTreeIter * iter)792 _wrap_gtk_tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
793 {
794     GtkTreeIter *new = gtk_tree_iter_copy (iter);
795 
796     if (gtk_tree_model_iter_next (model, new))
797         return new;
798     gtk_tree_iter_free (new);
799     return NULL;
800 }
801 
802 GList*
_wrap_gtk_tree_model_iter_children(GtkTreeModel * model,GtkTreeIter * iter)803 _wrap_gtk_tree_model_iter_children (GtkTreeModel *model, GtkTreeIter *iter)
804 {
805     GList *list = NULL;
806     GtkTreeIter prev;
807 
808     if (gtk_tree_model_iter_children (model, &prev, iter)) {
809         while (1) {
810             list = g_list_prepend (list, gtk_tree_iter_copy (&prev));
811 
812             if (!gtk_tree_model_iter_next (model, &prev)) {
813                 return g_list_reverse (list);
814             }
815         }
816     }
817     return NULL;
818 }
819 
820 GtkTreeIter*
_wrap_gtk_tree_model_iter_parent(GtkTreeModel * model,GtkTreeIter * iter)821 _wrap_gtk_tree_model_iter_parent (GtkTreeModel *model, GtkTreeIter *iter)
822 {
823     GtkTreeIter new;
824 
825     if (gtk_tree_model_iter_parent (model, &new, iter))
826         return gtk_tree_iter_copy (&new);
827     return NULL;
828 }
829 
830 GtkTreeIter*
_wrap_gtk_tree_model_iter_nth_child(GtkTreeModel * model,GtkTreeIter * iter,gint n)831 _wrap_gtk_tree_model_iter_nth_child (GtkTreeModel *model, GtkTreeIter *iter, gint n)
832 {
833     GtkTreeIter new;
834 
835     if (gtk_tree_model_iter_nth_child (model, &new, iter, n))
836         return gtk_tree_iter_copy (&new);
837     return NULL;
838 }
839 
840 SCM
_wrap_gtk_tree_selection_get_selected(GtkTreeSelection * selection)841 _wrap_gtk_tree_selection_get_selected (GtkTreeSelection *selection)
842 {
843     GtkTreeIter iter;
844     GtkTreeModel *model = NULL;
845 
846     if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
847         SCM smodel, siter;
848         g_object_ref (model);
849         smodel = scm_c_gtype_instance_to_scm ((GTypeInstance*)model);
850         siter = scm_c_gvalue_new_from_boxed (GTK_TYPE_TREE_ITER, &iter);
851         return scm_values (SCM_LIST2 (smodel, siter));
852     }
853     return scm_values (SCM_LIST2 (SCM_BOOL_F, SCM_BOOL_F));
854 }
855 
856 GtkTreeStore*
_wrap_gtk_tree_store_new(SCM col_types)857 _wrap_gtk_tree_store_new (SCM col_types)
858 #define FUNC_NAME "gtk-tree-store-new"
859 {
860     GType *col_gtypes;
861     gint len, i;
862     GtkTreeStore *ret;
863 
864     SCM_VALIDATE_NONEMPTYLIST (1, col_types);
865     len = scm_ilength (col_types);
866     col_gtypes = g_new (GType, len);
867 
868     for (i=0; i<len; i++) {
869         SCM v = SCM_CAR (col_types);
870         SCM_VALIDATE_GTYPE_CLASS_COPY (1, v, col_gtypes[i]);
871         col_types = SCM_CDR (col_types);
872     }
873 
874     ret = gtk_tree_store_newv (len, col_gtypes);
875     g_free (col_gtypes);
876     return ret;
877 }
878 #undef FUNC_NAME
879 
880 void
_wrap_gtk_tree_store_set_value(GtkTreeStore * store,GtkTreeIter * iter,gint column,SCM scm)881 _wrap_gtk_tree_store_set_value (GtkTreeStore *store, GtkTreeIter *iter,
882                                 gint column, SCM scm)
883 {
884     GValue *value;
885     GType type;
886 
887     SCM_ASSERT (column < gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)),
888                 scm_from_int (column), 3, "gtk-tree-store-set-value");
889     type = gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), column);
890     value = scm_c_scm_to_gvalue (type, scm);
891 
892     gtk_tree_store_set_value (store, iter, column, value);
893     g_value_unset (value);
894     g_free (value);
895 }
896 
897 GtkTreeIter*
_wrap_gtk_tree_store_remove(GtkTreeStore * store,GtkTreeIter * iter)898 _wrap_gtk_tree_store_remove (GtkTreeStore *store, GtkTreeIter *iter)
899 {
900     if (!gtk_tree_store_remove (store, iter))
901         return NULL;
902     return gtk_tree_iter_copy (iter);
903 }
904 
905 GtkTreeIter*
_wrap_gtk_tree_store_insert(GtkTreeStore * store,GtkTreeIter * parent,gint position)906 _wrap_gtk_tree_store_insert (GtkTreeStore *store, GtkTreeIter *parent, gint position)
907 {
908     GtkTreeIter new;
909     gtk_tree_store_insert (store, &new, parent, position);
910     return gtk_tree_iter_copy (&new);
911 }
912 
913 GtkTreeIter*
_wrap_gtk_tree_store_insert_before(GtkTreeStore * store,GtkTreeIter * parent,GtkTreeIter * sibling)914 _wrap_gtk_tree_store_insert_before (GtkTreeStore *store, GtkTreeIter *parent,
915                                     GtkTreeIter *sibling)
916 {
917     GtkTreeIter new;
918     gtk_tree_store_insert_before (store, &new, parent, sibling);
919     return gtk_tree_iter_copy (&new);
920 }
921 
922 GtkTreeIter*
_wrap_gtk_tree_store_insert_after(GtkTreeStore * store,GtkTreeIter * parent,GtkTreeIter * sibling)923 _wrap_gtk_tree_store_insert_after (GtkTreeStore *store, GtkTreeIter *parent,
924                                    GtkTreeIter *sibling)
925 {
926     GtkTreeIter new;
927     gtk_tree_store_insert_after (store, &new, parent, sibling);
928     return gtk_tree_iter_copy (&new);
929 }
930 
931 GtkTreeIter*
_wrap_gtk_tree_store_prepend(GtkTreeStore * store,GtkTreeIter * parent)932 _wrap_gtk_tree_store_prepend (GtkTreeStore *store, GtkTreeIter *parent)
933 {
934     GtkTreeIter new;
935     gtk_tree_store_prepend (store, &new, parent);
936     return gtk_tree_iter_copy (&new);
937 }
938 
939 GtkTreeIter*
_wrap_gtk_tree_store_append(GtkTreeStore * store,GtkTreeIter * parent)940 _wrap_gtk_tree_store_append (GtkTreeStore *store, GtkTreeIter *parent)
941 {
942     GtkTreeIter new;
943     gtk_tree_store_append (store, &new, parent);
944     return gtk_tree_iter_copy (&new);
945 }
946 
947 SCM
_wrap_gtk_tree_view_get_path_at_pos(GtkTreeView * treeview,gint x,gint y)948 _wrap_gtk_tree_view_get_path_at_pos (GtkTreeView *treeview,
949                                      gint x, gint y)
950 {
951     GtkTreePath *path;
952     GtkTreeViewColumn *column;
953     gint cell_x, cell_y;
954 
955     if (gtk_tree_view_get_path_at_pos (treeview, x, y, &path, &column,
956                                        &cell_x, &cell_y)) {
957         SCM spath = guile_gtk_tree_path_to_scm (path);
958         SCM scolumn = scm_c_gtype_instance_to_scm (column);
959 
960         gtk_tree_path_free (path);
961 
962         return scm_values (SCM_LIST4 (spath, scolumn, scm_from_int (cell_x),
963                                       scm_from_int (cell_y)));
964     }
965 
966     return scm_values (
967         SCM_LIST4 (SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F));
968 }
969 
970 static void
with_cell_data_func(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,GtkTreeModel * tree_model,GtkTreeIter * iter,gpointer data)971 with_cell_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
972                      GtkTreeModel *tree_model, GtkTreeIter *iter,
973                      gpointer data)
974 {
975     SCM proc, scolumn, scell, smodel, siter;
976     proc = GPOINTER_TO_SCM (data);
977     scolumn = scm_c_gtype_instance_to_scm ((GTypeInstance*)tree_column);
978     scell = scm_c_gtype_instance_to_scm ((GTypeInstance*)cell);
979     smodel = scm_c_gtype_instance_to_scm ((GTypeInstance*)tree_model);
980     siter = scm_c_gvalue_new_from_boxed (GTK_TYPE_TREE_ITER, iter);
981 
982     scm_call_4 (proc, scolumn, scell, smodel, siter);
983 }
984 
985 static void
cell_data_func(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,GtkTreeModel * tree_model,GtkTreeIter * iter,gpointer data)986 cell_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
987                 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
988 {
989     scm_dynwind_guile_v__p_p_p_p_p (scm_with_guile, with_cell_data_func,
990                                     tree_column, cell, tree_model, iter,
991                                     data);
992 }
993 
994 void
_wrap_gtk_tree_view_column_set_cell_data_func(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell_renderer,SCM proc)995 _wrap_gtk_tree_view_column_set_cell_data_func (GtkTreeViewColumn *tree_column,
996                                                GtkCellRenderer *cell_renderer,
997                                                SCM proc)
998 {
999     gtk_tree_view_column_set_cell_data_func
1000         (tree_column, cell_renderer, cell_data_func,
1001          SCM_TO_GPOINTER (scm_gc_protect_object (proc)),
1002          (GtkDestroyNotify)scm_gc_unprotect_object);
1003 }
1004 
1005 guint
_wrap_gtk_ui_manager_add_ui_from_string(GtkUIManager * ui,const gchar * string,GError ** error)1006 _wrap_gtk_ui_manager_add_ui_from_string (GtkUIManager *ui, const gchar *string,
1007                                          GError **error)
1008 {
1009     return gtk_ui_manager_add_ui_from_string (ui, string, -1, error);
1010 }
1011 
1012 void
_wrap_gtk_drag_dest_set(GtkWidget * widget,GtkDestDefaults flags,const GList * types,GdkDragAction actions)1013 _wrap_gtk_drag_dest_set (GtkWidget *widget, GtkDestDefaults flags,
1014                          const GList* types, GdkDragAction actions)
1015 {
1016     const GList *l;
1017     gint i, n;
1018     GtkTargetEntry* entries;
1019 
1020     n = g_list_length ((GList*)types);
1021     entries = g_new0 (GtkTargetEntry, n);
1022     for (i=0, l=types; i<n; i++, l=l->next)
1023         entries[i].target = (gchar*)l->data;
1024 
1025     gtk_drag_dest_set (widget, flags, entries, n, actions);
1026 }
1027 
1028 GdkGC*
gtk_style_get_fg_gc(GtkStyle * style,GtkStateType state)1029 gtk_style_get_fg_gc (GtkStyle *style, GtkStateType state)
1030 {
1031     return style->fg_gc[state];
1032 }
1033 
1034 GdkGC*
gtk_style_get_bg_gc(GtkStyle * style,GtkStateType state)1035 gtk_style_get_bg_gc (GtkStyle *style, GtkStateType state)
1036 {
1037     return style->bg_gc[state];
1038 }
1039 
1040 GdkGC*
gtk_style_get_white_gc(GtkStyle * style)1041 gtk_style_get_white_gc (GtkStyle *style)
1042 {
1043     return style->white_gc;
1044 }
1045 
1046 GdkGC*
gtk_style_get_black_gc(GtkStyle * style)1047 gtk_style_get_black_gc (GtkStyle *style)
1048 {
1049     return style->black_gc;
1050 }
1051 
1052 GdkWindow*
gtk_widget_get_window(GtkWidget * widget)1053 gtk_widget_get_window (GtkWidget *widget)
1054 {
1055     return GTK_WIDGET_NO_WINDOW (widget) ? NULL : widget->window;
1056 }
1057 
1058 GdkRectangle*
_wrap_gtk_widget_get_allocation(GtkWidget * widget)1059 _wrap_gtk_widget_get_allocation (GtkWidget *widget)
1060 {
1061     GdkRectangle *ret = g_new (GdkRectangle, 1);
1062 #if GTK_CHECK_VERSION(2,18,0)
1063     gtk_widget_get_allocation (widget, (GtkAllocation*)ret);
1064 #else
1065      *ret = widget->allocation;
1066 #endif
1067     return ret;
1068 }
1069 
1070 GtkStateType
gtk_widget_get_state(GtkWidget * widget)1071 gtk_widget_get_state (GtkWidget *widget)
1072 {
1073   g_return_val_if_fail (widget != NULL, 0);
1074   g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
1075 
1076   return GTK_WIDGET_STATE (widget);
1077 }
1078