Initial git import
[sxemacs] / src / ui / Gtk / frame-gtk.c
1 /* Functions for the X window system.
2    Copyright (C) 1989, 1992-5, 1997 Free Software Foundation, Inc.
3    Copyright (C) 1995, 1996 Ben Wing.
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Not synched with FSF. */
22
23 /* Substantially rewritten for SXEmacs.  */
24 /* Revamped to use Gdk/Gtk by William Perry */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "elhash.h"
30 #include "console-gtk.h"
31 #include "ui-gtk.h"
32 #include "glyphs-gtk.h"
33 #include "objects-gtk.h"
34 #include "scrollbar-gtk.h"
35
36 #include "gtk-xemacs.h"
37
38 #include "buffer.h"
39 #include "events/events.h"
40 #include "extents.h"
41 #include "ui/faces.h"
42 #include "ui/frame.h"
43 #include "ui/window.h"
44
45 #ifdef HAVE_GNOME
46 #include <libgnomeui/libgnomeui.h>
47 #endif
48
49 #ifdef HAVE_DRAGNDROP
50 #include "dragdrop.h"
51 #endif
52
53 #define BORDER_WIDTH 0
54 #define INTERNAL_BORDER_WIDTH 0
55
56 #define TRANSIENT_DATA_IDENTIFIER "sxemacs::transient_for"
57 #define UNMAPPED_DATA_IDENTIFIER "sxemacs::initially_unmapped"
58
59 #define STUPID_X_SPECIFIC_GTK_STUFF
60
61 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
62 #include <gdk/gdkx.h>
63 #endif
64
65 /* Default properties to use when creating frames.  */
66 Lisp_Object Vdefault_gtk_frame_plist;
67
68 Lisp_Object Qwindow_id;
69 Lisp_Object Qdetachable_menubar;
70 Lisp_Object Qtext_widget;
71 Lisp_Object Qcontainer_widget;
72 Lisp_Object Qshell_widget;
73
74 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
75 EXFUN(Fgtk_window_id, 1);
76 #endif
77
78 #ifdef HAVE_DRAGNDROP
79 enum {
80         TARGET_TYPE_STRING,
81         TARGET_TYPE_URI_LIST,
82 };
83
84 static GtkTargetEntry dnd_target_table[] = {
85         {"STRING", 0, TARGET_TYPE_STRING},
86         {"text/plain", 0, TARGET_TYPE_STRING},
87         {"text/uri-list", 0, TARGET_TYPE_URI_LIST},
88         {"_NETSCAPE_URL", 0, TARGET_TYPE_STRING}
89 };
90
91 static guint dnd_n_targets =
92     sizeof(dnd_target_table) / sizeof(dnd_target_table[0]);
93
94 #endif
95 \f
96 /************************************************************************/
97 /*                          helper functions                            */
98 /************************************************************************/
99
100 /* Return the Emacs frame-object which contains the given widget. */
101 struct frame *gtk_widget_to_frame(GtkWidget * w)
102 {
103         struct frame *f = NULL;
104
105         for (; w; w = w->parent) {
106                 if ((f = (struct frame *)gtk_object_get_data(GTK_OBJECT(w),
107                                                              GTK_DATA_FRAME_IDENTIFIER)))
108                         return (f);
109         }
110
111         return (selected_frame());
112 }
113
114 /* Return the Emacs frame-object corresponding to an X window */
115 struct frame *gtk_window_to_frame(struct device *d, GdkWindow * wdesc)
116 {
117         Lisp_Object tail, frame;
118         struct frame *f;
119
120         /* This function was previously written to accept only a window argument
121            (and to loop over all devices looking for a matching window), but
122            that is incorrect because window ID's are not unique across displays. */
123
124         for (tail = DEVICE_FRAME_LIST(d); CONSP(tail); tail = XCDR(tail)) {
125                 frame = XCAR(tail);
126                 if (!FRAMEP(frame))
127                         continue;
128                 f = XFRAME(frame);
129                 if (FRAME_GTK_P(f)
130                     && GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f)) == wdesc)
131                         return f;
132         }
133         return 0;
134 }
135
136 /* Like gtk_window_to_frame but also compares the window with the widget's
137    windows */
138 struct frame *gtk_any_window_to_frame(struct device *d, GdkWindow * w)
139 {
140         do {
141                 Lisp_Object frmcons;
142
143                 DEVICE_FRAME_LOOP(frmcons, d) {
144                         struct frame *fr = XFRAME(XCAR(frmcons));
145                         if ((w ==
146                              GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(fr)))
147                             || (w ==
148                                 GET_GTK_WIDGET_WINDOW(FRAME_GTK_CONTAINER_WIDGET
149                                                       (fr))) ||
150 #ifdef HAVE_MENUBARS
151                             (w ==
152                              GET_GTK_WIDGET_WINDOW(FRAME_GTK_MENUBAR_WIDGET
153                                                    (fr))) ||
154 #endif
155                             (w ==
156                              GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(fr))))
157                         {
158                                 return (fr);
159                         }
160                 }
161                 w = gdk_window_get_parent(w);
162         } while (w);
163
164         return (0);
165 }
166
167 struct frame *gtk_any_widget_or_parent_to_frame(struct device *d,
168                                                 GtkWidget * widget)
169 {
170         return (gtk_any_window_to_frame(d, GET_GTK_WIDGET_WINDOW(widget)));
171 }
172
173 struct device *gtk_any_window_to_device(GdkWindow * w)
174 {
175         struct device *d = NULL;
176         Lisp_Object devcons, concons;
177
178         DEVICE_LOOP_NO_BREAK(devcons, concons) {
179                 d = XDEVICE(XCAR(devcons));
180                 if (!DEVICE_GTK_P(d))
181                         continue;
182                 if (gtk_any_window_to_frame(d, w))
183                         return (d);
184         }
185         return (NULL);
186 }
187
188 struct frame *decode_gtk_frame(Lisp_Object frame)
189 {
190         if (NILP(frame))
191                 XSETFRAME(frame, selected_frame());
192         CHECK_LIVE_FRAME(frame);
193         /* this will also catch dead frames, but putting in the above check
194            results in a more useful error */
195         CHECK_GTK_FRAME(frame);
196         return XFRAME(frame);
197 }
198 \f
199 /************************************************************************/
200 /*                      window-manager interactions                     */
201 /************************************************************************/
202 static int gtk_frame_iconified_p(struct frame *f)
203 {
204         return (f->iconified);
205 }
206 \f
207 /************************************************************************/
208 /*                          frame properties                            */
209 /************************************************************************/
210
211 static Lisp_Object gtk_frame_property(struct frame *f, Lisp_Object property)
212 {
213         GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
214
215         if (EQ(Qleft, property) || EQ(Qtop, property)) {
216                 gint x, y;
217                 if (!GET_GTK_WIDGET_WINDOW(shell))
218                         return Qzero;
219                 gdk_window_get_deskrelative_origin(GET_GTK_WIDGET_WINDOW(shell),
220                                                    &x, &y);
221                 if (EQ(Qleft, property))
222                         return make_int(x);
223                 if (EQ(Qtop, property))
224                         return make_int(y);
225         }
226         if (EQ(Qshell_widget, property)) {
227                 return (FRAME_GTK_LISP_WIDGETS(f)[0]);
228         }
229         if (EQ(Qcontainer_widget, property)) {
230                 return (FRAME_GTK_LISP_WIDGETS(f)[1]);
231         }
232         if (EQ(Qtext_widget, property)) {
233                 return (FRAME_GTK_LISP_WIDGETS(f)[2]);
234         }
235 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
236         if (EQ(Qwindow_id, property))
237                 return Fgtk_window_id(make_frame(f));
238 #endif
239
240         return Qunbound;
241 }
242
243 static int gtk_internal_frame_property_p(struct frame *f, Lisp_Object property)
244 {
245         return EQ(property, Qleft)
246             || EQ(property, Qtop)
247             || EQ(Qshell_widget, property)
248             || EQ(Qcontainer_widget, property)
249             || EQ(Qtext_widget, property)
250             || EQ(property, Qwindow_id)
251             || STRINGP(property);
252 }
253
254 static Lisp_Object gtk_frame_properties(struct frame *f)
255 {
256         Lisp_Object props = Qnil;
257         GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
258         gint x, y;
259
260         props = cons3(Qshell_widget, FRAME_GTK_LISP_WIDGETS(f)[0], props);
261         props = cons3(Qcontainer_widget, FRAME_GTK_LISP_WIDGETS(f)[1], props);
262         props = cons3(Qtext_widget, FRAME_GTK_LISP_WIDGETS(f)[2], props);
263
264 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
265         props = cons3(Qwindow_id, Fgtk_window_id(make_frame(f)), props);
266 #endif
267
268         if (!GET_GTK_WIDGET_WINDOW(shell))
269                 x = y = 0;
270         else
271                 gdk_window_get_deskrelative_origin(GET_GTK_WIDGET_WINDOW(shell),
272                                                    &x, &y);
273
274         props = cons3(Qtop, make_int(y), props);
275         props = cons3(Qleft, make_int(x), props);
276
277         return props;
278 }
279 \f
280 /* Functions called only from `gtk_set_frame_properties' to set
281    individual properties. */
282
283 static void
284 gtk_set_frame_text_value(struct frame *f, Bufbyte * value,
285                          void (*func) (gpointer, gchar *), gpointer arg)
286 {
287         gchar *the_text = (gchar *) value;
288
289         /* Programmer fuckup or window is not realized yet. */
290         if (!func || !arg)
291                 return;
292
293 #ifdef MULE
294         {
295                 Bufbyte *ptr;
296
297                 /* Optimize for common ASCII case */
298                 for (ptr = value; *ptr; ptr++)
299                         if (!BYTE_ASCII_P(*ptr)) {
300                                 char *tmp;
301                                 C_STRING_TO_EXTERNAL(value, tmp, Qctext);
302                                 the_text = tmp;
303                                 break;
304                         }
305         }
306 #endif                          /* MULE */
307
308         (*func) (arg, (gchar *) the_text);
309 }
310
311 static void gtk_set_title_from_bufbyte(struct frame *f, Bufbyte * name)
312 {
313         if (GTK_IS_WINDOW(FRAME_GTK_SHELL_WIDGET(f)))
314                 gtk_set_frame_text_value(f, name, (void (*)(gpointer, gchar *))
315                                          gtk_window_set_title,
316                                          FRAME_GTK_SHELL_WIDGET(f));
317 }
318
319 static void gtk_set_icon_name_from_bufbyte(struct frame *f, Bufbyte * name)
320 {
321         gtk_set_frame_text_value(f, name, (void (*)(gpointer, gchar *))
322                                  gdk_window_set_icon_name,
323                                  FRAME_GTK_SHELL_WIDGET(f)->window);
324 }
325
326 /* Set the initial frame size as specified.  This function is used
327    when the frame's widgets have not yet been realized.
328 */
329 static void
330 gtk_set_initial_frame_size(struct frame *f, int x, int y,
331                            unsigned int w, unsigned int h)
332 {
333         GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
334         GdkGeometry geometry;
335         GdkWindowHints geometry_mask = 0x00;
336
337         if (GTK_IS_WINDOW(shell)) {
338                 /* Deal with the cell size */
339                 default_face_height_and_width(make_frame(f),
340                                               &geometry.height_inc,
341                                               &geometry.width_inc);
342                 geometry_mask |= GDK_HINT_RESIZE_INC;
343
344                 gtk_window_set_geometry_hints(GTK_WINDOW(shell),
345                                               FRAME_GTK_TEXT_WIDGET(f),
346                                               &geometry, geometry_mask);
347                 gdk_window_set_hints(GET_GTK_WIDGET_WINDOW(shell), x, y, 0, 0,
348                                      0, 0, GDK_HINT_POS);
349                 gtk_window_set_policy(GTK_WINDOW(shell), TRUE, TRUE, FALSE);
350         }
351
352         FRAME_HEIGHT(f) = h;
353         FRAME_WIDTH(f) = w;
354
355         change_frame_size(f, h, w, 0);
356         {
357                 GtkRequisition req;
358
359                 gtk_widget_size_request(FRAME_GTK_SHELL_WIDGET(f), &req);
360                 gtk_widget_set_usize(FRAME_GTK_SHELL_WIDGET(f), req.width,
361                                      req.height);
362         }
363 }
364
365 /* Report that a frame property of frame S is being set or changed.
366    If the property is not specially recognized, do nothing.
367  */
368
369 static void gtk_set_frame_properties(struct frame *f, Lisp_Object plist)
370 {
371         gint x, y;
372         gint width = 0, height = 0;
373         gboolean width_specified_p = FALSE;
374         gboolean height_specified_p = FALSE;
375         gboolean x_position_specified_p = FALSE;
376         gboolean y_position_specified_p = FALSE;
377         Lisp_Object tail;
378
379         for (tail = plist; !NILP(tail); tail = Fcdr(Fcdr(tail))) {
380                 Lisp_Object prop = Fcar(tail);
381                 Lisp_Object val = Fcar(Fcdr(tail));
382
383                 if (SYMBOLP(prop)) {
384                         if (EQ(prop, Qfont)) {
385                                 /* If the value is not a string we silently ignore it. */
386                                 if (STRINGP(val)) {
387                                         Lisp_Object frm, font_spec;
388
389                                         XSETFRAME(frm, f);
390                                         font_spec =
391                                             Fget(Fget_face(Qdefault), Qfont,
392                                                  Qnil);
393
394                                         Fadd_spec_to_specifier(font_spec, val,
395                                                                frm, Qnil, Qnil);
396                                         update_frame_face_values(f);
397                                 }
398                                 continue;
399                         } else if (EQ(prop, Qwidth)) {
400                                 CHECK_INT(val);
401                                 width = XINT(val);
402                                 width_specified_p = TRUE;
403                                 continue;
404                         } else if (EQ(prop, Qheight)) {
405                                 CHECK_INT(val);
406                                 height = XINT(val);
407                                 height_specified_p = TRUE;
408                                 continue;
409                         }
410                         /* Further kludge the x/y. */
411                         else if (EQ(prop, Qx)) {
412                                 CHECK_INT(val);
413                                 x = (gint) XINT(val);
414                                 x_position_specified_p = TRUE;
415                                 continue;
416                         } else if (EQ(prop, Qy)) {
417                                 CHECK_INT(val);
418                                 y = (gint) XINT(val);
419                                 y_position_specified_p = TRUE;
420                                 continue;
421                         }
422                 }
423         }
424
425         /* Kludge kludge kludge.   We need to deal with the size and position
426            specially. */
427         {
428                 int size_specified_p = width_specified_p || height_specified_p;
429                 int position_specified_p = x_position_specified_p
430                     || y_position_specified_p;
431
432                 if (!width_specified_p)
433                         width = 80;
434                 if (!height_specified_p)
435                         height = 30;
436
437                 /* Kludge kludge kludge kludge. */
438                 if (position_specified_p &&
439                     (!x_position_specified_p || !y_position_specified_p)) {
440                         gint dummy;
441                         GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
442                         gdk_window_get_deskrelative_origin(GET_GTK_WIDGET_WINDOW
443                                                            (shell),
444                                                            (x_position_specified_p
445                                                             ? &dummy : &x),
446                                                            (y_position_specified_p
447                                                             ? &dummy : &y));
448                 }
449
450                 if (!f->init_finished) {
451                         if (size_specified_p || position_specified_p)
452                                 gtk_set_initial_frame_size(f, x, y, width,
453                                                            height);
454                 } else {
455                         if (size_specified_p) {
456                                 Lisp_Object frame;
457                                 XSETFRAME(frame, f);
458                                 Fset_frame_size(frame, make_int(width),
459                                                 make_int(height), Qnil);
460                         }
461                         if (position_specified_p) {
462                                 Lisp_Object frame;
463                                 XSETFRAME(frame, f);
464                                 Fset_frame_position(frame, make_int(x),
465                                                     make_int(y));
466                         }
467                 }
468         }
469 }
470 \f
471 /************************************************************************/
472 /*                              widget creation                         */
473 /************************************************************************/
474 /* Figure out what size the shell widget should initially be,
475    and set it.  Should be called after the default font has been
476    determined but before the widget has been realized. */
477
478 extern Lisp_Object Vgtk_initial_geometry;
479
480 #ifndef HAVE_GNOME
481 static int get_number(const char **geometry)
482 {
483         int value = 0;
484         int mult = 1;
485
486         if (**geometry == '-') {
487                 mult = -1;
488                 (*geometry)++;
489         }
490         while (**geometry && isdigit(**geometry)) {
491                 value = value * 10 + (**geometry - '0');
492                 (*geometry)++;
493         }
494         return value * mult;
495 }
496
497 /*
498  */
499
500 /**
501  * gnome_parse_geometry
502  * @geometry: geometry string to be parsed
503  * @xpos: X position geometry component
504  * @ypos: Y position geometry component
505  * @width: pixel width geometry component
506  * @height: pixel height geometry component
507  *
508  * Description:
509  * Parses the geometry string passed in @geometry, and fills
510  * @xpos, @ypos, @width, and @height with
511  * the corresponding values upon completion of the parse.
512  * If the parse fails, it should be assumed that @xpos, @ypos, @width,
513  * and @height contain undefined values.
514  *
515  * Returns:
516  * %TRUE if the geometry was successfully parsed, %FALSE otherwise.
517  **/
518
519 static gboolean
520 gnome_parse_geometry(const gchar * geometry, gint * xpos,
521                      gint * ypos, gint * width, gint * height)
522 {
523         int subtract;
524
525         g_return_val_if_fail(xpos != NULL, FALSE);
526         g_return_val_if_fail(ypos != NULL, FALSE);
527         g_return_val_if_fail(width != NULL, FALSE);
528         g_return_val_if_fail(height != NULL, FALSE);
529
530         *xpos = *ypos = *width = *height = -1;
531
532         if (!geometry)
533                 return FALSE;
534
535         if (*geometry == '=')
536                 geometry++;
537         if (!*geometry)
538                 return FALSE;
539         if (isdigit(*geometry))
540                 *width = get_number(&geometry);
541         if (!*geometry)
542                 return TRUE;
543         if (*geometry == 'x' || *geometry == 'X') {
544                 geometry++;
545                 *height = get_number(&geometry);
546         }
547         if (!*geometry)
548                 return 1;
549         if (*geometry == '+') {
550                 subtract = 0;
551                 geometry++;
552         } else if (*geometry == '-') {
553                 subtract = gdk_screen_width();
554                 geometry++;
555         } else
556                 return FALSE;
557         *xpos = get_number(&geometry);
558         if (subtract)
559                 *xpos = subtract - *xpos;
560         if (!*geometry)
561                 return TRUE;
562         if (*geometry == '+') {
563                 subtract = 0;
564                 geometry++;
565         } else if (*geometry == '-') {
566                 subtract = gdk_screen_height();
567                 geometry++;
568         } else
569                 return FALSE;
570         *ypos = get_number(&geometry);
571         if (subtract)
572                 *ypos = subtract - *ypos;
573         return TRUE;
574 }
575 #endif
576
577 static void gtk_initialize_frame_size(struct frame *f)
578 {
579         gint x = 10, y = 10, w = 80, h = 30;
580
581         if (STRINGP(Vgtk_initial_geometry)) {
582                 if (!gnome_parse_geometry
583                     (XSTRING_DATA(Vgtk_initial_geometry), &x, &y, &w, &h)) {
584                         x = y = 10;
585                         w = 80;
586                         h = 30;
587                 }
588         }
589
590         /* set the position of the frame's root window now.  When the
591            frame was created, the position was initialized to (0,0). */
592         {
593                 struct window *win = XWINDOW(f->root_window);
594
595                 WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f);
596                 WINDOW_TOP(win) = FRAME_TOP_BORDER_END(f);
597
598                 if (!NILP(f->minibuffer_window)) {
599                         win = XWINDOW(f->minibuffer_window);
600                         WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f);
601                 }
602         }
603
604         gtk_set_initial_frame_size(f, x, y, w, h);
605 }
606
607 static gboolean
608 resize_event_cb(GtkWidget * w, GtkAllocation * allocation, gpointer user_data)
609 {
610         struct frame *f = (struct frame *)user_data;
611
612         f->pixwidth = allocation->width;
613         f->pixheight = allocation->height;
614
615         if (FRAME_GTK_TEXT_WIDGET(f)->window) {
616                 Lisp_Object frame;
617                 XSETFRAME(frame, f);
618                 Fredraw_frame(frame, Qt);
619         }
620
621         return (FALSE);
622 }
623
624 static gboolean
625 delete_event_cb(GtkWidget * w, GdkEvent * ev, gpointer user_data)
626 {
627         struct frame *f = (struct frame *)user_data;
628         Lisp_Object frame;
629
630         XSETFRAME(frame, f);
631         enqueue_misc_user_event(frame, Qeval, list3(Qdelete_frame, frame, Qt));
632
633         /* See if tickling the event queue helps us with our delays when
634            clicking 'close' */
635         signal_fake_event();
636
637         return (TRUE);
638 }
639
640 extern gboolean emacs_shell_event_handler(GtkWidget * wid, GdkEvent * event,
641                                           gpointer closure);
642 extern Lisp_Object build_gtk_object(GtkObject * obj);
643
644 #ifndef GNOME_IS_APP
645 #define GNOME_IS_APP(x) 0
646 #define gnome_app_set_contents(x,y) 0
647 #endif
648
649 static void cleanup_deleted_frame(gpointer data)
650 {
651         struct frame *f = (struct frame *)data;
652         Lisp_Object frame;
653
654         XSETFRAME(frame, f);
655         Fdelete_frame(frame, Qt);
656 }
657
658 #ifdef HAVE_DRAGNDROP
659 extern void
660 dragndrop_data_received(GtkWidget * widget,
661                         GdkDragContext * context,
662                         gint x,
663                         gint y,
664                         GtkSelectionData * data, guint info, guint time);
665
666 extern gboolean
667 dragndrop_dropped(GtkWidget * widget,
668                   GdkDragContext * drag_context,
669                   gint x, gint y, guint time, gpointer user_data);
670
671 Lisp_Object Vcurrent_drag_object;
672
673 #define DRAG_SELECTION_DATA_ERROR "Error converting drag data to external format"
674 static void
675 dragndrop_get_drag(GtkWidget * widget,
676                    GdkDragContext * drag_context,
677                    GtkSelectionData * data,
678                    guint info, guint time, gpointer user_data)
679 {
680         gtk_selection_data_set(data, GDK_SELECTION_TYPE_STRING, 8,
681                                DRAG_SELECTION_DATA_ERROR,
682                                strlen(DRAG_SELECTION_DATA_ERROR));
683
684         switch (info) {
685         case TARGET_TYPE_STRING:
686                 {
687                         Lisp_Object string = Vcurrent_drag_object;
688
689                         if (!STRINGP(Vcurrent_drag_object)) {
690                                 string = Fprin1_to_string(string, Qnil);
691                                 /* Convert to a string */
692                         }
693
694                         gtk_selection_data_set(data, GDK_SELECTION_TYPE_STRING,
695                                                8, XSTRING_DATA(string),
696                                                XSTRING_LENGTH(string));
697                 }
698                 break;
699         case TARGET_TYPE_URI_LIST:
700                 break;
701         default:
702                 break;
703         }
704         Vcurrent_drag_object = Qnil;
705 }
706
707 DEFUN("gtk-start-drag-internal", Fgtk_start_drag_internal, 2, 3, 0,     /*
708 Start a GTK drag from a buffer.
709 First arg is the event that started the drag,
710 second arg should be some string, and the third
711 is the type of the data (this should be a MIME type as a string (ie: text/plain)).
712 The type defaults to text/plain.
713 */
714       (event, data, dtyp))
715 {
716         if (EVENTP(event)) {
717                 struct frame *f = decode_gtk_frame(Fselected_frame(Qnil));
718                 GtkWidget *wid = FRAME_GTK_TEXT_WIDGET(f);
719                 struct Lisp_Event *lisp_event = XEVENT(event);
720                 GdkAtom dnd_typ;
721                 GtkTargetList *tl =
722                     gtk_target_list_new(dnd_target_table, dnd_n_targets);
723
724                 /* only drag if this is really a press */
725                 if (EVENT_TYPE(lisp_event) != button_press_event)
726                         return Qnil;
727
728                 /* get the desired type */
729                 if (!NILP(dtyp) && STRINGP(dtyp))
730                         dnd_typ = gdk_atom_intern(XSTRING_DATA(dtyp), FALSE);
731
732                 gtk_drag_begin(wid, tl, GDK_ACTION_COPY,
733                                lisp_event->event.button.button, NULL);
734
735                 Vcurrent_drag_object = data;
736
737                 gtk_target_list_unref(tl);
738         }
739         return Qnil;
740 }
741 #endif
742
743 /* Creates the widgets for a frame.
744    lisp_window_id is a Lisp description of an X window or Xt
745    widget to parse.
746
747    This function does not map the windows.  (That is
748    done by gtk_popup_frame().)
749 */
750 static void
751 gtk_create_widgets(struct frame *f, Lisp_Object lisp_window_id,
752                    Lisp_Object parent)
753 {
754         const char *name;
755         GtkWidget *text, *container, *shell;
756         gboolean embedded_p = !NILP(lisp_window_id);
757 #ifdef HAVE_MENUBARS
758         int menubar_visible;
759 #endif
760
761         if (STRINGP(f->name))
762                 TO_EXTERNAL_FORMAT(LISP_STRING, f->name, C_STRING_ALLOCA, name,
763                                    Qctext);
764         else
765                 name = "emacs";
766
767         FRAME_GTK_TOP_LEVEL_FRAME_P(f) = 1;
768
769         if (embedded_p) {
770                 CHECK_GTK_OBJECT(lisp_window_id);
771
772                 if (!GTK_IS_CONTAINER(XGTK_OBJECT(lisp_window_id)->object)) {
773                         signal_simple_error
774                             ("Window ID must be a GtkContainer subclass",
775                              lisp_window_id);
776                 }
777
778                 shell = gtk_vbox_new(FALSE, 0);
779
780                 gtk_object_weakref(GTK_OBJECT(shell), cleanup_deleted_frame, f);
781                 gtk_container_add(GTK_CONTAINER
782                                   (XGTK_OBJECT(lisp_window_id)->object), shell);
783         } else {
784 #ifdef HAVE_GNOME
785                 shell = GTK_WIDGET(gnome_app_new("SXEmacs", "SXEmacs/GNOME"));
786 #else
787                 shell = GTK_WIDGET(gtk_window_new(GTK_WINDOW_TOPLEVEL));
788 #endif
789         }
790
791         if (!NILP(parent)) {
792                 /* If this is a transient window, keep the parent info around */
793                 GtkWidget *parentwid = FRAME_GTK_SHELL_WIDGET(XFRAME(parent));
794                 gtk_object_set_data(GTK_OBJECT(shell),
795                                     TRANSIENT_DATA_IDENTIFIER, parentwid);
796                 gtk_window_set_transient_for(GTK_WINDOW(shell),
797                                              GTK_WINDOW(parentwid));
798         }
799
800         gtk_container_set_border_width(GTK_CONTAINER(shell), 0);
801
802         gtk_object_set_data(GTK_OBJECT(shell), GTK_DATA_FRAME_IDENTIFIER, f);
803
804         FRAME_GTK_SHELL_WIDGET(f) = shell;
805
806         text = GTK_WIDGET(gtk_xemacs_new(f));
807
808         if (!GNOME_IS_APP(shell))
809                 container =
810                     GTK_WIDGET(gtk_vbox_new(FALSE, INTERNAL_BORDER_WIDTH));
811         else
812                 container = shell;
813
814         FRAME_GTK_CONTAINER_WIDGET(f) = container;
815         FRAME_GTK_TEXT_WIDGET(f) = text;
816
817 #ifdef HAVE_DRAGNDROP
818         gtk_drag_dest_set(text,
819                           GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT,
820                           dnd_target_table, dnd_n_targets,
821                           GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK);
822         gtk_signal_connect(GTK_OBJECT(text), "drag_drop",
823                            GTK_SIGNAL_FUNC(dragndrop_dropped), text);
824         gtk_signal_connect(GTK_OBJECT(text), "drag_data_received",
825                            GTK_SIGNAL_FUNC(dragndrop_data_received), text);
826         gtk_signal_connect(GTK_OBJECT(text), "drag_data_get",
827                            GTK_SIGNAL_FUNC(dragndrop_get_drag), NULL);
828 #endif
829
830 #ifdef HAVE_MENUBARS
831         /* Create the initial menubar widget. */
832         menubar_visible = gtk_initialize_frame_menubar(f);
833
834         if (menubar_visible) {
835                 gtk_widget_show_all(FRAME_GTK_MENUBAR_WIDGET(f));
836         }
837 #endif                          /* HAVE_MENUBARS */
838
839 #ifdef HAVE_GNOME
840         if (GNOME_IS_APP(shell))
841                 gnome_app_set_contents(GNOME_APP(shell), text);
842         else
843 #endif
844                 /* Now comes the drawing area, which should fill the rest of the
845                  ** frame completely.
846                  */
847                 gtk_box_pack_end(GTK_BOX(container), text, TRUE, TRUE, 0);
848
849         /* Connect main event handler */
850         gtk_signal_connect(GTK_OBJECT(shell), "delete-event",
851                            GTK_SIGNAL_FUNC(delete_event_cb), f);
852
853         {
854                 static char *events_to_frob[] = { "focus-in-event",
855                         "focus-out-event",
856                         "enter-notify-event",
857                         "leave-notify-event",
858                         "map-event",
859                         "unmap-event",
860                         "property-notify-event",
861                         "selection-clear-event",
862                         "selection-request-event",
863                         "selection-notify-event",
864                         "client-event",
865                         /* "configure-event", */
866                         "visibility-notify-event",
867                         NULL
868                 };
869                 int i;
870
871                 for (i = 0; events_to_frob[i]; i++) {
872                         gtk_signal_connect(GTK_OBJECT(shell), events_to_frob[i],
873                                            GTK_SIGNAL_FUNC
874                                            (emacs_shell_event_handler), f);
875                 }
876         }
877
878         gtk_signal_connect(GTK_OBJECT(shell), "size-allocate",
879                            GTK_SIGNAL_FUNC(resize_event_cb), f);
880
881         /* This might be safe to call now... */
882         /* gtk_signal_connect (GTK_OBJECT (shell), "event", GTK_SIGNAL_FUNC (emacs_shell_event_handler), f); */
883
884         /* Let's make sure we get all the events we can */
885         gtk_widget_set_events(text, GDK_ALL_EVENTS_MASK);
886
887         if (shell != container)
888                 gtk_container_add(GTK_CONTAINER(shell), container);
889
890         gtk_widget_set_name(shell, "SXEmacs::shell");
891         gtk_widget_set_name(container, "SXEmacs::container");
892         gtk_widget_set_name(text, "SXEmacs::text");
893
894         FRAME_GTK_LISP_WIDGETS(f)[0] = build_gtk_object(GTK_OBJECT(shell));
895         FRAME_GTK_LISP_WIDGETS(f)[1] = build_gtk_object(GTK_OBJECT(container));
896         FRAME_GTK_LISP_WIDGETS(f)[2] = build_gtk_object(GTK_OBJECT(text));
897
898         gtk_widget_realize(shell);
899 }
900
901 /* create the windows for the specified frame and display them.
902    Note that the widgets have already been created, and any
903    necessary geometry calculations have already been done. */
904 static void gtk_popup_frame(struct frame *f)
905 {
906         /* */
907
908         if (gtk_object_get_data
909             (GTK_OBJECT(FRAME_GTK_SHELL_WIDGET(f)), UNMAPPED_DATA_IDENTIFIER)) {
910                 FRAME_GTK_TOTALLY_VISIBLE_P(f) = 0;
911                 f->visible = 0;
912                 gtk_widget_realize(FRAME_GTK_SHELL_WIDGET(f));
913                 gtk_widget_realize(FRAME_GTK_TEXT_WIDGET(f));
914                 gtk_widget_hide_all(FRAME_GTK_SHELL_WIDGET(f));
915         } else {
916                 gtk_widget_show_all(FRAME_GTK_SHELL_WIDGET(f));
917         }
918 }
919
920 static void allocate_gtk_frame_struct(struct frame *f)
921 {
922         /* zero out all slots. */
923         f->frame_data = xnew_and_zero(struct gtk_frame);
924
925         /* yeah, except the lisp ones */
926         FRAME_GTK_ICON_PIXMAP(f) = Qnil;
927         FRAME_GTK_ICON_PIXMAP_MASK(f) = Qnil;
928
929         /*
930            Hashtables of callback data for glyphs on the frame.  Make them EQ because
931            we only use ints as keys.  Otherwise we run into stickiness in redisplay
932            because internal_equal() can QUIT.  See enter_redisplay_critical_section().
933          */
934         FRAME_GTK_WIDGET_INSTANCE_HASH_TABLE(f) =
935             make_lisp_hash_table(50, HASH_TABLE_VALUE_WEAK, HASH_TABLE_EQ);
936         FRAME_GTK_WIDGET_CALLBACK_HASH_TABLE(f) =
937             make_lisp_hash_table(50, HASH_TABLE_VALUE_WEAK, HASH_TABLE_EQ);
938         FRAME_GTK_WIDGET_CALLBACK_EX_HASH_TABLE(f) =
939             make_lisp_hash_table(50, HASH_TABLE_VALUE_WEAK, HASH_TABLE_EQ);
940 }
941 \f
942 /************************************************************************/
943 /*                              Lisp functions                          */
944 /************************************************************************/
945
946 static void gtk_init_frame_1(struct frame *f, Lisp_Object props)
947 {
948         /* This function can GC */
949         Lisp_Object initially_unmapped;
950         Lisp_Object device = FRAME_DEVICE(f);
951         Lisp_Object lisp_window_id = Fplist_get(props, Qwindow_id, Qnil);
952         Lisp_Object popup = Fplist_get(props, Qpopup, Qnil);
953
954         if (!NILP(popup)) {
955                 if (EQ(popup, Qt))
956                         popup = Fselected_frame(device);
957                 CHECK_LIVE_FRAME(popup);
958                 if (!EQ(device, FRAME_DEVICE(XFRAME(popup))))
959                         signal_simple_error_2
960                             ("Parent must be on same device as frame", device,
961                              popup);
962         }
963
964         initially_unmapped = Fplist_get(props, Qinitially_unmapped, Qnil);
965
966         /*
967          * Previously we set this only if NILP (DEVICE_SELECTED_FRAME (d))
968          * to make sure that messages were displayed as soon as possible
969          * if we're creating the first frame on a device.  But it is
970          * better to just set this all the time, so that when a new frame
971          * is created that covers the selected frame, echo area status
972          * messages can still be seen.  f->visible is reset later if the
973          * initially-unmapped property is found to be non-nil in the
974          * frame properties.
975          */
976         f->visible = 1;
977
978         allocate_gtk_frame_struct(f);
979         gtk_create_widgets(f, lisp_window_id, popup);
980
981         if (!NILP(initially_unmapped)) {
982                 gtk_object_set_data(GTK_OBJECT(FRAME_GTK_SHELL_WIDGET(f)),
983                                     UNMAPPED_DATA_IDENTIFIER, (gpointer) 1);
984         }
985 }
986
987 static void gtk_init_frame_2(struct frame *f, Lisp_Object props)
988 {
989         /* Set up the values of the widget/frame.  A case could be made for putting
990            this inside of the widget's initialize method. */
991
992         update_frame_face_values(f);
993         gtk_initialize_frame_size(f);
994         /* Kyle:
995          *   update_frame_title() can't be done here, because some of the
996          *   modeline specs depend on the frame's device having a selected
997          *   frame, and that may not have been set up yet.  The redisplay
998          *   will update the frame title anyway, so nothing is lost.
999          * JV:
1000          *   It turns out it gives problems with FVWMs name based mapping.
1001          *   We'll just  need to be carefull in the modeline specs.
1002          */
1003         update_frame_title(f);
1004 }
1005
1006 static void gtk_init_frame_3(struct frame *f)
1007 {
1008         /* Pop up the frame. */
1009         gtk_popup_frame(f);
1010 }
1011
1012 static void gtk_mark_frame(struct frame *f)
1013 {
1014         mark_object(FRAME_GTK_ICON_PIXMAP(f));
1015         mark_object(FRAME_GTK_ICON_PIXMAP_MASK(f));
1016         mark_object(FRAME_GTK_LISP_WIDGETS(f)[0]);
1017         mark_object(FRAME_GTK_LISP_WIDGETS(f)[1]);
1018         mark_object(FRAME_GTK_LISP_WIDGETS(f)[2]);
1019         mark_object(FRAME_GTK_WIDGET_INSTANCE_HASH_TABLE(f));
1020         mark_object(FRAME_GTK_WIDGET_CALLBACK_HASH_TABLE(f));
1021         mark_object(FRAME_GTK_WIDGET_CALLBACK_EX_HASH_TABLE(f));
1022 }
1023
1024 static void gtk_set_frame_icon(struct frame *f)
1025 {
1026         GdkPixmap *gtk_pixmap = NULL, *gtk_mask = NULL;
1027
1028         if (IMAGE_INSTANCEP(f->icon)
1029             && IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(f->icon))) {
1030                 gtk_pixmap = XIMAGE_INSTANCE_GTK_PIXMAP(f->icon);
1031                 gtk_mask = XIMAGE_INSTANCE_GTK_MASK(f->icon);
1032         } else {
1033                 gtk_pixmap = 0;
1034                 gtk_mask = 0;
1035         }
1036
1037         gdk_window_set_icon(GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f)),
1038                             NULL, gtk_pixmap, gtk_mask);
1039 }
1040
1041 static void gtk_set_frame_pointer(struct frame *f)
1042 {
1043         GtkWidget *w = FRAME_GTK_TEXT_WIDGET(f);
1044         GdkCursor *c = XIMAGE_INSTANCE_GTK_CURSOR(f->pointer);
1045
1046         if (POINTER_IMAGE_INSTANCEP(f->pointer)) {
1047                 gdk_window_set_cursor(GET_GTK_WIDGET_WINDOW(w), c);
1048                 gdk_flush();
1049         } else {
1050                 /* abort()? */
1051                 stderr_out("POINTER_IMAGE_INSTANCEP (f->pointer) failed!\n");
1052         }
1053 }
1054
1055 static Lisp_Object gtk_get_frame_parent(struct frame *f)
1056 {
1057         GtkWidget *parentwid =
1058             gtk_object_get_data(GTK_OBJECT(FRAME_GTK_SHELL_WIDGET(f)),
1059                                 TRANSIENT_DATA_IDENTIFIER);
1060
1061         /* find the frame whose wid is parentwid */
1062         if (parentwid) {
1063                 Lisp_Object frmcons;
1064                 DEVICE_FRAME_LOOP(frmcons, XDEVICE(FRAME_DEVICE(f))) {
1065                         Lisp_Object frame = XCAR(frmcons);
1066                         if (FRAME_GTK_SHELL_WIDGET(XFRAME(frame)) == parentwid)
1067                                 return frame;
1068                 }
1069         }
1070         return Qnil;
1071 }
1072
1073 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
1074 DEFUN("gtk-window-id", Fgtk_window_id, 0, 1, 0, /*
1075 Get the ID of the Gtk window.
1076 This gives us a chance to manipulate the Emacs window from within a
1077 different program.  Since the ID is an unsigned long, we return it as
1078 a string.
1079 */
1080       (frame))
1081 {
1082         char str[255];
1083         struct frame *f = decode_gtk_frame(frame);
1084
1085         /* Arrrrggghhh... this defeats the whole purpose of using Gdk... do we really need this? */
1086         sprintf(str, "%lu",
1087                 GDK_WINDOW_XWINDOW(GET_GTK_WIDGET_WINDOW
1088                                    (FRAME_GTK_TEXT_WIDGET(f))));
1089         return build_string(str);
1090 }
1091 #endif
1092 \f
1093 /************************************************************************/
1094 /*                      manipulating the X window                       */
1095 /************************************************************************/
1096
1097 static void gtk_set_frame_position(struct frame *f, int xoff, int yoff)
1098 {
1099         gtk_widget_set_uposition(FRAME_GTK_SHELL_WIDGET(f), xoff, yoff);
1100 }
1101
1102 /* Call this to change the size of frame S's x-window. */
1103
1104 static void gtk_set_frame_size(struct frame *f, int cols, int rows)
1105 {
1106         GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
1107         GdkGeometry geometry;
1108         GdkWindowHints geometry_mask = 0x00;
1109
1110         if (GTK_IS_WINDOW(shell)) {
1111                 /* Update the cell size */
1112                 default_face_height_and_width(make_frame(f),
1113                                               &geometry.height_inc,
1114                                               &geometry.width_inc);
1115                 geometry_mask |= GDK_HINT_RESIZE_INC;
1116
1117                 gtk_window_set_geometry_hints(GTK_WINDOW(shell),
1118                                               FRAME_GTK_TEXT_WIDGET(f),
1119                                               &geometry, geometry_mask);
1120         }
1121
1122         change_frame_size(f, rows, cols, 0);
1123
1124         {
1125                 GtkRequisition req;
1126
1127                 gtk_widget_size_request(FRAME_GTK_SHELL_WIDGET(f), &req);
1128                 gtk_widget_set_usize(FRAME_GTK_SHELL_WIDGET(f), req.width,
1129                                      req.height);
1130         }
1131 }
1132
1133 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
1134 /* There is NO equivalent to XWarpPointer under Gtk */
1135 static void gtk_set_mouse_position(struct window *w, int x, int y)
1136 {
1137         struct frame *f = XFRAME(w->frame);
1138         Display *display = GDK_DISPLAY();
1139         XWarpPointer(display, None,
1140                      GDK_WINDOW_XWINDOW(GET_GTK_WIDGET_WINDOW
1141                                         (FRAME_GTK_TEXT_WIDGET(f))), 0, 0, 0, 0,
1142                      w->pixel_left + x, w->pixel_top + y);
1143 }
1144 #endif                          /* STUPID_X_SPECIFIC_GTK_STUFF */
1145
1146 static int
1147 gtk_get_mouse_position(struct device *d, Lisp_Object * frame, int *x, int *y)
1148 {
1149         /* Returns the pixel position within the editor text widget */
1150         gint win_x, win_y;
1151         GdkWindow *w = gdk_window_at_pointer(&win_x, &win_y);
1152         struct frame *f = NULL;
1153
1154         if (!w)
1155                 return (0);
1156
1157         /* At this point, w is the innermost GdkWindow containing the
1158          ** pointer and win_x and win_y are the coordinates of that window.
1159          */
1160         f = gtk_any_window_to_frame(d, w);
1161
1162         if (!f)
1163                 return (0);
1164
1165         XSETFRAME(*frame, f);
1166
1167         gdk_window_get_pointer(GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f)),
1168                                &win_x, &win_y, NULL);
1169
1170         *x = win_x;
1171         *y = win_y;
1172
1173         return (1);
1174 }
1175
1176 static void gtk_cant_notify_wm_error(void)
1177 {
1178         error("Can't notify window manager of iconification.");
1179 }
1180
1181 /* Raise frame F.  */
1182 static void gtk_raise_frame_1(struct frame *f, int force)
1183 {
1184         if (FRAME_VISIBLE_P(f) || force) {
1185                 GdkWindow *emacs_window =
1186                     GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f));
1187
1188                 gdk_window_raise(emacs_window);
1189         }
1190 }
1191
1192 static void gtk_raise_frame(struct frame *f)
1193 {
1194         gtk_raise_frame_1(f, 1);
1195 }
1196
1197 /* Lower frame F.  */
1198 static void gtk_lower_frame(struct frame *f)
1199 {
1200         if (FRAME_VISIBLE_P(f)) {
1201                 gdk_window_lower(GET_GTK_WIDGET_WINDOW
1202                                  (FRAME_GTK_SHELL_WIDGET(f)));
1203         }
1204 }
1205
1206 /* Change from withdrawn state to mapped state. */
1207 static void gtk_make_frame_visible(struct frame *f)
1208 {
1209         gtk_widget_map(FRAME_GTK_SHELL_WIDGET(f));
1210         gtk_raise_frame_1(f, 0);
1211 }
1212
1213 /* Change from mapped state to withdrawn state. */
1214 static void gtk_make_frame_invisible(struct frame *f)
1215 {
1216         gtk_widget_unmap(FRAME_GTK_SHELL_WIDGET(f));
1217 }
1218
1219 static int gtk_frame_visible_p(struct frame *f)
1220 {
1221         GtkWidget *w = FRAME_GTK_SHELL_WIDGET(f);
1222
1223         f->visible = (GTK_OBJECT_FLAGS(w) & GTK_VISIBLE);
1224
1225         return f->visible;
1226 }
1227
1228 static int gtk_frame_totally_visible_p(struct frame *f)
1229 {
1230         return FRAME_GTK_TOTALLY_VISIBLE_P(f);
1231 }
1232
1233 /* Change window state from mapped to iconified. */
1234 static void gtk_iconify_frame(struct frame *f)
1235 {
1236         GdkWindow *w = GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f));
1237
1238         /* There is no equivalent to XIconifyWindow in Gtk/Gdk. */
1239         if (!XIconifyWindow(GDK_WINDOW_XDISPLAY(w),
1240                             GDK_WINDOW_XWINDOW(w),
1241                             DefaultScreen(GDK_WINDOW_XDISPLAY(w))))
1242                 gtk_cant_notify_wm_error();
1243
1244         f->iconified = 1;
1245 }
1246
1247 /* Sets the X focus to frame f. */
1248 static void gtk_focus_on_frame(struct frame *f)
1249 {
1250         GtkWidget *shell_widget;
1251
1252         assert(FRAME_GTK_P(f));
1253
1254         shell_widget = FRAME_GTK_SHELL_WIDGET(f);
1255         if (!GET_GTK_WIDGET_WINDOW(shell_widget))
1256                 return;
1257
1258         gtk_widget_grab_focus(shell_widget);
1259 }
1260
1261 /* Destroy the window of frame S.  */
1262 static void gtk_delete_frame(struct frame *f)
1263 {
1264         GtkWidget *w = FRAME_GTK_SHELL_WIDGET(f);
1265
1266         gtk_widget_destroy(w);
1267
1268         if (FRAME_GTK_GEOM_FREE_ME_PLEASE(f))
1269                 xfree(FRAME_GTK_GEOM_FREE_ME_PLEASE(f));
1270         xfree(f->frame_data);
1271         f->frame_data = 0;
1272 }
1273
1274 static void gtk_recompute_cell_sizes(struct frame *frm)
1275 {
1276         if (GTK_IS_WINDOW(FRAME_GTK_SHELL_WIDGET(frm))) {
1277                 GtkWindow *w = GTK_WINDOW(FRAME_GTK_SHELL_WIDGET(frm));
1278                 GdkGeometry geometry;
1279                 GdkWindowHints geometry_mask;
1280                 gint width_inc = 10;
1281                 gint height_inc = 10;
1282
1283                 default_face_height_and_width(make_frame(frm), &height_inc,
1284                                               &width_inc);
1285                 geometry_mask = GDK_HINT_RESIZE_INC;
1286                 geometry.width_inc = width_inc;
1287                 geometry.height_inc = height_inc;
1288
1289                 gtk_window_set_geometry_hints(w, FRAME_GTK_TEXT_WIDGET(frm),
1290                                               &geometry, geometry_mask);
1291         }
1292 }
1293
1294 static void
1295 gtk_update_frame_external_traits(struct frame *frm, Lisp_Object name)
1296 {
1297         Lisp_Object frame = Qnil;
1298
1299         XSETFRAME(frame, frm);
1300
1301         if (EQ(name, Qforeground)) {
1302                 Lisp_Object color = FACE_FOREGROUND(Vdefault_face, frame);
1303                 GdkColor *fgc;
1304
1305                 if (!EQ(color, Vthe_null_color_instance)) {
1306                         fgc = COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(color));
1307                         /* #### BILL!!! The X code set the XtNforeground property of
1308                            the text widget here.  Why did they bother?  All that type
1309                            of thing is done down in the guts of the redisplay code,
1310                            not in the Emacs* widgets. */
1311                 }
1312         } else if (EQ(name, Qbackground)) {
1313                 Lisp_Object color = FACE_BACKGROUND(Vdefault_face, frame);
1314                 GdkColor *bgc;
1315
1316                 if (!EQ(color, Vthe_null_color_instance)) {
1317                         bgc = COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(color));
1318                         if (FRAME_GTK_SHELL_WIDGET(frm)->window) {
1319                                 gdk_window_set_background(FRAME_GTK_SHELL_WIDGET
1320                                                           (frm)->window, bgc);
1321                         }
1322                         if (FRAME_GTK_TEXT_WIDGET(frm)->window) {
1323                                 gdk_window_set_background(FRAME_GTK_TEXT_WIDGET
1324                                                           (frm)->window, bgc);
1325                         }
1326                 }
1327
1328                 /* Really crappy way to force the modeline shadows to be
1329                    redrawn.  But effective. */
1330                 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED(frm);
1331                 MARK_FRAME_CHANGED(frm);
1332         } else if (EQ(name, Qfont)) {
1333                 Lisp_Object font =
1334                     FACE_FONT(Vdefault_face, frame, Vcharset_ascii);
1335
1336                 if (!EQ(font, Vthe_null_font_instance)) {
1337                         /* #### BILL!!! The X code set the XtNfont property of the
1338                            text widget here.  Why did they bother?  All that type of
1339                            thing is done down in the guts of the redisplay code, not
1340                            in the Emacs* widgets. */
1341                 }
1342         } else
1343                 abort();
1344
1345 #ifdef HAVE_TOOLBARS
1346         /* Setting the background clears the entire frame area
1347            including the toolbar so we force an immediate redraw of
1348            it. */
1349         if (EQ(name, Qbackground))
1350                 MAYBE_DEVMETH(XDEVICE(frm->device), redraw_frame_toolbars,
1351                               (frm));
1352 #endif                          /* HAVE_TOOLBARS */
1353
1354         /* Set window manager resize increment hints according to
1355            the new character size */
1356         if (EQ(name, Qfont) && FRAME_GTK_TOP_LEVEL_FRAME_P(frm))
1357                 gtk_recompute_cell_sizes(frm);
1358 }
1359 \f
1360 /************************************************************************/
1361 /*                            initialization                            */
1362 /************************************************************************/
1363
1364 void syms_of_frame_gtk(void)
1365 {
1366         defsymbol(&Qwindow_id, "window-id");
1367         defsymbol(&Qtext_widget, "text-widget");
1368         defsymbol(&Qcontainer_widget, "container-widget");
1369         defsymbol(&Qshell_widget, "shell-widget");
1370         defsymbol(&Qdetachable_menubar, "detachable-menubar");
1371
1372 #ifdef HAVE_DRAGNDROP
1373         staticpro(&Vcurrent_drag_object);
1374         Vcurrent_drag_object = Qnil;
1375         DEFSUBR(Fgtk_start_drag_internal);
1376 #endif
1377 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
1378         DEFSUBR(Fgtk_window_id);
1379 #endif
1380 }
1381
1382 void console_type_create_frame_gtk(void)
1383 {
1384         /* frame methods */
1385         CONSOLE_HAS_METHOD(gtk, init_frame_1);
1386         CONSOLE_HAS_METHOD(gtk, init_frame_2);
1387         CONSOLE_HAS_METHOD(gtk, init_frame_3);
1388         CONSOLE_HAS_METHOD(gtk, mark_frame);
1389         CONSOLE_HAS_METHOD(gtk, focus_on_frame);
1390         CONSOLE_HAS_METHOD(gtk, delete_frame);
1391         CONSOLE_HAS_METHOD(gtk, get_mouse_position);
1392 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
1393         CONSOLE_HAS_METHOD(gtk, set_mouse_position);
1394 #endif
1395         CONSOLE_HAS_METHOD(gtk, raise_frame);
1396         CONSOLE_HAS_METHOD(gtk, lower_frame);
1397         CONSOLE_HAS_METHOD(gtk, make_frame_visible);
1398         CONSOLE_HAS_METHOD(gtk, make_frame_invisible);
1399         CONSOLE_HAS_METHOD(gtk, iconify_frame);
1400         CONSOLE_HAS_METHOD(gtk, set_frame_size);
1401         CONSOLE_HAS_METHOD(gtk, set_frame_position);
1402         CONSOLE_HAS_METHOD(gtk, frame_property);
1403         CONSOLE_HAS_METHOD(gtk, internal_frame_property_p);
1404         CONSOLE_HAS_METHOD(gtk, frame_properties);
1405         CONSOLE_HAS_METHOD(gtk, set_frame_properties);
1406         CONSOLE_HAS_METHOD(gtk, set_title_from_bufbyte);
1407         CONSOLE_HAS_METHOD(gtk, set_icon_name_from_bufbyte);
1408         CONSOLE_HAS_METHOD(gtk, frame_visible_p);
1409         CONSOLE_HAS_METHOD(gtk, frame_totally_visible_p);
1410         CONSOLE_HAS_METHOD(gtk, frame_iconified_p);
1411         CONSOLE_HAS_METHOD(gtk, set_frame_pointer);
1412         CONSOLE_HAS_METHOD(gtk, set_frame_icon);
1413         CONSOLE_HAS_METHOD(gtk, get_frame_parent);
1414         CONSOLE_HAS_METHOD(gtk, update_frame_external_traits);
1415 }
1416
1417 void vars_of_frame_gtk(void)
1418 {
1419         DEFVAR_LISP("default-gtk-frame-plist", &Vdefault_gtk_frame_plist        /*
1420 Plist of default frame-creation properties for Gtk frames.
1421 These override what is specified in the resource database and in
1422 `default-frame-plist', but are overridden by the arguments to the
1423 particular call to `make-frame'.
1424
1425 Note: In many cases, properties of a frame are available as specifiers
1426 instead of through the frame-properties mechanism.
1427
1428 Here is a list of recognized frame properties, other than those
1429 documented in `set-frame-properties' (they can be queried and
1430 set at any time, except as otherwise noted):
1431
1432 initially-unmapped               If non-nil, the frame will not be visible
1433 when it is created.  In this case, you
1434 need to call `make-frame-visible' to make
1435 the frame appear.
1436 popup                            If non-nil, it should be a frame, and this
1437 frame will be created as a "popup" frame
1438 whose parent is the given frame.  This
1439 will make the window manager treat the
1440 frame as a dialog box, which may entail
1441 doing different things (e.g. not asking
1442 for positioning, and not iconifying
1443 separate from its parent).
1444 inter-line-space         Not currently implemented.
1445 toolbar-shadow-thickness Thickness of toolbar shadows.
1446 background-toolbar-color Color of toolbar background.
1447 bottom-toolbar-shadow-color      Color of bottom shadows on toolbars.
1448 (*Not* specific to the bottom-toolbar.)
1449 top-toolbar-shadow-color Color of top shadows on toolbars.
1450 (*Not* specific to the top-toolbar.)
1451 internal-border-width            Width of internal border around text area.
1452 border-width                     Width of external border around text area.
1453 top                              Y position (in pixels) of the upper-left
1454 outermost corner of the frame (i.e. the
1455 upper-left of the window-manager
1456 decorations).
1457 left                             X position (in pixels) of the upper-left
1458 outermost corner of the frame (i.e. the
1459 upper-left of the window-manager
1460 decorations).
1461 border-color                     Color of external border around text area.
1462 cursor-color                     Color of text cursor.
1463
1464 See also `default-frame-plist', which specifies properties which apply
1465 to all frames, not just Gtk frames.
1466                                                                                  */ );
1467         Vdefault_gtk_frame_plist = Qnil;
1468
1469         gtk_console_methods->device_specific_frame_props =
1470             &Vdefault_gtk_frame_plist;
1471 }