Mercurial > hg > xemacs-beta
annotate src/ui-gtk.c @ 4709:db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
are missing. This is done with Bill Perry's stated permission, in private
email to me.
author | Jerry James <james@xemacs.org> |
---|---|
date | Mon, 05 Oct 2009 11:08:59 -0600 |
parents | 1e7cc382eb16 |
children | a98ca4640147 e0db3c197671 |
rev | line source |
---|---|
462 | 1 /* ui-gtk.c |
2 ** | |
3 ** Description: Creating 'real' UIs from lisp. | |
4 ** | |
5 ** Created by: William M. Perry <wmperry@gnu.org> | |
6 ** Copyright (c) 2000 William M. Perry <wmperry@gnu.org> | |
7 ** | |
4709
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
8 ** This file is part of XEmacs. |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
9 ** |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
10 ** XEmacs is free software; you can redistribute it and/or modify it |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
11 ** under the terms of the GNU General Public License as published by the |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
12 ** Free Software Foundation; either version 2, or (at your option) any |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
13 ** later version. |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
14 ** |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
15 ** XEmacs is distributed in the hope that it will be useful, but WITHOUT |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
16 ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
17 ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
18 ** for more details. |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
19 ** |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
20 ** You should have received a copy of the GNU General Public License |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
21 ** along with XEmacs; see the file COPYING. If not, write to |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
22 ** the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
db7068430402
Add explicit GPL v2 or later notices to Bill Perry's code, where such notices
Jerry James <james@xemacs.org>
parents:
3017
diff
changeset
|
23 ** Boston, MA 02111-1301, USA. */ |
462 | 24 */ |
25 | |
26 #include <config.h> | |
27 #include "lisp.h" | |
1346 | 28 |
462 | 29 #include "buffer.h" |
2168 | 30 #include "console-gtk-impl.h" |
462 | 31 #include "device.h" |
32 #include "elhash.h" | |
778 | 33 #include "event-gtk.h" |
1346 | 34 #include "events.h" |
35 #include "faces.h" | |
36 #include "glyphs-gtk.h" | |
37 #include "hash.h" | |
38 #include "objects-gtk.h" | |
39 #include "sysdll.h" | |
40 #include "ui-gtk.h" | |
41 #include "window.h" | |
462 | 42 |
43 /* XEmacs specific GTK types */ | |
44 #include "gtk-glue.c" | |
45 | |
2054 | 46 /* Is the fundamental type of 't' the xemacs defined fundamental type 'type'? */ |
47 #define IS_XEMACS_GTK_FUNDAMENTAL_TYPE(t,type) (((GtkType) GTK_FUNDAMENTAL_TYPE(t)) == (type)) | |
48 | |
462 | 49 Lisp_Object Qemacs_ffip; |
50 Lisp_Object Qemacs_gtk_objectp; | |
51 Lisp_Object Qemacs_gtk_boxedp; | |
52 Lisp_Object Qvoid; | |
53 Lisp_Object Venumeration_info; | |
54 | |
55 static GHashTable *dll_cache; | |
56 | |
57 Lisp_Object gtk_type_to_lisp (GtkArg *arg); | |
58 int lisp_to_gtk_type (Lisp_Object obj, GtkArg *arg); | |
1883 | 59 int lisp_to_gtk_ret_type (Lisp_Object obj, GtkArg *arg); |
778 | 60 #if 0 |
462 | 61 void describe_gtk_arg (GtkArg *arg); |
778 | 62 #endif |
462 | 63 guint symbol_to_enum (Lisp_Object obj, GtkType t); |
64 static guint lisp_to_flag (Lisp_Object obj, GtkType t); | |
65 static Lisp_Object flags_to_list (guint value, GtkType t); | |
66 static Lisp_Object enum_to_symbol (guint value, GtkType t); | |
67 | |
68 #define NIL_OR_VOID_P(x) (NILP (x) || EQ (x, Qvoid)) | |
69 | |
70 static void | |
71 initialize_dll_cache (void) | |
72 { | |
73 if (!dll_cache) | |
74 { | |
2054 | 75 static char text[] = "---XEmacs Internal Handle---"; |
76 | |
462 | 77 dll_cache = g_hash_table_new (g_str_hash, g_str_equal); |
78 | |
2054 | 79 g_hash_table_insert (dll_cache, text, dll_open (Qnil)); |
462 | 80 } |
81 } | |
82 | |
83 DEFUN ("dll-load", Fdll_load, 1, 1, 0, /* | |
84 Load a shared library DLL into XEmacs. No initialization routines are required. | |
85 This is for loading dependency DLLs into XEmacs. | |
86 */ | |
87 (dll)) | |
88 { | |
89 dll_handle h; | |
90 | |
91 CHECK_STRING (dll); | |
92 | |
93 initialize_dll_cache (); | |
94 | |
95 /* If the dll name has a directory component in it, then we should | |
96 expand it. */ | |
97 if (!NILP (Fstring_match (build_string ("/"), dll, Qnil, Qnil))) | |
98 dll = Fexpand_file_name (dll, Qnil); | |
99 | |
100 /* Check if we have already opened it first */ | |
101 h = g_hash_table_lookup (dll_cache, XSTRING_DATA (dll)); | |
102 | |
103 if (!h) | |
104 { | |
1811 | 105 h = dll_open (dll); |
462 | 106 |
107 if (h) | |
108 { | |
2054 | 109 g_hash_table_insert (dll_cache, qxestrdup (XSTRING_DATA (dll)), h); |
462 | 110 } |
111 else | |
112 { | |
2054 | 113 signal_error (Qfile_error, "dll_open error", dll_error()); |
462 | 114 } |
115 } | |
116 return (h ? Qt : Qnil); | |
117 } | |
118 | |
119 | |
120 /* Gtk object importing */ | |
121 EXFUN (Fgtk_import_type, 1); | |
122 | |
123 static struct hash_table *internal_type_hash; | |
124 | |
125 static int | |
126 type_already_imported_p (GtkType t) | |
127 { | |
128 void *retval = NULL; | |
129 | |
130 /* These are cases that we don't need to import */ | |
131 switch (GTK_FUNDAMENTAL_TYPE (t)) | |
132 { | |
133 case GTK_TYPE_CHAR: | |
134 case GTK_TYPE_UCHAR: | |
135 case GTK_TYPE_BOOL: | |
136 case GTK_TYPE_INT: | |
137 case GTK_TYPE_UINT: | |
138 case GTK_TYPE_LONG: | |
139 case GTK_TYPE_ULONG: | |
140 case GTK_TYPE_FLOAT: | |
141 case GTK_TYPE_DOUBLE: | |
142 case GTK_TYPE_STRING: | |
143 case GTK_TYPE_BOXED: | |
144 case GTK_TYPE_POINTER: | |
145 case GTK_TYPE_SIGNAL: | |
146 case GTK_TYPE_ARGS: | |
147 case GTK_TYPE_CALLBACK: | |
148 case GTK_TYPE_C_CALLBACK: | |
149 case GTK_TYPE_FOREIGN: | |
150 return (1); | |
151 } | |
152 | |
153 if (!internal_type_hash) | |
154 { | |
2515 | 155 internal_type_hash = make_hash_table (163); |
462 | 156 return (0); |
157 } | |
158 | |
159 if (gethash ((void *)t, internal_type_hash, (const void **)&retval)) | |
160 { | |
161 return (1); | |
162 } | |
163 return (0); | |
164 } | |
165 | |
166 static void | |
167 mark_type_as_imported (GtkType t) | |
168 { | |
169 if (type_already_imported_p (t)) | |
170 return; | |
171 | |
172 puthash ((void *) t, (void *) 1, internal_type_hash); | |
173 } | |
174 | |
175 static void import_gtk_type (GtkType t); | |
176 | |
177 static void | |
178 import_gtk_object_internal (GtkType the_type) | |
179 { | |
180 GtkType original_type = the_type; | |
181 int first_time = 1; | |
182 | |
183 do | |
184 { | |
185 GtkArg *args; | |
186 guint32 *flags; | |
187 guint n_args; | |
188 guint i; | |
189 #if 0 | |
190 GtkObjectClass *klass; | |
191 GtkSignalQuery *query; | |
192 guint32 *signals; | |
193 guint n_signals; | |
194 #endif | |
195 | |
196 /* Register the type before we do anything else with it... */ | |
197 if (!first_time) | |
198 { | |
199 if (!type_already_imported_p (the_type)) | |
200 { | |
201 import_gtk_type (the_type); | |
202 } | |
203 } | |
204 else | |
205 { | |
206 /* We need to mark the object type as imported here or we | |
207 run the risk of SERIOUS recursion when we do automatic | |
208 argument type importing. mark_type_as_imported() is | |
209 smart enough to be a noop if we attempt to register | |
210 things twice. */ | |
211 first_time = 0; | |
212 mark_type_as_imported (the_type); | |
213 } | |
214 | |
215 args = gtk_object_query_args(the_type,&flags,&n_args); | |
216 | |
217 /* First get the arguments the object can accept */ | |
218 for (i = 0; i < n_args; i++) | |
219 { | |
220 if ((args[i].type != original_type) && !type_already_imported_p (args[i].type)) | |
221 { | |
222 import_gtk_type (args[i].type); | |
223 } | |
224 } | |
225 | |
226 g_free(args); | |
227 g_free(flags); | |
228 | |
229 #if 0 | |
230 /* Now lets publish the signals */ | |
231 klass = (GtkObjectClass *) gtk_type_class (the_type); | |
232 signals = klass->signals; | |
233 n_signals = klass->nsignals; | |
234 | |
235 for (i = 0; i < n_signals; i++) | |
236 { | |
237 query = gtk_signal_query (signals[i]); | |
238 /* What do we want to do here? */ | |
239 g_free (query); | |
240 } | |
241 #endif | |
242 | |
243 the_type = gtk_type_parent(the_type); | |
244 } while (the_type != GTK_TYPE_INVALID); | |
245 } | |
246 | |
247 static void | |
248 import_gtk_enumeration_internal (GtkType the_type) | |
249 { | |
250 GtkEnumValue *vals = gtk_type_enum_get_values (the_type); | |
251 Lisp_Object assoc = Qnil; | |
252 | |
253 if (NILP (Venumeration_info)) | |
254 { | |
255 Venumeration_info = call2 (intern ("make-hashtable"), make_int (100), Qequal); | |
256 } | |
257 | |
258 while (vals && vals->value_name) | |
259 { | |
260 assoc = Fcons (Fcons (intern (vals->value_nick), make_int (vals->value)), assoc); | |
261 assoc = Fcons (Fcons (intern (vals->value_name), make_int (vals->value)), assoc); | |
262 vals++; | |
263 } | |
264 | |
265 assoc = Fnreverse (assoc); | |
266 | |
267 Fputhash (make_int (the_type), assoc, Venumeration_info); | |
268 } | |
269 | |
270 static void | |
271 import_gtk_type (GtkType t) | |
272 { | |
273 if (type_already_imported_p (t)) | |
274 { | |
275 return; | |
276 } | |
277 | |
278 switch (GTK_FUNDAMENTAL_TYPE (t)) | |
279 { | |
280 case GTK_TYPE_ENUM: | |
281 case GTK_TYPE_FLAGS: | |
282 import_gtk_enumeration_internal (t); | |
283 break; | |
284 case GTK_TYPE_OBJECT: | |
285 import_gtk_object_internal (t); | |
286 break; | |
287 default: | |
288 break; | |
289 } | |
290 | |
291 mark_type_as_imported (t); | |
292 } | |
293 | |
294 | |
295 /* Foreign function calls */ | |
296 static emacs_ffi_data * | |
297 allocate_ffi_data (void) | |
298 { | |
3017 | 299 emacs_ffi_data *data = ALLOC_LCRECORD_TYPE (emacs_ffi_data, &lrecord_emacs_ffi); |
462 | 300 |
301 data->return_type = GTK_TYPE_NONE; | |
302 data->n_args = 0; | |
303 data->function_name = Qnil; | |
304 data->function_ptr = 0; | |
305 data->marshal = 0; | |
306 | |
307 return (data); | |
308 } | |
309 | |
1204 | 310 static const struct memory_description ffi_data_description [] = { |
311 { XD_LISP_OBJECT, offsetof (emacs_ffi_data, function_name) }, | |
934 | 312 { XD_END } |
313 }; | |
314 | |
462 | 315 static Lisp_Object |
316 mark_ffi_data (Lisp_Object obj) | |
317 { | |
318 emacs_ffi_data *data = (emacs_ffi_data *) XFFI (obj); | |
319 | |
320 mark_object (data->function_name); | |
321 return (Qnil); | |
322 } | |
323 | |
324 static void | |
2286 | 325 ffi_object_printer (Lisp_Object obj, Lisp_Object printcharfun, |
326 int UNUSED (escapeflag)) | |
462 | 327 { |
328 if (print_readably) | |
563 | 329 printing_unreadable_object ("#<ffi %p>", XFFI (obj)->function_ptr); |
462 | 330 |
800 | 331 write_fmt_string_lisp (printcharfun, "#<ffi %S", 1, XFFI (obj)->function_name); |
462 | 332 if (XFFI (obj)->n_args) |
800 | 333 write_fmt_string (printcharfun, " %d arguments", XFFI (obj)->n_args); |
334 write_fmt_string (printcharfun, " %p>", (void *)XFFI (obj)->function_ptr); | |
462 | 335 } |
336 | |
934 | 337 DEFINE_LRECORD_IMPLEMENTATION ("ffi", emacs_ffi, |
960 | 338 0, /*dumpable-flag*/ |
934 | 339 mark_ffi_data, ffi_object_printer, |
340 0, 0, 0, | |
341 ffi_data_description, emacs_ffi_data); | |
462 | 342 |
2054 | 343 #if defined (__cplusplus) |
344 #define MANY_ARGS ... | |
345 #else | |
346 #define MANY_ARGS | |
347 #endif | |
348 | |
349 typedef void (*pfv)(); | |
350 typedef GtkObject * (*__OBJECT_fn) (MANY_ARGS); | |
351 typedef gint (*__INT_fn) (MANY_ARGS); | |
352 typedef void (*__NONE_fn) (MANY_ARGS); | |
353 typedef gchar * (*__STRING_fn) (MANY_ARGS); | |
354 typedef gboolean (*__BOOL_fn) (MANY_ARGS); | |
355 typedef gfloat (*__FLOAT_fn) (MANY_ARGS); | |
356 typedef void * (*__POINTER_fn) (MANY_ARGS); | |
357 typedef GList * (*__LIST_fn) (MANY_ARGS); | |
462 | 358 |
359 /* An auto-generated file of marshalling functions. */ | |
360 #include "emacs-marshals.c" | |
2054 | 361 #undef MANY_ARGS |
462 | 362 |
363 #define CONVERT_SINGLE_TYPE(var,nam,tp) case GTK_TYPE_##nam: GTK_VALUE_##nam (var) = * (tp *) v; break; | |
364 #define CONVERT_RETVAL(a,freep) \ | |
365 do { \ | |
366 void *v = GTK_VALUE_POINTER(a); \ | |
367 switch (GTK_FUNDAMENTAL_TYPE (a.type)) \ | |
1726 | 368 { \ |
462 | 369 CONVERT_SINGLE_TYPE(a,CHAR,gchar); \ |
370 CONVERT_SINGLE_TYPE(a,UCHAR,guchar); \ | |
371 CONVERT_SINGLE_TYPE(a,BOOL,gboolean); \ | |
372 CONVERT_SINGLE_TYPE(a,INT,gint); \ | |
373 CONVERT_SINGLE_TYPE(a,UINT,guint); \ | |
374 CONVERT_SINGLE_TYPE(a,LONG,glong); \ | |
375 CONVERT_SINGLE_TYPE(a,ULONG,gulong); \ | |
376 CONVERT_SINGLE_TYPE(a,FLOAT,gfloat); \ | |
377 CONVERT_SINGLE_TYPE(a,DOUBLE,gdouble); \ | |
378 CONVERT_SINGLE_TYPE(a,STRING,gchar *); \ | |
379 CONVERT_SINGLE_TYPE(a,ENUM,gint); \ | |
380 CONVERT_SINGLE_TYPE(a,FLAGS,guint); \ | |
381 CONVERT_SINGLE_TYPE(a,BOXED,void *); \ | |
382 CONVERT_SINGLE_TYPE(a,POINTER,void *); \ | |
383 CONVERT_SINGLE_TYPE(a,OBJECT,GtkObject *); \ | |
1726 | 384 default: \ |
385 GTK_VALUE_POINTER (a) = * (void **) v; \ | |
462 | 386 break; \ |
1726 | 387 } \ |
388 if (freep) xfree(v, void *); \ | |
462 | 389 } while (0) |
390 | |
778 | 391 static gpointer __allocate_object_storage (GtkType t) |
462 | 392 { |
393 size_t s = 0; | |
394 void *rval = NULL; | |
395 | |
396 switch (GTK_FUNDAMENTAL_TYPE (t)) | |
397 { | |
398 /* flag types */ | |
399 case GTK_TYPE_CHAR: | |
400 s = (sizeof (gchar)); | |
401 break; | |
402 case GTK_TYPE_UCHAR: | |
403 s = (sizeof (guchar)); | |
404 break; | |
405 case GTK_TYPE_BOOL: | |
406 s = (sizeof (gboolean)); | |
407 break; | |
408 case GTK_TYPE_INT: | |
409 s = (sizeof (gint)); | |
410 break; | |
411 case GTK_TYPE_UINT: | |
412 s = (sizeof (guint)); | |
413 break; | |
414 case GTK_TYPE_LONG: | |
415 s = (sizeof (glong)); | |
416 break; | |
417 case GTK_TYPE_ULONG: | |
418 s = (sizeof (gulong)); | |
419 break; | |
420 case GTK_TYPE_FLOAT: | |
421 s = (sizeof (gfloat)); | |
422 break; | |
423 case GTK_TYPE_DOUBLE: | |
424 s = (sizeof (gdouble)); | |
425 break; | |
426 case GTK_TYPE_STRING: | |
427 s = (sizeof (gchar *)); | |
428 break; | |
429 case GTK_TYPE_ENUM: | |
430 case GTK_TYPE_FLAGS: | |
431 s = (sizeof (guint)); | |
432 break; | |
433 case GTK_TYPE_BOXED: | |
434 case GTK_TYPE_POINTER: | |
435 s = (sizeof (void *)); | |
436 break; | |
437 | |
438 /* base type of the object system */ | |
439 case GTK_TYPE_OBJECT: | |
440 s = (sizeof (GtkObject *)); | |
441 break; | |
442 | |
443 default: | |
2054 | 444 if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(t, GTK_TYPE_LISTOF)) |
462 | 445 { |
446 s = (sizeof (void *)); | |
447 } | |
448 rval = NULL; | |
449 break; | |
450 } | |
451 | |
452 if (s) | |
453 { | |
454 rval = xmalloc (s); | |
455 memset (rval, '\0', s); | |
456 } | |
457 | |
458 return (rval); | |
459 } | |
460 | |
778 | 461 static Lisp_Object type_to_marshaller_type (GtkType t) |
462 | 462 { |
463 switch (GTK_FUNDAMENTAL_TYPE (t)) | |
464 { | |
465 case GTK_TYPE_NONE: | |
466 return (build_string ("NONE")); | |
467 /* flag types */ | |
468 case GTK_TYPE_CHAR: | |
469 case GTK_TYPE_UCHAR: | |
470 return (build_string ("CHAR")); | |
471 case GTK_TYPE_BOOL: | |
472 return (build_string ("BOOL")); | |
473 case GTK_TYPE_ENUM: | |
474 case GTK_TYPE_FLAGS: | |
475 case GTK_TYPE_INT: | |
476 case GTK_TYPE_UINT: | |
477 return (build_string ("INT")); | |
478 case GTK_TYPE_LONG: | |
479 case GTK_TYPE_ULONG: | |
480 return (build_string ("LONG")); | |
481 case GTK_TYPE_FLOAT: | |
482 case GTK_TYPE_DOUBLE: | |
483 return (build_string ("FLOAT")); | |
484 case GTK_TYPE_STRING: | |
485 return (build_string ("STRING")); | |
486 case GTK_TYPE_BOXED: | |
487 case GTK_TYPE_POINTER: | |
488 return (build_string ("POINTER")); | |
489 case GTK_TYPE_OBJECT: | |
490 return (build_string ("OBJECT")); | |
491 case GTK_TYPE_CALLBACK: | |
492 return (build_string ("CALLBACK")); | |
493 default: | |
494 /* I can't put this in the main switch statement because it is a | |
495 new fundamental type that is not fixed at compile time. | |
496 *sigh* | |
497 */ | |
2054 | 498 if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(t, GTK_TYPE_ARRAY)) |
462 | 499 return (build_string ("ARRAY")); |
500 | |
2054 | 501 if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(t, GTK_TYPE_LISTOF)) |
462 | 502 return (build_string ("LIST")); |
503 return (Qnil); | |
504 } | |
505 } | |
506 | |
507 struct __dll_mapper_closure { | |
2054 | 508 void * (*func) (dll_handle, const CIbyte *); |
509 Ibyte *obj_name; | |
462 | 510 void **storage; |
511 }; | |
512 | |
2286 | 513 static void __dll_mapper (gpointer UNUSED (key), gpointer value, |
514 gpointer user_data) | |
462 | 515 { |
516 struct __dll_mapper_closure *closure = (struct __dll_mapper_closure *) user_data; | |
517 | |
518 if (*(closure->storage) == NULL) | |
519 { | |
520 /* Need to see if it is in this one */ | |
2054 | 521 *(closure->storage) = closure->func ((dll_handle) value, (CIbyte*) closure->obj_name); |
462 | 522 } |
523 } | |
524 | |
525 DEFUN ("gtk-import-variable-internal", Fgtk_import_variable_internal, 2, 2, 0, /* | |
526 Import a variable into the XEmacs namespace. | |
527 */ | |
528 (type, name)) | |
529 { | |
530 void *var = NULL; | |
531 GtkArg arg; | |
532 | |
533 if (SYMBOLP (type)) type = Fsymbol_name (type); | |
534 | |
535 CHECK_STRING (type); | |
536 CHECK_STRING (name); | |
537 | |
538 initialize_dll_cache (); | |
539 xemacs_init_gtk_classes (); | |
540 | |
541 arg.type = gtk_type_from_name ((char *) XSTRING_DATA (type)); | |
542 | |
543 if (arg.type == GTK_TYPE_INVALID) | |
544 { | |
563 | 545 sferror ("Unknown type", type); |
462 | 546 } |
547 | |
548 /* Need to look thru the already-loaded dlls */ | |
549 { | |
550 struct __dll_mapper_closure closure; | |
551 | |
552 closure.func = dll_variable; | |
553 closure.obj_name = XSTRING_DATA (name); | |
554 closure.storage = &var; | |
555 | |
556 g_hash_table_foreach (dll_cache, __dll_mapper, &closure); | |
557 } | |
558 | |
559 if (!var) | |
560 { | |
563 | 561 gui_error ("Could not locate variable", name); |
462 | 562 } |
563 | |
564 GTK_VALUE_POINTER(arg) = var; | |
565 CONVERT_RETVAL (arg, 0); | |
566 return (gtk_type_to_lisp (&arg)); | |
567 } | |
568 | |
569 DEFUN ("gtk-import-function-internal", Fgtk_import_function_internal, 2, 3, 0, /* | |
570 Import a function into the XEmacs namespace. | |
571 */ | |
572 (rettype, name, args)) | |
573 { | |
574 Lisp_Object rval = Qnil; | |
575 Lisp_Object marshaller = Qnil; | |
576 emacs_ffi_data *data = NULL; | |
577 gint n_args = 0; | |
578 #if 0 | |
579 dll_handle h = NULL; | |
580 #endif | |
581 ffi_marshalling_function marshaller_func = NULL; | |
582 ffi_actual_function name_func = NULL; | |
583 | |
584 CHECK_SYMBOL (rettype); | |
585 CHECK_STRING (name); | |
586 CHECK_LIST (args); | |
587 | |
588 initialize_dll_cache (); | |
589 xemacs_init_gtk_classes (); | |
590 | |
591 /* Need to look thru the already-loaded dlls */ | |
592 { | |
593 struct __dll_mapper_closure closure; | |
594 | |
595 closure.func = dll_function; | |
596 closure.obj_name = XSTRING_DATA (name); | |
597 closure.storage = (void **) &name_func; | |
598 | |
599 g_hash_table_foreach (dll_cache, __dll_mapper, &closure); | |
600 } | |
601 | |
602 if (!name_func) | |
603 { | |
563 | 604 gui_error ("Could not locate function", name); |
462 | 605 } |
606 | |
607 data = allocate_ffi_data (); | |
608 | |
609 if (NILP (rettype)) | |
610 { | |
611 rettype = Qvoid; | |
612 } | |
613 | |
614 if (!NILP (args)) | |
615 { | |
616 Lisp_Object value = args; | |
617 Lisp_Object type = Qnil; | |
618 | |
2367 | 619 EXTERNAL_LIST_LOOP_2 (elt, value) |
462 | 620 { |
621 GtkType the_type; | |
622 Lisp_Object marshaller_type = Qnil; | |
623 | |
2367 | 624 CHECK_SYMBOL (elt); |
462 | 625 |
2367 | 626 type = Fsymbol_name (elt); |
462 | 627 |
628 the_type = gtk_type_from_name ((char *) XSTRING_DATA (type)); | |
629 | |
630 if (the_type == GTK_TYPE_INVALID) | |
631 { | |
563 | 632 invalid_argument ("Unknown argument type", type); |
462 | 633 } |
634 | |
635 /* All things must be reduced to their basest form... */ | |
636 import_gtk_type (the_type); | |
637 data->args[n_args] = the_type; /* GTK_FUNDAMENTAL_TYPE (the_type); */ | |
638 | |
639 /* Now lets build up another chunk of our marshaller function name */ | |
640 marshaller_type = type_to_marshaller_type (data->args[n_args]); | |
641 | |
642 if (NILP (marshaller_type)) | |
643 { | |
563 | 644 invalid_argument ("Do not know how to marshal", type); |
462 | 645 } |
646 marshaller = concat3 (marshaller, build_string ("_"), marshaller_type); | |
647 n_args++; | |
648 } | |
649 } | |
650 else | |
651 { | |
652 marshaller = concat3 (marshaller, build_string ("_"), type_to_marshaller_type (GTK_TYPE_NONE)); | |
653 } | |
654 | |
655 rettype = Fsymbol_name (rettype); | |
656 data->return_type = gtk_type_from_name ((char *) XSTRING_DATA (rettype)); | |
657 | |
658 if (data->return_type == GTK_TYPE_INVALID) | |
659 { | |
563 | 660 invalid_argument ("Unknown return type", rettype); |
462 | 661 } |
662 | |
663 import_gtk_type (data->return_type); | |
664 | |
665 marshaller = concat3 (type_to_marshaller_type (data->return_type), build_string ("_"), marshaller); | |
666 marshaller = concat2 (build_string ("emacs_gtk_marshal_"), marshaller); | |
667 | |
668 marshaller_func = (ffi_marshalling_function) find_marshaller ((char *) XSTRING_DATA (marshaller)); | |
669 | |
670 if (!marshaller_func) | |
671 { | |
563 | 672 gui_error ("Could not locate marshaller function", marshaller); |
462 | 673 } |
674 | |
675 data->n_args = n_args; | |
676 data->function_name = name; | |
2054 | 677 data->function_ptr = (dll_func) name_func; |
462 | 678 data->marshal = marshaller_func; |
679 | |
797 | 680 rval = wrap_emacs_ffi (data); |
462 | 681 return (rval); |
682 } | |
683 | |
684 DEFUN ("gtk-call-function", Fgtk_call_function, 1, 2, 0, /* | |
685 Call an external function. | |
686 */ | |
687 (func, args)) | |
688 { | |
689 GtkArg the_args[MAX_GTK_ARGS]; | |
690 gint n_args = 0; | |
691 Lisp_Object retval = Qnil; | |
692 | |
693 CHECK_FFI (func); | |
694 CHECK_LIST (args); | |
695 | |
696 n_args = XINT (Flength (args)); | |
697 | |
698 #ifdef XEMACS_IS_SMARTER_THAN_THE_PROGRAMMER | |
699 /* #### I think this is too dangerous to enable by default. | |
700 ** #### Genuine program bugs would probably be allowed to | |
701 ** #### slip by, and not be very easy to find. | |
702 ** #### Bill Perry July 9, 2000 | |
703 */ | |
704 if (n_args != XFFI(func)->n_args) | |
705 { | |
706 Lisp_Object for_append[3]; | |
707 | |
708 /* Signal an error if they pass in too many arguments */ | |
709 if (n_args > XFFI(func)->n_args) | |
710 { | |
711 return Fsignal (Qwrong_number_of_arguments, | |
712 list2 (func, make_int (n_args))); | |
713 } | |
714 | |
715 /* If they did not provide enough arguments, be nice and assume | |
716 ** they wanted `nil' in there. | |
717 */ | |
718 for_append[0] = args; | |
719 for_append[1] = Fmake_list (make_int (XFFI(func)->n_args - n_args), Qnil); | |
720 | |
721 args = Fappend (2, for_append); | |
722 } | |
723 #else | |
724 if (n_args != XFFI(func)->n_args) | |
725 { | |
726 /* Signal an error if they do not pass in the correct # of arguments */ | |
727 return Fsignal (Qwrong_number_of_arguments, | |
728 list2 (func, make_int (n_args))); | |
729 } | |
730 #endif | |
731 | |
732 if (!NILP (args)) | |
733 { | |
734 Lisp_Object value = args; | |
735 | |
736 CHECK_LIST (args); | |
737 n_args = 0; | |
738 | |
739 /* First we convert all of the arguments from Lisp to GtkArgs */ | |
2367 | 740 { |
741 EXTERNAL_LIST_LOOP_2 (elt, value) | |
742 { | |
743 the_args[n_args].type = XFFI (func)->args[n_args]; | |
462 | 744 |
2367 | 745 if (lisp_to_gtk_type (elt, &the_args[n_args])) |
746 { | |
747 /* There was some sort of an error */ | |
748 gui_error ("Error converting arguments", args); | |
749 } | |
750 n_args++; | |
751 } | |
752 } | |
462 | 753 } |
754 | |
755 /* Now we need to tack on space for a return value, if they have | |
756 asked for one */ | |
757 if (XFFI (func)->return_type != GTK_TYPE_NONE) | |
758 { | |
759 the_args[n_args].type = XFFI (func)->return_type; | |
760 GTK_VALUE_POINTER (the_args[n_args]) = __allocate_object_storage (the_args[n_args].type); | |
761 n_args++; | |
762 } | |
763 | |
764 XFFI (func)->marshal ((ffi_actual_function) (XFFI (func)->function_ptr), the_args); | |
765 | |
766 if (XFFI (func)->return_type != GTK_TYPE_NONE) | |
767 { | |
768 CONVERT_RETVAL (the_args[n_args - 1], 1); | |
769 retval = gtk_type_to_lisp (&the_args[n_args - 1]); | |
770 } | |
771 | |
772 /* Need to free any array or list pointers */ | |
773 { | |
774 int i; | |
775 for (i = 0; i < n_args; i++) | |
776 { | |
2054 | 777 if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(the_args[i].type, GTK_TYPE_ARRAY)) |
462 | 778 { |
779 g_free (GTK_VALUE_POINTER (the_args[i])); | |
780 } | |
2054 | 781 else if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(the_args[i].type, GTK_TYPE_LISTOF)) |
462 | 782 { |
783 /* g_list_free (GTK_VALUE_POINTER (the_args[i])); */ | |
784 } | |
785 } | |
786 } | |
787 | |
788 return (retval); | |
789 } | |
790 | |
791 | |
792 | |
793 /* GtkObject wrapping for Lisp */ | |
794 static void | |
2286 | 795 emacs_gtk_object_printer (Lisp_Object obj, Lisp_Object printcharfun, |
796 int UNUSED (escapeflag)) | |
462 | 797 { |
798 if (print_readably) | |
563 | 799 printing_unreadable_object ("#<GtkObject %p>", XGTK_OBJECT (obj)->object); |
462 | 800 |
826 | 801 write_c_string (printcharfun, "#<GtkObject ("); |
462 | 802 if (XGTK_OBJECT (obj)->alive_p) |
826 | 803 write_c_string (printcharfun, gtk_type_name (GTK_OBJECT_TYPE (XGTK_OBJECT (obj)->object))); |
462 | 804 else |
826 | 805 write_c_string (printcharfun, "dead"); |
800 | 806 write_fmt_string (printcharfun, ") %p>", (void *) XGTK_OBJECT (obj)->object); |
462 | 807 } |
808 | |
809 static Lisp_Object | |
810 object_getprop (Lisp_Object obj, Lisp_Object prop) | |
811 { | |
812 Lisp_Object rval = Qnil; | |
813 Lisp_Object prop_name = Qnil; | |
814 GtkArgInfo *info = NULL; | |
815 char *err; | |
816 GtkArg args[2]; | |
817 | |
818 CHECK_SYMBOL (prop); /* Shouldn't need to ever do this, but I'm paranoid */ | |
819 | |
820 prop_name = Fsymbol_name (prop); | |
821 | |
822 args[0].name = (char *) XSTRING_DATA (prop_name); | |
823 | |
824 err = gtk_object_arg_get_info (GTK_OBJECT_TYPE (XGTK_OBJECT (obj)->object), | |
825 args[0].name, | |
826 &info); | |
827 | |
828 if (err) | |
829 { | |
830 /* Not a magic symbol, fall back to just looking in our real plist */ | |
831 g_free (err); | |
832 | |
833 return (Fplist_get (XGTK_OBJECT (obj)->plist, prop, Qunbound)); | |
834 } | |
835 | |
836 if (!(info->arg_flags & GTK_ARG_READABLE)) | |
837 { | |
563 | 838 invalid_operation ("Attempt to get write-only property", prop); |
462 | 839 } |
840 | |
841 gtk_object_getv (XGTK_OBJECT (obj)->object, 1, args); | |
842 | |
843 if (args[0].type == GTK_TYPE_INVALID) | |
844 { | |
845 /* If we can't get the attribute, then let the code in Fget know | |
846 so it can use the default value supplied by the caller */ | |
847 return (Qunbound); | |
848 } | |
849 | |
850 rval = gtk_type_to_lisp (&args[0]); | |
851 | |
852 /* Free up any memory. According to the documentation and Havoc's | |
853 book, if the fundamental type of the returned value is | |
854 GTK_TYPE_STRING, GTK_TYPE_BOXED, or GTK_TYPE_ARGS, you are | |
855 responsible for freeing it. */ | |
856 switch (GTK_FUNDAMENTAL_TYPE (args[0].type)) | |
857 { | |
858 case GTK_TYPE_STRING: | |
859 g_free (GTK_VALUE_STRING (args[0])); | |
860 break; | |
861 case GTK_TYPE_BOXED: | |
862 g_free (GTK_VALUE_BOXED (args[0])); | |
863 break; | |
864 case GTK_TYPE_ARGS: | |
865 g_free (GTK_VALUE_ARGS (args[0]).args); | |
866 default: | |
867 break; | |
868 } | |
869 | |
870 return (rval); | |
871 } | |
872 | |
873 static int | |
874 object_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value) | |
875 { | |
876 GtkArgInfo *info = NULL; | |
877 Lisp_Object prop_name = Qnil; | |
878 GtkArg args[2]; | |
879 char *err = NULL; | |
880 | |
881 prop_name = Fsymbol_name (prop); | |
882 | |
883 args[0].name = (char *) XSTRING_DATA (prop_name); | |
884 | |
885 err = gtk_object_arg_get_info (GTK_OBJECT_TYPE (XGTK_OBJECT (obj)->object), | |
886 args[0].name, | |
887 &info); | |
888 | |
889 if (err) | |
890 { | |
891 /* Not a magic symbol, fall back to just storing in our real plist */ | |
892 g_free (err); | |
893 | |
894 XGTK_OBJECT (obj)->plist = Fplist_put (XGTK_OBJECT (obj)->plist, prop, value); | |
895 return (1); | |
896 } | |
897 | |
898 args[0].type = info->type; | |
899 | |
900 if (lisp_to_gtk_type (value, &args[0])) | |
901 { | |
563 | 902 gui_error ("Error converting to GtkType", value); |
462 | 903 } |
904 | |
905 if (!(info->arg_flags & GTK_ARG_WRITABLE)) | |
906 { | |
563 | 907 invalid_operation ("Attempt to set read-only argument", prop); |
462 | 908 } |
909 | |
910 gtk_object_setv (XGTK_OBJECT (obj)->object, 1, args); | |
911 | |
912 return (1); | |
913 } | |
914 | |
1204 | 915 static const struct memory_description gtk_object_data_description [] = { |
916 { XD_LISP_OBJECT, offsetof (emacs_gtk_object_data, plist) }, | |
934 | 917 { XD_END } |
918 }; | |
919 | |
462 | 920 static Lisp_Object |
921 mark_gtk_object_data (Lisp_Object obj) | |
922 { | |
923 return (XGTK_OBJECT (obj)->plist); | |
924 } | |
925 | |
926 static void | |
927 emacs_gtk_object_finalizer (void *header, int for_disksave) | |
928 { | |
929 emacs_gtk_object_data *data = (emacs_gtk_object_data *) header; | |
930 | |
931 if (for_disksave) | |
932 { | |
797 | 933 Lisp_Object obj = wrap_emacs_gtk_object (data); |
793 | 934 |
462 | 935 |
563 | 936 invalid_operation |
462 | 937 ("Can't dump an emacs containing GtkObject objects", obj); |
938 } | |
939 | |
940 if (data->alive_p) | |
941 { | |
942 gtk_object_unref (data->object); | |
943 } | |
944 } | |
945 | |
934 | 946 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("GtkObject", emacs_gtk_object, |
960 | 947 0, /*dumpable-flag*/ |
1204 | 948 mark_gtk_object_data, |
949 emacs_gtk_object_printer, | |
950 emacs_gtk_object_finalizer, | |
934 | 951 0, /* equality */ |
952 0, /* hash */ | |
1204 | 953 gtk_object_data_description, |
954 object_getprop, | |
955 object_putprop, | |
934 | 956 0, /* rem prop */ |
957 0, /* plist */ | |
958 emacs_gtk_object_data); | |
462 | 959 |
960 static emacs_gtk_object_data * | |
961 allocate_emacs_gtk_object_data (void) | |
962 { | |
3017 | 963 emacs_gtk_object_data *data = ALLOC_LCRECORD_TYPE (emacs_gtk_object_data, |
462 | 964 &lrecord_emacs_gtk_object); |
965 | |
966 data->object = NULL; | |
967 data->alive_p = FALSE; | |
968 data->plist = Qnil; | |
969 | |
970 return (data); | |
971 } | |
972 | |
973 /* We need to keep track of when the object is destroyed so that we | |
974 can mark it as dead, otherwise even our print routine (which calls | |
975 GTK_OBJECT_TYPE) will crap out and die. This is also used in the | |
976 lisp_to_gtk_type() routine to defend against passing dead objects | |
977 to GTK routines. */ | |
978 static void | |
2286 | 979 __notice_object_destruction (GtkObject *UNUSED (obj), gpointer user_data) |
462 | 980 { |
981 ungcpro_popup_callbacks ((GUI_ID) user_data); | |
982 } | |
983 | |
984 Lisp_Object build_gtk_object (GtkObject *obj) | |
985 { | |
986 Lisp_Object retval = Qnil; | |
987 emacs_gtk_object_data *data = NULL; | |
988 GUI_ID id = 0; | |
989 | |
2168 | 990 id = (GUI_ID) gtk_object_get_data (obj, GTK_DATA_GUI_IDENTIFIER); |
462 | 991 |
992 if (id) | |
993 { | |
994 retval = get_gcpro_popup_callbacks (id); | |
995 } | |
996 | |
997 if (NILP (retval)) | |
998 { | |
999 data = allocate_emacs_gtk_object_data (); | |
1000 | |
1001 data->object = obj; | |
1002 data->alive_p = TRUE; | |
797 | 1003 retval = wrap_emacs_gtk_object (data); |
462 | 1004 |
1005 id = new_gui_id (); | |
2168 | 1006 gtk_object_set_data (obj, GTK_DATA_GUI_IDENTIFIER, (gpointer) id); |
462 | 1007 gcpro_popup_callbacks (id, retval); |
1008 gtk_object_ref (obj); | |
1009 gtk_signal_connect (obj, "destroy", GTK_SIGNAL_FUNC (__notice_object_destruction), (gpointer)id); | |
1010 } | |
1011 | |
1012 return (retval); | |
1013 } | |
1014 | |
1015 static void | |
1016 __internal_callback_destroy (gpointer data) | |
1017 { | |
1018 Lisp_Object lisp_data; | |
1019 | |
826 | 1020 lisp_data = VOID_TO_LISP (data); |
462 | 1021 |
1022 ungcpro_popup_callbacks (XINT (XCAR (lisp_data))); | |
1023 } | |
1024 | |
1025 static void | |
1026 __internal_callback_marshal (GtkObject *obj, gpointer data, guint n_args, GtkArg *args) | |
1027 { | |
1028 Lisp_Object arg_list = Qnil; | |
1029 Lisp_Object callback_fn = Qnil; | |
1030 Lisp_Object callback_data = Qnil; | |
1031 Lisp_Object newargs[3]; | |
1032 Lisp_Object rval = Qnil; | |
1033 struct gcpro gcpro1; | |
1034 int i; | |
1035 | |
826 | 1036 callback_fn = VOID_TO_LISP (data); |
462 | 1037 |
1038 /* Nuke the GUI_ID off the front */ | |
1039 callback_fn = XCDR (callback_fn); | |
1040 | |
1041 callback_data = XCAR (callback_fn); | |
1042 callback_fn = XCDR (callback_fn); | |
1043 | |
1044 /* The callback data goes at the very end of the argument list */ | |
1045 arg_list = Fcons (callback_data, Qnil); | |
1046 | |
1047 /* Build up the argument list, lisp style */ | |
1048 for (i = n_args - 1; i >= 0; i--) | |
1049 { | |
1050 arg_list = Fcons (gtk_type_to_lisp (&args[i]), arg_list); | |
1051 } | |
1052 | |
1053 /* We always pass the widget as the first parameter at the very least */ | |
1054 arg_list = Fcons (build_gtk_object (obj), arg_list); | |
1055 | |
1056 GCPRO1 ((arg_list)); | |
1057 | |
1058 newargs[0] = callback_fn; | |
1059 newargs[1] = arg_list; | |
1060 | |
1061 rval = Fapply (2, newargs); | |
1062 signal_fake_event (); | |
1063 | |
1064 if (args[n_args].type != GTK_TYPE_NONE) | |
1883 | 1065 lisp_to_gtk_ret_type (rval, &args[n_args]); |
462 | 1066 |
1067 UNGCPRO; | |
1068 } | |
1069 | |
1070 DEFUN ("gtk-signal-connect", Fgtk_signal_connect, 3, 6, 0, /* | |
1071 */ | |
1072 (obj, name, func, cb_data, object_signal, after_p)) | |
1073 { | |
1074 int c_after; | |
1075 int c_object_signal; | |
1076 GUI_ID id = 0; | |
1077 | |
1078 CHECK_GTK_OBJECT (obj); | |
1079 | |
1080 if (SYMBOLP (name)) | |
1081 name = Fsymbol_name (name); | |
1082 | |
1083 CHECK_STRING (name); | |
1084 | |
1085 if (NILP (object_signal)) | |
1086 c_object_signal = 0; | |
1087 else | |
1088 c_object_signal = 1; | |
1089 | |
1090 if (NILP (after_p)) | |
1091 c_after = 0; | |
1092 else | |
1093 c_after = 1; | |
1094 | |
1095 id = new_gui_id (); | |
1096 func = Fcons (cb_data, func); | |
1097 func = Fcons (make_int (id), func); | |
1098 | |
1099 gcpro_popup_callbacks (id, func); | |
1100 | |
1101 gtk_signal_connect_full (XGTK_OBJECT (obj)->object, (char *) XSTRING_DATA (name), | |
1102 NULL, __internal_callback_marshal, LISP_TO_VOID (func), | |
1103 __internal_callback_destroy, c_object_signal, c_after); | |
1104 return (Qt); | |
1105 } | |
1106 | |
1107 | |
1108 /* GTK_TYPE_BOXED wrapper for Emacs lisp */ | |
1204 | 1109 static const struct memory_description emacs_gtk_boxed_description [] = { |
960 | 1110 { XD_END } |
1111 }; | |
1112 | |
462 | 1113 static void |
2286 | 1114 emacs_gtk_boxed_printer (Lisp_Object obj, Lisp_Object printcharfun, |
1115 int UNUSED (escapeflag)) | |
462 | 1116 { |
1117 if (print_readably) | |
563 | 1118 printing_unreadable_object ("#<GtkBoxed %p>", XGTK_BOXED (obj)->object); |
462 | 1119 |
826 | 1120 write_c_string (printcharfun, "#<GtkBoxed ("); |
1121 write_c_string (printcharfun, gtk_type_name (XGTK_BOXED (obj)->object_type)); | |
800 | 1122 write_fmt_string (printcharfun, ") %p>", (void *) XGTK_BOXED (obj)->object); |
462 | 1123 } |
1124 | |
1125 static int | |
2286 | 1126 emacs_gtk_boxed_equality (Lisp_Object o1, Lisp_Object o2, int UNUSED (depth)) |
462 | 1127 { |
1128 emacs_gtk_boxed_data *data1 = XGTK_BOXED(o1); | |
1129 emacs_gtk_boxed_data *data2 = XGTK_BOXED(o2); | |
1130 | |
1131 return ((data1->object == data2->object) && | |
1132 (data1->object_type == data2->object_type)); | |
1133 } | |
1134 | |
2515 | 1135 static Hashcode |
2286 | 1136 emacs_gtk_boxed_hash (Lisp_Object obj, int UNUSED (depth)) |
462 | 1137 { |
1138 emacs_gtk_boxed_data *data = XGTK_BOXED(obj); | |
2515 | 1139 return (HASH2 ((Hashcode) data->object, data->object_type)); |
462 | 1140 } |
1141 | |
960 | 1142 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("GtkBoxed", emacs_gtk_boxed, |
1143 0, /*dumpable-flag*/ | |
1144 0, /* marker function */ | |
1204 | 1145 emacs_gtk_boxed_printer, |
960 | 1146 0, /* nuker */ |
1204 | 1147 emacs_gtk_boxed_equality, |
1148 emacs_gtk_boxed_hash, | |
1149 emacs_gtk_boxed_description, | |
960 | 1150 0, /* get prop */ |
1151 0, /* put prop */ | |
1152 0, /* rem prop */ | |
1153 0, /* plist */ | |
1154 emacs_gtk_boxed_data); | |
462 | 1155 /* Currently defined GTK_TYPE_BOXED structures are: |
1156 | |
1157 GtkAccelGroup - | |
1158 GtkSelectionData - | |
1159 GtkStyle - | |
1160 GtkCTreeNode - | |
1161 GdkColormap - | |
1162 GdkVisual - | |
1163 GdkFont - | |
1164 GdkWindow - | |
1165 GdkDragContext - | |
1166 GdkEvent - | |
1167 GdkColor - | |
1168 */ | |
1169 static emacs_gtk_boxed_data * | |
1170 allocate_emacs_gtk_boxed_data (void) | |
1171 { | |
3017 | 1172 emacs_gtk_boxed_data *data = ALLOC_LCRECORD_TYPE (emacs_gtk_boxed_data, |
462 | 1173 &lrecord_emacs_gtk_boxed); |
1174 | |
1175 data->object = NULL; | |
1176 data->object_type = GTK_TYPE_INVALID; | |
1177 | |
1178 return (data); | |
1179 } | |
1180 | |
1181 Lisp_Object build_gtk_boxed (void *obj, GtkType t) | |
1182 { | |
1183 Lisp_Object retval = Qnil; | |
1184 emacs_gtk_boxed_data *data = NULL; | |
1185 | |
1186 if (GTK_FUNDAMENTAL_TYPE (t) != GTK_TYPE_BOXED) | |
2500 | 1187 ABORT(); |
462 | 1188 |
1189 data = allocate_emacs_gtk_boxed_data (); | |
1190 data->object = obj; | |
1191 data->object_type = t; | |
1192 | |
797 | 1193 retval = wrap_emacs_gtk_boxed (data); |
462 | 1194 |
1195 return (retval); | |
1196 } | |
1197 | |
1198 | |
1199 /* The automatically generated structure access routines */ | |
1200 #include "emacs-widget-accessors.c" | |
1201 | |
1202 /* The hand generated funky functions that we can't just import using the FFI */ | |
1203 #include "ui-byhand.c" | |
1204 | |
1205 /* The glade support */ | |
1206 #include "glade.c" | |
1207 | |
1208 | |
1209 /* Type manipulation */ | |
1210 DEFUN ("gtk-fundamental-type", Fgtk_fundamental_type, 1, 1, 0, /* | |
1211 Load a shared library DLL into XEmacs. No initialization routines are required. | |
1212 This is for loading dependency DLLs into XEmacs. | |
1213 */ | |
1214 (type)) | |
1215 { | |
1216 GtkType t; | |
1217 | |
1218 if (SYMBOLP (type)) | |
1219 type = Fsymbol_name (type); | |
1220 | |
1221 CHECK_STRING (type); | |
1222 | |
1223 t = gtk_type_from_name ((char *) XSTRING_DATA (type)); | |
1224 | |
1225 if (t == GTK_TYPE_INVALID) | |
1226 { | |
563 | 1227 invalid_argument ("Not a GTK type", type); |
462 | 1228 } |
1229 return (make_int (GTK_FUNDAMENTAL_TYPE (t))); | |
1230 } | |
1231 | |
1232 DEFUN ("gtk-object-type", Fgtk_object_type, 1, 1, 0, /* | |
1233 Return the GtkType of OBJECT. | |
1234 */ | |
1235 (object)) | |
1236 { | |
1237 CHECK_GTK_OBJECT (object); | |
1238 return (make_int (GTK_OBJECT_TYPE (XGTK_OBJECT (object)->object))); | |
1239 } | |
1240 | |
1241 DEFUN ("gtk-describe-type", Fgtk_describe_type, 1, 1, 0, /* | |
1242 Returns a cons of two lists describing the Gtk object TYPE. | |
1243 The car is a list of all the signals that it will emit. | |
1244 The cdr is a list of all the magic properties it has. | |
1245 */ | |
1246 (type)) | |
1247 { | |
1248 Lisp_Object rval, signals, props; | |
1249 GtkType t; | |
1250 | |
1251 props = signals = rval = Qnil; | |
1252 | |
1253 if (SYMBOLP (type)) | |
1254 { | |
1255 type = Fsymbol_name (type); | |
1256 } | |
1257 | |
1258 if (STRINGP (type)) | |
1259 { | |
2054 | 1260 t = gtk_type_from_name ((gchar*) XSTRING_DATA (type)); |
462 | 1261 if (t == GTK_TYPE_INVALID) |
1262 { | |
563 | 1263 invalid_argument ("Not a GTK type", type); |
462 | 1264 } |
1265 } | |
1266 else | |
1267 { | |
1268 CHECK_INT (type); | |
1269 t = XINT (type); | |
1270 } | |
1271 | |
1272 if (GTK_FUNDAMENTAL_TYPE (t) != GTK_TYPE_OBJECT) | |
1273 { | |
563 | 1274 invalid_argument ("Not a GtkObject", type); |
462 | 1275 } |
1276 | |
1277 /* Need to do stupid shit like this to get the args | |
1278 ** registered... damn GTK and its lazy loading | |
1279 */ | |
1280 { | |
1281 GtkArg args[3]; | |
1282 GtkObject *obj = gtk_object_newv (t, 0, args); | |
1283 | |
1284 gtk_object_destroy(obj); | |
1285 } | |
1286 | |
1287 do | |
1288 { | |
1289 guint i; | |
1290 | |
1291 /* Do the magic arguments first */ | |
1292 { | |
1293 GtkArg *args; | |
1294 guint32 *flags; | |
1295 guint n_args; | |
1296 | |
1297 args = gtk_object_query_args(t,&flags,&n_args); | |
1298 | |
1299 for (i = 0; i < n_args; i++) | |
1300 { | |
1301 props = Fcons (Fcons (intern (gtk_type_name(args[i].type)), | |
1302 intern (args[i].name)), props); | |
1303 } | |
1304 | |
1305 g_free (args); | |
1306 g_free (flags); | |
1307 } | |
1308 | |
1309 /* Now the signals */ | |
1310 { | |
1311 GtkObjectClass *klass; | |
1312 GtkSignalQuery *query; | |
1313 guint32 *gtk_signals; | |
1314 guint n_signals; | |
1315 | |
1316 klass = (GtkObjectClass *) gtk_type_class (t); | |
1317 gtk_signals = klass->signals; | |
1318 n_signals = klass->nsignals; | |
1319 | |
1320 for (i = 0; i < n_signals; i++) | |
1321 { | |
1322 Lisp_Object params = Qnil; | |
1323 | |
1324 query = gtk_signal_query (gtk_signals[i]); | |
1325 | |
1326 if (query) | |
1327 { | |
1328 if (query->nparams) | |
1329 { | |
1330 int j; | |
1331 | |
1332 for (j = query->nparams - 1; j >= 0; j--) | |
1333 { | |
1334 params = Fcons (intern (gtk_type_name (query->params[j])), params); | |
1335 } | |
1336 } | |
1337 | |
1338 signals = Fcons (Fcons (intern (gtk_type_name (query->return_val)), | |
1339 Fcons (intern (query->signal_name), | |
1340 params)), | |
1341 signals); | |
1342 | |
1343 g_free (query); | |
1344 } | |
1345 } | |
1346 } | |
1347 t = gtk_type_parent(t); | |
1348 } while (t != GTK_TYPE_INVALID); | |
1349 | |
1350 rval = Fcons (signals, props); | |
1351 | |
1352 return (rval); | |
1353 } | |
1354 | |
1355 | |
1356 void | |
1357 syms_of_ui_gtk (void) | |
1358 { | |
1359 INIT_LRECORD_IMPLEMENTATION (emacs_ffi); | |
1360 INIT_LRECORD_IMPLEMENTATION (emacs_gtk_object); | |
1361 INIT_LRECORD_IMPLEMENTATION (emacs_gtk_boxed); | |
563 | 1362 DEFSYMBOL_MULTIWORD_PREDICATE (Qemacs_ffip); |
1363 DEFSYMBOL_MULTIWORD_PREDICATE (Qemacs_gtk_objectp); | |
1364 DEFSYMBOL_MULTIWORD_PREDICATE (Qemacs_gtk_boxedp); | |
1365 DEFSYMBOL (Qvoid); | |
462 | 1366 DEFSUBR (Fdll_load); |
1367 DEFSUBR (Fgtk_import_function_internal); | |
1368 DEFSUBR (Fgtk_import_variable_internal); | |
1369 DEFSUBR (Fgtk_signal_connect); | |
1370 DEFSUBR (Fgtk_call_function); | |
1371 DEFSUBR (Fgtk_fundamental_type); | |
1372 DEFSUBR (Fgtk_object_type); | |
1373 DEFSUBR (Fgtk_describe_type); | |
1374 syms_of_widget_accessors (); | |
1375 syms_of_ui_byhand (); | |
1376 syms_of_glade (); | |
1377 } | |
1378 | |
1379 void | |
1380 vars_of_ui_gtk (void) | |
1381 { | |
1382 Fprovide (intern ("gtk-ui")); | |
1383 DEFVAR_LISP ("gtk-enumeration-info", &Venumeration_info /* | |
1384 A hashtable holding type information about GTK enumerations and flags. | |
1385 Do NOT modify unless you really understand ui-gtk.c. | |
1386 */); | |
1387 | |
1388 Venumeration_info = Qnil; | |
1389 vars_of_glade (); | |
1390 } | |
1391 | |
1392 | |
1393 /* Various utility functions */ | |
778 | 1394 #if 0 |
462 | 1395 void describe_gtk_arg (GtkArg *arg) |
1396 { | |
1397 GtkArg a = *arg; | |
1398 | |
1399 switch (GTK_FUNDAMENTAL_TYPE (a.type)) | |
1400 { | |
1401 /* flag types */ | |
1402 case GTK_TYPE_CHAR: | |
1403 stderr_out ("char: %c\n", GTK_VALUE_CHAR (a)); | |
1404 break; | |
1405 case GTK_TYPE_UCHAR: | |
1406 stderr_out ("uchar: %c\n", GTK_VALUE_CHAR (a)); | |
1407 break; | |
1408 case GTK_TYPE_BOOL: | |
1409 stderr_out ("uchar: %s\n", GTK_VALUE_BOOL (a) ? "true" : "false"); | |
1410 break; | |
1411 case GTK_TYPE_INT: | |
1412 stderr_out ("int: %d\n", GTK_VALUE_INT (a)); | |
1413 break; | |
1414 case GTK_TYPE_UINT: | |
1415 stderr_out ("uint: %du\n", GTK_VALUE_UINT (a)); | |
1416 break; | |
1417 case GTK_TYPE_LONG: | |
1418 stderr_out ("long: %ld\n", GTK_VALUE_LONG (a)); | |
1419 break; | |
1420 case GTK_TYPE_ULONG: | |
1421 stderr_out ("ulong: %lu\n", GTK_VALUE_ULONG (a)); | |
1422 break; | |
1423 case GTK_TYPE_FLOAT: | |
1424 stderr_out ("float: %g\n", GTK_VALUE_FLOAT (a)); | |
1425 break; | |
1426 case GTK_TYPE_DOUBLE: | |
1427 stderr_out ("double: %f\n", GTK_VALUE_DOUBLE (a)); | |
1428 break; | |
1429 case GTK_TYPE_STRING: | |
1430 stderr_out ("string: %s\n", GTK_VALUE_STRING (a)); | |
1431 break; | |
1432 case GTK_TYPE_ENUM: | |
1433 case GTK_TYPE_FLAGS: | |
1434 stderr_out ("%s: ", (a.type == GTK_TYPE_ENUM) ? "enum" : "flag"); | |
1435 { | |
1436 GtkEnumValue *vals = gtk_type_enum_get_values (a.type); | |
1437 | |
1438 while (vals && vals->value_name && (vals->value != GTK_VALUE_ENUM(a))) vals++; | |
1439 | |
1440 stderr_out ("%s\n", vals ? vals->value_name : "!!! UNKNOWN ENUM VALUE !!!"); | |
1441 } | |
1442 break; | |
1443 case GTK_TYPE_BOXED: | |
1444 stderr_out ("boxed: %p\n", GTK_VALUE_BOXED (a)); | |
1445 break; | |
1446 case GTK_TYPE_POINTER: | |
1447 stderr_out ("pointer: %p\n", GTK_VALUE_BOXED (a)); | |
1448 break; | |
1449 | |
1450 /* structured types */ | |
1451 case GTK_TYPE_SIGNAL: | |
1452 case GTK_TYPE_ARGS: /* This we can do as a list of values */ | |
2500 | 1453 ABORT(); |
462 | 1454 case GTK_TYPE_CALLBACK: |
1455 stderr_out ("callback fn: ...\n"); | |
1456 break; | |
1457 case GTK_TYPE_C_CALLBACK: | |
1458 case GTK_TYPE_FOREIGN: | |
2500 | 1459 ABORT(); |
462 | 1460 |
1461 /* base type of the object system */ | |
1462 case GTK_TYPE_OBJECT: | |
1463 if (GTK_VALUE_OBJECT (a)) | |
1464 stderr_out ("object: %s\n", gtk_type_name (GTK_OBJECT_TYPE (GTK_VALUE_OBJECT (a)))); | |
1465 else | |
1466 stderr_out ("object: NULL\n"); | |
1467 break; | |
1468 | |
1469 default: | |
2500 | 1470 ABORT(); |
462 | 1471 } |
1472 } | |
778 | 1473 #endif |
462 | 1474 |
1475 Lisp_Object gtk_type_to_lisp (GtkArg *arg) | |
1476 { | |
1477 switch (GTK_FUNDAMENTAL_TYPE (arg->type)) | |
1478 { | |
1479 case GTK_TYPE_NONE: | |
1480 return (Qnil); | |
1481 case GTK_TYPE_CHAR: | |
1482 return (make_char (GTK_VALUE_CHAR (*arg))); | |
1483 case GTK_TYPE_UCHAR: | |
1484 return (make_char (GTK_VALUE_UCHAR (*arg))); | |
1485 case GTK_TYPE_BOOL: | |
1486 return (GTK_VALUE_BOOL (*arg) ? Qt : Qnil); | |
1487 case GTK_TYPE_INT: | |
1488 return (make_int (GTK_VALUE_INT (*arg))); | |
1489 case GTK_TYPE_UINT: | |
1490 return (make_int (GTK_VALUE_INT (*arg))); | |
1491 case GTK_TYPE_LONG: /* I think these are wrong! */ | |
1492 return (make_int (GTK_VALUE_INT (*arg))); | |
1493 case GTK_TYPE_ULONG: /* I think these are wrong! */ | |
1494 return (make_int (GTK_VALUE_INT (*arg))); | |
1495 case GTK_TYPE_FLOAT: | |
1496 return (make_float (GTK_VALUE_FLOAT (*arg))); | |
1497 case GTK_TYPE_DOUBLE: | |
1498 return (make_float (GTK_VALUE_DOUBLE (*arg))); | |
1499 case GTK_TYPE_STRING: | |
1500 return (build_string (GTK_VALUE_STRING (*arg))); | |
1501 case GTK_TYPE_FLAGS: | |
1502 return (flags_to_list (GTK_VALUE_FLAGS (*arg), arg->type)); | |
1503 case GTK_TYPE_ENUM: | |
1504 return (enum_to_symbol (GTK_VALUE_ENUM (*arg), arg->type)); | |
1505 case GTK_TYPE_BOXED: | |
1506 if (arg->type == GTK_TYPE_GDK_EVENT) | |
1507 { | |
1508 return (gdk_event_to_emacs_event((GdkEvent *) GTK_VALUE_BOXED (*arg))); | |
1509 } | |
1510 | |
1511 if (GTK_VALUE_BOXED (*arg)) | |
1512 return (build_gtk_boxed (GTK_VALUE_BOXED (*arg), arg->type)); | |
1513 else | |
1514 return (Qnil); | |
1515 case GTK_TYPE_POINTER: | |
1516 if (GTK_VALUE_POINTER (*arg)) | |
1517 { | |
1518 Lisp_Object rval; | |
1519 | |
826 | 1520 rval = VOID_TO_LISP (GTK_VALUE_POINTER (*arg)); |
462 | 1521 return (rval); |
1522 } | |
1523 else | |
1524 return (Qnil); | |
1525 case GTK_TYPE_OBJECT: | |
1526 if (GTK_VALUE_OBJECT (*arg)) | |
1527 return (build_gtk_object (GTK_VALUE_OBJECT (*arg))); | |
1528 else | |
1529 return (Qnil); | |
1530 | |
1531 case GTK_TYPE_CALLBACK: | |
1532 { | |
1533 Lisp_Object rval; | |
1534 | |
826 | 1535 rval = VOID_TO_LISP (GTK_VALUE_CALLBACK (*arg).data); |
462 | 1536 |
1537 return (rval); | |
1538 } | |
1539 | |
1540 default: | |
2054 | 1541 if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(arg->type, GTK_TYPE_LISTOF)) |
462 | 1542 { |
1543 if (!GTK_VALUE_POINTER (*arg)) | |
1544 return (Qnil); | |
1545 else | |
1546 { | |
1547 return (xemacs_gtklist_to_list (arg)); | |
1548 } | |
1549 } | |
1550 stderr_out ("Do not know how to convert `%s' to lisp!\n", gtk_type_name (arg->type)); | |
2500 | 1551 ABORT (); |
462 | 1552 } |
1553 /* This is chuck reminding GCC to... SHUT UP! */ | |
1554 return (Qnil); | |
1555 } | |
1556 | |
1557 int lisp_to_gtk_type (Lisp_Object obj, GtkArg *arg) | |
1558 { | |
1559 switch (GTK_FUNDAMENTAL_TYPE (arg->type)) | |
1560 { | |
1561 /* flag types */ | |
1562 case GTK_TYPE_NONE: | |
1563 return (0); | |
1564 case GTK_TYPE_CHAR: | |
1565 { | |
867 | 1566 Ichar c; |
462 | 1567 |
1568 CHECK_CHAR_COERCE_INT (obj); | |
1569 c = XCHAR (obj); | |
1570 GTK_VALUE_CHAR (*arg) = c; | |
1571 } | |
1572 break; | |
1573 case GTK_TYPE_UCHAR: | |
1574 { | |
867 | 1575 Ichar c; |
462 | 1576 |
1577 CHECK_CHAR_COERCE_INT (obj); | |
1578 c = XCHAR (obj); | |
1579 GTK_VALUE_CHAR (*arg) = c; | |
1580 } | |
1581 break; | |
1582 case GTK_TYPE_BOOL: | |
1583 GTK_VALUE_BOOL (*arg) = NILP (obj) ? FALSE : TRUE; | |
1584 break; | |
1585 case GTK_TYPE_INT: | |
1586 case GTK_TYPE_UINT: | |
1587 if (NILP (obj) || EQ (Qt, obj)) | |
1588 { | |
1589 /* For we are a kind mistress and allow sending t/nil for | |
1590 1/0 to stupid GTK functions that say they take guint or | |
1591 gint in the header files, but actually treat it like a | |
1592 bool. *sigh* | |
1593 */ | |
1594 GTK_VALUE_INT(*arg) = NILP (obj) ? 0 : 1; | |
1595 } | |
1596 else | |
1597 { | |
1598 CHECK_INT (obj); | |
1599 GTK_VALUE_INT(*arg) = XINT (obj); | |
1600 } | |
1601 break; | |
1602 case GTK_TYPE_LONG: | |
1603 case GTK_TYPE_ULONG: | |
2500 | 1604 ABORT(); |
462 | 1605 case GTK_TYPE_FLOAT: |
1606 CHECK_INT_OR_FLOAT (obj); | |
1607 GTK_VALUE_FLOAT(*arg) = extract_float (obj); | |
1608 break; | |
1609 case GTK_TYPE_DOUBLE: | |
1610 CHECK_INT_OR_FLOAT (obj); | |
1611 GTK_VALUE_DOUBLE(*arg) = extract_float (obj); | |
1612 break; | |
1613 case GTK_TYPE_STRING: | |
1614 if (NILP (obj)) | |
1615 GTK_VALUE_STRING (*arg) = NULL; | |
1616 else | |
1617 { | |
1618 CHECK_STRING (obj); | |
1619 GTK_VALUE_STRING (*arg) = (char *) XSTRING_DATA (obj); | |
1620 } | |
1621 break; | |
1622 case GTK_TYPE_ENUM: | |
1623 case GTK_TYPE_FLAGS: | |
1624 /* Convert a lisp symbol to a GTK enum */ | |
1625 GTK_VALUE_ENUM(*arg) = lisp_to_flag (obj, arg->type); | |
1626 break; | |
1627 case GTK_TYPE_BOXED: | |
1628 if (NILP (obj)) | |
1629 { | |
1630 GTK_VALUE_BOXED(*arg) = NULL; | |
1631 } | |
1632 else if (GTK_BOXEDP (obj)) | |
1633 { | |
1634 GTK_VALUE_BOXED(*arg) = XGTK_BOXED (obj)->object; | |
1635 } | |
1636 else if (arg->type == GTK_TYPE_STYLE) | |
1637 { | |
1638 obj = Ffind_face (obj); | |
1639 CHECK_FACE (obj); | |
1640 GTK_VALUE_BOXED(*arg) = face_to_style (obj); | |
1641 } | |
1642 else if (arg->type == GTK_TYPE_GDK_GC) | |
1643 { | |
1644 obj = Ffind_face (obj); | |
1645 CHECK_FACE (obj); | |
1646 GTK_VALUE_BOXED(*arg) = face_to_gc (obj); | |
1647 } | |
1648 else if (arg->type == GTK_TYPE_GDK_WINDOW) | |
1649 { | |
1650 if (GLYPHP (obj)) | |
1651 { | |
1652 Lisp_Object window = Fselected_window (Qnil); | |
793 | 1653 Lisp_Object instance = |
1654 glyph_image_instance (obj, window, ERROR_ME_DEBUG_WARN, 1); | |
462 | 1655 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (instance); |
1656 | |
1657 switch (XIMAGE_INSTANCE_TYPE (instance)) | |
1658 { | |
1659 case IMAGE_TEXT: | |
1660 case IMAGE_POINTER: | |
1661 case IMAGE_SUBWINDOW: | |
1662 case IMAGE_NOTHING: | |
1663 GTK_VALUE_BOXED(*arg) = NULL; | |
1664 break; | |
1665 | |
1666 case IMAGE_MONO_PIXMAP: | |
1667 case IMAGE_COLOR_PIXMAP: | |
1668 GTK_VALUE_BOXED(*arg) = IMAGE_INSTANCE_GTK_PIXMAP (p); | |
1669 break; | |
1670 } | |
1671 } | |
1672 else if (GTK_OBJECTP (obj) && GTK_IS_WIDGET (XGTK_OBJECT (obj)->object)) | |
1673 { | |
1674 GTK_VALUE_BOXED(*arg) = GTK_WIDGET (XGTK_OBJECT (obj))->window; | |
1675 } | |
1676 else | |
1677 { | |
563 | 1678 invalid_argument ("Don't know how to convert object to GDK_WINDOW", obj); |
462 | 1679 } |
1680 break; | |
1681 } | |
1682 else if (arg->type == GTK_TYPE_GDK_COLOR) | |
1683 { | |
1684 if (COLOR_SPECIFIERP (obj)) | |
1685 { | |
1686 /* If it is a specifier, we just convert it to an | |
1687 instance, and let the ifs below handle it. | |
1688 */ | |
1689 obj = Fspecifier_instance (obj, Qnil, Qnil, Qnil); | |
1690 } | |
1691 | |
1692 if (COLOR_INSTANCEP (obj)) | |
1693 { | |
1694 /* Easiest one */ | |
1695 GTK_VALUE_BOXED(*arg) = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (obj)); | |
1696 } | |
1697 else if (STRINGP (obj)) | |
1698 { | |
563 | 1699 invalid_argument ("Please use a color specifier or instance, not a string", obj); |
462 | 1700 } |
1701 else | |
1702 { | |
563 | 1703 invalid_argument ("Don't know how to convert to GdkColor", obj); |
462 | 1704 } |
1705 } | |
1706 else if (arg->type == GTK_TYPE_GDK_FONT) | |
1707 { | |
1708 if (SYMBOLP (obj)) | |
1709 { | |
1710 /* If it is a symbol, we treat that as a face name */ | |
1711 obj = Ffind_face (obj); | |
1712 } | |
1713 | |
1714 if (FACEP (obj)) | |
1715 { | |
1716 /* If it is a face, we just grab the font specifier, and | |
1717 cascade down until we finally reach a FONT_INSTANCE | |
1718 */ | |
1719 obj = Fget (obj, Qfont, Qnil); | |
1720 } | |
1721 | |
1722 if (FONT_SPECIFIERP (obj)) | |
1723 { | |
1724 /* If it is a specifier, we just convert it to an | |
1725 instance, and let the ifs below handle it | |
1726 */ | |
1727 obj = Fspecifier_instance (obj, Qnil, Qnil, Qnil); | |
1728 } | |
1729 | |
1730 if (FONT_INSTANCEP (obj)) | |
1731 { | |
1732 /* Easiest one */ | |
1733 GTK_VALUE_BOXED(*arg) = FONT_INSTANCE_GTK_FONT (XFONT_INSTANCE (obj)); | |
1734 } | |
1735 else if (STRINGP (obj)) | |
1736 { | |
563 | 1737 invalid_argument ("Please use a font specifier or instance, not a string", obj); |
462 | 1738 } |
1739 else | |
1740 { | |
563 | 1741 invalid_argument ("Don't know how to convert to GdkColor", obj); |
462 | 1742 } |
1743 } | |
1744 else | |
1745 { | |
1746 /* Unknown type to convert to boxed */ | |
1747 stderr_out ("Don't know how to convert to boxed!\n"); | |
1748 GTK_VALUE_BOXED(*arg) = NULL; | |
1749 } | |
1750 break; | |
1751 | |
1752 case GTK_TYPE_POINTER: | |
1753 if (NILP (obj)) | |
1754 GTK_VALUE_POINTER(*arg) = NULL; | |
1755 else | |
1756 GTK_VALUE_POINTER(*arg) = LISP_TO_VOID (obj); | |
1757 break; | |
1758 | |
1759 /* structured types */ | |
1760 case GTK_TYPE_SIGNAL: | |
1761 case GTK_TYPE_ARGS: /* This we can do as a list of values */ | |
1762 case GTK_TYPE_C_CALLBACK: | |
1763 case GTK_TYPE_FOREIGN: | |
1764 stderr_out ("Do not know how to convert `%s' from lisp!\n", gtk_type_name (arg->type)); | |
1765 return (-1); | |
1766 | |
1767 #if 0 | |
1768 /* #### BILL! */ | |
1769 /* This is not used, and does not work with union type */ | |
1770 case GTK_TYPE_CALLBACK: | |
1771 { | |
1772 GUI_ID id; | |
1773 | |
1774 id = new_gui_id (); | |
1775 obj = Fcons (Qnil, obj); /* Empty data */ | |
1776 obj = Fcons (make_int (id), obj); | |
1777 | |
1778 gcpro_popup_callbacks (id, obj); | |
1779 | |
1780 GTK_VALUE_CALLBACK(*arg).marshal = __internal_callback_marshal; | |
1781 GTK_VALUE_CALLBACK(*arg).data = (gpointer) obj; | |
1782 GTK_VALUE_CALLBACK(*arg).notify = __internal_callback_destroy; | |
1783 } | |
1784 break; | |
1785 #endif | |
1786 | |
1787 /* base type of the object system */ | |
1788 case GTK_TYPE_OBJECT: | |
1789 if (NILP (obj)) | |
1790 GTK_VALUE_OBJECT (*arg) = NULL; | |
1791 else | |
1792 { | |
1793 CHECK_GTK_OBJECT (obj); | |
1794 if (XGTK_OBJECT (obj)->alive_p) | |
1795 GTK_VALUE_OBJECT (*arg) = XGTK_OBJECT (obj)->object; | |
1796 else | |
563 | 1797 invalid_argument ("Attempting to pass dead object to GTK function", obj); |
462 | 1798 } |
1799 break; | |
1800 | |
1801 default: | |
2054 | 1802 if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(arg->type, GTK_TYPE_ARRAY)) |
462 | 1803 { |
1804 if (NILP (obj)) | |
1805 GTK_VALUE_POINTER(*arg) = NULL; | |
1806 else | |
1807 { | |
1808 xemacs_list_to_array (obj, arg); | |
1809 } | |
1810 } | |
2054 | 1811 else if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(arg->type, GTK_TYPE_LISTOF)) |
462 | 1812 { |
1813 if (NILP (obj)) | |
1814 GTK_VALUE_POINTER(*arg) = NULL; | |
1815 else | |
1816 { | |
1817 xemacs_list_to_gtklist (obj, arg); | |
1818 } | |
1819 } | |
1820 else | |
1821 { | |
1822 stderr_out ("Do not know how to convert `%s' from lisp!\n", gtk_type_name (arg->type)); | |
2500 | 1823 ABORT(); |
462 | 1824 } |
1825 break; | |
1826 } | |
1827 | |
1828 return (0); | |
1829 } | |
1830 | |
1883 | 1831 /* Convert lisp types to GTK return types. This is identical to |
1832 lisp_to_gtk_type() except that the macro used to set the value is | |
1833 different. | |
1834 | |
1835 ### There should be some way of combining these two functions. | |
1836 */ | |
1837 int lisp_to_gtk_ret_type (Lisp_Object obj, GtkArg *arg) | |
1838 { | |
1839 switch (GTK_FUNDAMENTAL_TYPE (arg->type)) | |
1840 { | |
1841 /* flag types */ | |
1842 case GTK_TYPE_NONE: | |
1843 return (0); | |
1844 case GTK_TYPE_CHAR: | |
1845 { | |
1846 Ichar c; | |
1847 | |
1848 CHECK_CHAR_COERCE_INT (obj); | |
1849 c = XCHAR (obj); | |
1850 *(GTK_RETLOC_CHAR (*arg)) = c; | |
1851 } | |
1852 break; | |
1853 case GTK_TYPE_UCHAR: | |
1854 { | |
1855 Ichar c; | |
1856 | |
1857 CHECK_CHAR_COERCE_INT (obj); | |
1858 c = XCHAR (obj); | |
1859 *(GTK_RETLOC_CHAR (*arg)) = c; | |
1860 } | |
1861 break; | |
1862 case GTK_TYPE_BOOL: | |
1863 *(GTK_RETLOC_BOOL (*arg)) = NILP (obj) ? FALSE : TRUE; | |
1864 break; | |
1865 case GTK_TYPE_INT: | |
1866 case GTK_TYPE_UINT: | |
1867 if (NILP (obj) || EQ (Qt, obj)) | |
1868 { | |
1869 /* For we are a kind mistress and allow sending t/nil for | |
1870 1/0 to stupid GTK functions that say they take guint or | |
1871 gint in the header files, but actually treat it like a | |
1872 bool. *sigh* | |
1873 */ | |
1874 *(GTK_RETLOC_INT(*arg)) = NILP (obj) ? 0 : 1; | |
1875 } | |
1876 else | |
1877 { | |
1878 CHECK_INT (obj); | |
1879 *(GTK_RETLOC_INT(*arg)) = XINT (obj); | |
1880 } | |
1881 break; | |
1882 case GTK_TYPE_LONG: | |
1883 case GTK_TYPE_ULONG: | |
2500 | 1884 ABORT(); |
1883 | 1885 case GTK_TYPE_FLOAT: |
1886 CHECK_INT_OR_FLOAT (obj); | |
1887 *(GTK_RETLOC_FLOAT(*arg)) = extract_float (obj); | |
1888 break; | |
1889 case GTK_TYPE_DOUBLE: | |
1890 CHECK_INT_OR_FLOAT (obj); | |
1891 *(GTK_RETLOC_DOUBLE(*arg)) = extract_float (obj); | |
1892 break; | |
1893 case GTK_TYPE_STRING: | |
1894 if (NILP (obj)) | |
1895 *(GTK_RETLOC_STRING (*arg)) = NULL; | |
1896 else | |
1897 { | |
1898 CHECK_STRING (obj); | |
1899 *(GTK_RETLOC_STRING (*arg)) = (char *) XSTRING_DATA (obj); | |
1900 } | |
1901 break; | |
1902 case GTK_TYPE_ENUM: | |
1903 case GTK_TYPE_FLAGS: | |
1904 /* Convert a lisp symbol to a GTK enum */ | |
1905 *(GTK_RETLOC_ENUM(*arg)) = lisp_to_flag (obj, arg->type); | |
1906 break; | |
1907 case GTK_TYPE_BOXED: | |
1908 if (NILP (obj)) | |
1909 { | |
1910 *(GTK_RETLOC_BOXED(*arg)) = NULL; | |
1911 } | |
1912 else if (GTK_BOXEDP (obj)) | |
1913 { | |
1914 *(GTK_RETLOC_BOXED(*arg)) = XGTK_BOXED (obj)->object; | |
1915 } | |
1916 else if (arg->type == GTK_TYPE_STYLE) | |
1917 { | |
1918 obj = Ffind_face (obj); | |
1919 CHECK_FACE (obj); | |
1920 *(GTK_RETLOC_BOXED(*arg)) = face_to_style (obj); | |
1921 } | |
1922 else if (arg->type == GTK_TYPE_GDK_GC) | |
1923 { | |
1924 obj = Ffind_face (obj); | |
1925 CHECK_FACE (obj); | |
1926 *(GTK_RETLOC_BOXED(*arg)) = face_to_gc (obj); | |
1927 } | |
1928 else if (arg->type == GTK_TYPE_GDK_WINDOW) | |
1929 { | |
1930 if (GLYPHP (obj)) | |
1931 { | |
1932 Lisp_Object window = Fselected_window (Qnil); | |
1933 Lisp_Object instance = | |
1934 glyph_image_instance (obj, window, ERROR_ME_DEBUG_WARN, 1); | |
1935 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (instance); | |
1936 | |
1937 switch (XIMAGE_INSTANCE_TYPE (instance)) | |
1938 { | |
1939 case IMAGE_TEXT: | |
1940 case IMAGE_POINTER: | |
1941 case IMAGE_SUBWINDOW: | |
1942 case IMAGE_NOTHING: | |
1943 *(GTK_RETLOC_BOXED(*arg)) = NULL; | |
1944 break; | |
1945 | |
1946 case IMAGE_MONO_PIXMAP: | |
1947 case IMAGE_COLOR_PIXMAP: | |
1948 *(GTK_RETLOC_BOXED(*arg)) = IMAGE_INSTANCE_GTK_PIXMAP (p); | |
1949 break; | |
1950 } | |
1951 } | |
1952 else if (GTK_OBJECTP (obj) && GTK_IS_WIDGET (XGTK_OBJECT (obj)->object)) | |
1953 { | |
1954 *(GTK_RETLOC_BOXED(*arg)) = GTK_WIDGET (XGTK_OBJECT (obj))->window; | |
1955 } | |
1956 else | |
1957 { | |
1958 invalid_argument ("Don't know how to convert object to GDK_WINDOW", obj); | |
1959 } | |
1960 break; | |
1961 } | |
1962 else if (arg->type == GTK_TYPE_GDK_COLOR) | |
1963 { | |
1964 if (COLOR_SPECIFIERP (obj)) | |
1965 { | |
1966 /* If it is a specifier, we just convert it to an | |
1967 instance, and let the ifs below handle it. | |
1968 */ | |
1969 obj = Fspecifier_instance (obj, Qnil, Qnil, Qnil); | |
1970 } | |
1971 | |
1972 if (COLOR_INSTANCEP (obj)) | |
1973 { | |
1974 /* Easiest one */ | |
1975 *(GTK_RETLOC_BOXED(*arg)) = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (obj)); | |
1976 } | |
1977 else if (STRINGP (obj)) | |
1978 { | |
1979 invalid_argument ("Please use a color specifier or instance, not a string", obj); | |
1980 } | |
1981 else | |
1982 { | |
1983 invalid_argument ("Don't know how to convert to GdkColor", obj); | |
1984 } | |
1985 } | |
1986 else if (arg->type == GTK_TYPE_GDK_FONT) | |
1987 { | |
1988 if (SYMBOLP (obj)) | |
1989 { | |
1990 /* If it is a symbol, we treat that as a face name */ | |
1991 obj = Ffind_face (obj); | |
1992 } | |
1993 | |
1994 if (FACEP (obj)) | |
1995 { | |
1996 /* If it is a face, we just grab the font specifier, and | |
1997 cascade down until we finally reach a FONT_INSTANCE | |
1998 */ | |
1999 obj = Fget (obj, Qfont, Qnil); | |
2000 } | |
2001 | |
2002 if (FONT_SPECIFIERP (obj)) | |
2003 { | |
2004 /* If it is a specifier, we just convert it to an | |
2005 instance, and let the ifs below handle it | |
2006 */ | |
2007 obj = Fspecifier_instance (obj, Qnil, Qnil, Qnil); | |
2008 } | |
2009 | |
2010 if (FONT_INSTANCEP (obj)) | |
2011 { | |
2012 /* Easiest one */ | |
2013 *(GTK_RETLOC_BOXED(*arg)) = FONT_INSTANCE_GTK_FONT (XFONT_INSTANCE (obj)); | |
2014 } | |
2015 else if (STRINGP (obj)) | |
2016 { | |
2017 invalid_argument ("Please use a font specifier or instance, not a string", obj); | |
2018 } | |
2019 else | |
2020 { | |
2021 invalid_argument ("Don't know how to convert to GdkColor", obj); | |
2022 } | |
2023 } | |
2024 else | |
2025 { | |
2026 /* Unknown type to convert to boxed */ | |
2027 stderr_out ("Don't know how to convert to boxed!\n"); | |
2028 *(GTK_RETLOC_BOXED(*arg)) = NULL; | |
2029 } | |
2030 break; | |
2031 | |
2032 case GTK_TYPE_POINTER: | |
2033 if (NILP (obj)) | |
2034 *(GTK_RETLOC_POINTER(*arg)) = NULL; | |
2035 else | |
2036 *(GTK_RETLOC_POINTER(*arg)) = LISP_TO_VOID (obj); | |
2037 break; | |
2038 | |
2039 /* structured types */ | |
2040 case GTK_TYPE_SIGNAL: | |
2041 case GTK_TYPE_ARGS: /* This we can do as a list of values */ | |
2042 case GTK_TYPE_C_CALLBACK: | |
2043 case GTK_TYPE_FOREIGN: | |
2044 stderr_out ("Do not know how to convert `%s' from lisp!\n", gtk_type_name (arg->type)); | |
2045 return (-1); | |
2046 | |
2047 #if 0 | |
2048 /* #### BILL! */ | |
2049 /* This is not used, and does not work with union type */ | |
2050 case GTK_TYPE_CALLBACK: | |
2051 { | |
2052 GUI_ID id; | |
2053 | |
2054 id = new_gui_id (); | |
2055 obj = Fcons (Qnil, obj); /* Empty data */ | |
2056 obj = Fcons (make_int (id), obj); | |
2057 | |
2058 gcpro_popup_callbacks (id, obj); | |
2059 | |
2060 *(GTK_RETLOC_CALLBACK(*arg)).marshal = __internal_callback_marshal; | |
2061 *(GTK_RETLOC_CALLBACK(*arg)).data = (gpointer) obj; | |
2062 *(GTK_RETLOC_CALLBACK(*arg)).notify = __internal_callback_destroy; | |
2063 } | |
2064 break; | |
2065 #endif | |
2066 | |
2067 /* base type of the object system */ | |
2068 case GTK_TYPE_OBJECT: | |
2069 if (NILP (obj)) | |
2070 *(GTK_RETLOC_OBJECT (*arg)) = NULL; | |
2071 else | |
2072 { | |
2073 CHECK_GTK_OBJECT (obj); | |
2074 if (XGTK_OBJECT (obj)->alive_p) | |
2075 *(GTK_RETLOC_OBJECT (*arg)) = XGTK_OBJECT (obj)->object; | |
2076 else | |
2077 invalid_argument ("Attempting to pass dead object to GTK function", obj); | |
2078 } | |
2079 break; | |
2080 | |
2081 default: | |
2054 | 2082 if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(arg->type, GTK_TYPE_ARRAY)) |
1883 | 2083 { |
2084 if (NILP (obj)) | |
2085 *(GTK_RETLOC_POINTER(*arg)) = NULL; | |
2086 else | |
2087 { | |
2088 xemacs_list_to_array (obj, arg); | |
2089 } | |
2090 } | |
2054 | 2091 else if (IS_XEMACS_GTK_FUNDAMENTAL_TYPE(arg->type, GTK_TYPE_LISTOF)) |
1883 | 2092 { |
2093 if (NILP (obj)) | |
2094 *(GTK_RETLOC_POINTER(*arg)) = NULL; | |
2095 else | |
2096 { | |
2097 xemacs_list_to_gtklist (obj, arg); | |
2098 } | |
2099 } | |
2100 else | |
2101 { | |
2102 stderr_out ("Do not know how to convert `%s' from lisp!\n", gtk_type_name (arg->type)); | |
2500 | 2103 ABORT(); |
1883 | 2104 } |
2105 break; | |
2106 } | |
2107 | |
2108 return (0); | |
2109 } | |
2110 | |
462 | 2111 /* This is used in glyphs-gtk.c as well */ |
2112 static Lisp_Object | |
2113 get_enumeration (GtkType t) | |
2114 { | |
2115 Lisp_Object alist; | |
2116 | |
2117 if (NILP (Venumeration_info)) | |
2118 { | |
2119 Venumeration_info = call2 (intern ("make-hashtable"), make_int (100), Qequal); | |
2120 } | |
2121 | |
2122 alist = Fgethash (make_int (t), Venumeration_info, Qnil); | |
2123 | |
2124 if (NILP (alist)) | |
2125 { | |
2126 import_gtk_enumeration_internal (t); | |
2127 alist = Fgethash (make_int (t), Venumeration_info, Qnil); | |
2128 } | |
2129 return (alist); | |
2130 } | |
2131 | |
2132 guint | |
2133 symbol_to_enum (Lisp_Object obj, GtkType t) | |
2134 { | |
2135 Lisp_Object alist = get_enumeration (t); | |
2136 Lisp_Object value = Qnil; | |
2137 | |
2138 if (NILP (alist)) | |
2139 { | |
563 | 2140 invalid_argument ("Unknown enumeration", build_string (gtk_type_name (t))); |
462 | 2141 } |
2142 | |
2143 value = Fassq (obj, alist); | |
2144 | |
2145 if (NILP (value)) | |
2146 { | |
563 | 2147 invalid_argument ("Unknown value", obj); |
462 | 2148 } |
2149 | |
2150 CHECK_INT (XCDR (value)); | |
2151 | |
2152 return (XINT (XCDR (value))); | |
2153 } | |
2154 | |
2155 static guint | |
2156 lisp_to_flag (Lisp_Object obj, GtkType t) | |
2157 { | |
2158 guint val = 0; | |
2159 | |
2160 if (NILP (obj)) | |
2161 { | |
2162 /* Do nothing */ | |
2163 } | |
2164 else if (SYMBOLP (obj)) | |
2165 { | |
2166 val = symbol_to_enum (obj, t); | |
2167 } | |
2168 else if (LISTP (obj)) | |
2169 { | |
2170 while (!NILP (obj)) | |
2171 { | |
2172 val |= symbol_to_enum (XCAR (obj), t); | |
2173 obj = XCDR (obj); | |
2174 } | |
2175 } | |
2176 else | |
2177 { | |
2500 | 2178 /* ABORT ()? */ |
462 | 2179 } |
2180 return (val); | |
2181 } | |
2182 | |
2183 static Lisp_Object | |
2184 flags_to_list (guint value, GtkType t) | |
2185 { | |
2186 Lisp_Object rval = Qnil; | |
2187 Lisp_Object alist = get_enumeration (t); | |
2188 | |
2189 while (!NILP (alist)) | |
2190 { | |
2191 if (value & XINT (XCDR (XCAR (alist)))) | |
2192 { | |
2193 rval = Fcons (XCAR (XCAR (alist)), rval); | |
2194 value &= ~(XINT (XCDR (XCAR (alist)))); | |
2195 } | |
2196 alist = XCDR (alist); | |
2197 } | |
2198 return (rval); | |
2199 } | |
2200 | |
2201 static Lisp_Object | |
2202 enum_to_symbol (guint value, GtkType t) | |
2203 { | |
2204 Lisp_Object alist = get_enumeration (t); | |
2205 Lisp_Object cell = Qnil; | |
2206 | |
2207 if (NILP (alist)) | |
2208 { | |
563 | 2209 invalid_argument ("Unknown enumeration", build_string (gtk_type_name (t))); |
462 | 2210 } |
2211 | |
2212 cell = Frassq (make_int (value), alist); | |
2213 | |
2214 return (NILP (cell) ? Qnil : XCAR (cell)); | |
2215 } |