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.
5 This file is part of SXEmacs
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.
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.
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/>. */
21 /* Synched up with: Not synched with FSF. */
23 /* Substantially rewritten for SXEmacs. */
24 /* Revamped to use Gdk/Gtk by William Perry */
30 #include "console-gtk.h"
32 #include "glyphs-gtk.h"
33 #include "objects-gtk.h"
34 #include "scrollbar-gtk.h"
36 #include "gtk-xemacs.h"
39 #include "events/events.h"
43 #include "ui/window.h"
46 #include <libgnomeui/libgnomeui.h>
53 #define BORDER_WIDTH 0
54 #define INTERNAL_BORDER_WIDTH 0
56 #define TRANSIENT_DATA_IDENTIFIER "sxemacs::transient_for"
57 #define UNMAPPED_DATA_IDENTIFIER "sxemacs::initially_unmapped"
59 #define STUPID_X_SPECIFIC_GTK_STUFF
61 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
65 /* Default properties to use when creating frames. */
66 Lisp_Object Vdefault_gtk_frame_plist;
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;
74 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
75 EXFUN(Fgtk_window_id, 1);
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}
91 static guint dnd_n_targets =
92 sizeof(dnd_target_table) / sizeof(dnd_target_table[0]);
96 /************************************************************************/
97 /* helper functions */
98 /************************************************************************/
100 /* Return the Emacs frame-object which contains the given widget. */
101 struct frame *gtk_widget_to_frame(GtkWidget * w)
103 struct frame *f = NULL;
105 for (; w; w = w->parent) {
106 if ((f = (struct frame *)gtk_object_get_data(GTK_OBJECT(w),
107 GTK_DATA_FRAME_IDENTIFIER)))
111 return (selected_frame());
114 /* Return the Emacs frame-object corresponding to an X window */
115 struct frame *gtk_window_to_frame(struct device *d, GdkWindow * wdesc)
117 Lisp_Object tail, frame;
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. */
124 for (tail = DEVICE_FRAME_LIST(d); CONSP(tail); tail = XCDR(tail)) {
130 && GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f)) == wdesc)
136 /* Like gtk_window_to_frame but also compares the window with the widget's
138 struct frame *gtk_any_window_to_frame(struct device *d, GdkWindow * w)
143 DEVICE_FRAME_LOOP(frmcons, d) {
144 struct frame *fr = XFRAME(XCAR(frmcons));
146 GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(fr)))
148 GET_GTK_WIDGET_WINDOW(FRAME_GTK_CONTAINER_WIDGET
152 GET_GTK_WIDGET_WINDOW(FRAME_GTK_MENUBAR_WIDGET
156 GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(fr))))
161 w = gdk_window_get_parent(w);
167 struct frame *gtk_any_widget_or_parent_to_frame(struct device *d,
170 return (gtk_any_window_to_frame(d, GET_GTK_WIDGET_WINDOW(widget)));
173 struct device *gtk_any_window_to_device(GdkWindow * w)
175 struct device *d = NULL;
176 Lisp_Object devcons, concons;
178 DEVICE_LOOP_NO_BREAK(devcons, concons) {
179 d = XDEVICE(XCAR(devcons));
180 if (!DEVICE_GTK_P(d))
182 if (gtk_any_window_to_frame(d, w))
188 struct frame *decode_gtk_frame(Lisp_Object 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);
199 /************************************************************************/
200 /* window-manager interactions */
201 /************************************************************************/
202 static int gtk_frame_iconified_p(struct frame *f)
204 return (f->iconified);
207 /************************************************************************/
208 /* frame properties */
209 /************************************************************************/
211 static Lisp_Object gtk_frame_property(struct frame *f, Lisp_Object property)
213 GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
215 if (EQ(Qleft, property) || EQ(Qtop, property)) {
217 if (!GET_GTK_WIDGET_WINDOW(shell))
219 gdk_window_get_deskrelative_origin(GET_GTK_WIDGET_WINDOW(shell),
221 if (EQ(Qleft, property))
223 if (EQ(Qtop, property))
226 if (EQ(Qshell_widget, property)) {
227 return (FRAME_GTK_LISP_WIDGETS(f)[0]);
229 if (EQ(Qcontainer_widget, property)) {
230 return (FRAME_GTK_LISP_WIDGETS(f)[1]);
232 if (EQ(Qtext_widget, property)) {
233 return (FRAME_GTK_LISP_WIDGETS(f)[2]);
235 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
236 if (EQ(Qwindow_id, property))
237 return Fgtk_window_id(make_frame(f));
243 static int gtk_internal_frame_property_p(struct frame *f, Lisp_Object property)
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);
254 static Lisp_Object gtk_frame_properties(struct frame *f)
256 Lisp_Object props = Qnil;
257 GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
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);
264 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
265 props = cons3(Qwindow_id, Fgtk_window_id(make_frame(f)), props);
268 if (!GET_GTK_WIDGET_WINDOW(shell))
271 gdk_window_get_deskrelative_origin(GET_GTK_WIDGET_WINDOW(shell),
274 props = cons3(Qtop, make_int(y), props);
275 props = cons3(Qleft, make_int(x), props);
280 /* Functions called only from `gtk_set_frame_properties' to set
281 individual properties. */
284 gtk_set_frame_text_value(struct frame *f, Bufbyte * value,
285 void (*func) (gpointer, gchar *), gpointer arg)
287 gchar *the_text = (gchar *) value;
289 /* Programmer fuckup or window is not realized yet. */
297 /* Optimize for common ASCII case */
298 for (ptr = value; *ptr; ptr++)
299 if (!BYTE_ASCII_P(*ptr)) {
301 C_STRING_TO_EXTERNAL(value, tmp, Qctext);
308 (*func) (arg, (gchar *) the_text);
311 static void gtk_set_title_from_bufbyte(struct frame *f, Bufbyte * name)
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));
319 static void gtk_set_icon_name_from_bufbyte(struct frame *f, Bufbyte * name)
321 gtk_set_frame_text_value(f, name, (void (*)(gpointer, gchar *))
322 gdk_window_set_icon_name,
323 FRAME_GTK_SHELL_WIDGET(f)->window);
326 /* Set the initial frame size as specified. This function is used
327 when the frame's widgets have not yet been realized.
330 gtk_set_initial_frame_size(struct frame *f, int x, int y,
331 unsigned int w, unsigned int h)
333 GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
334 GdkGeometry geometry;
335 GdkWindowHints geometry_mask = 0x00;
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;
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,
349 gtk_window_set_policy(GTK_WINDOW(shell), TRUE, TRUE, FALSE);
355 change_frame_size(f, h, w, 0);
359 gtk_widget_size_request(FRAME_GTK_SHELL_WIDGET(f), &req);
360 gtk_widget_set_usize(FRAME_GTK_SHELL_WIDGET(f), req.width,
365 /* Report that a frame property of frame S is being set or changed.
366 If the property is not specially recognized, do nothing.
369 static void gtk_set_frame_properties(struct frame *f, Lisp_Object plist)
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;
379 for (tail = plist; !NILP(tail); tail = Fcdr(Fcdr(tail))) {
380 Lisp_Object prop = Fcar(tail);
381 Lisp_Object val = Fcar(Fcdr(tail));
384 if (EQ(prop, Qfont)) {
385 /* If the value is not a string we silently ignore it. */
387 Lisp_Object frm, font_spec;
391 Fget(Fget_face(Qdefault), Qfont,
394 Fadd_spec_to_specifier(font_spec, val,
396 update_frame_face_values(f);
399 } else if (EQ(prop, Qwidth)) {
402 width_specified_p = TRUE;
404 } else if (EQ(prop, Qheight)) {
407 height_specified_p = TRUE;
410 /* Further kludge the x/y. */
411 else if (EQ(prop, Qx)) {
413 x = (gint) XINT(val);
414 x_position_specified_p = TRUE;
416 } else if (EQ(prop, Qy)) {
418 y = (gint) XINT(val);
419 y_position_specified_p = TRUE;
425 /* Kludge kludge kludge. We need to deal with the size and position
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;
432 if (!width_specified_p)
434 if (!height_specified_p)
437 /* Kludge kludge kludge kludge. */
438 if (position_specified_p &&
439 (!x_position_specified_p || !y_position_specified_p)) {
441 GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
442 gdk_window_get_deskrelative_origin(GET_GTK_WIDGET_WINDOW
444 (x_position_specified_p
446 (y_position_specified_p
450 if (!f->init_finished) {
451 if (size_specified_p || position_specified_p)
452 gtk_set_initial_frame_size(f, x, y, width,
455 if (size_specified_p) {
458 Fset_frame_size(frame, make_int(width),
459 make_int(height), Qnil);
461 if (position_specified_p) {
464 Fset_frame_position(frame, make_int(x),
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. */
478 extern Lisp_Object Vgtk_initial_geometry;
481 static int get_number(const char **geometry)
486 if (**geometry == '-') {
490 while (**geometry && isdigit(**geometry)) {
491 value = value * 10 + (**geometry - '0');
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
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.
516 * %TRUE if the geometry was successfully parsed, %FALSE otherwise.
520 gnome_parse_geometry(const gchar * geometry, gint * xpos,
521 gint * ypos, gint * width, gint * height)
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);
530 *xpos = *ypos = *width = *height = -1;
535 if (*geometry == '=')
539 if (isdigit(*geometry))
540 *width = get_number(&geometry);
543 if (*geometry == 'x' || *geometry == 'X') {
545 *height = get_number(&geometry);
549 if (*geometry == '+') {
552 } else if (*geometry == '-') {
553 subtract = gdk_screen_width();
557 *xpos = get_number(&geometry);
559 *xpos = subtract - *xpos;
562 if (*geometry == '+') {
565 } else if (*geometry == '-') {
566 subtract = gdk_screen_height();
570 *ypos = get_number(&geometry);
572 *ypos = subtract - *ypos;
577 static void gtk_initialize_frame_size(struct frame *f)
579 gint x = 10, y = 10, w = 80, h = 30;
581 if (STRINGP(Vgtk_initial_geometry)) {
582 if (!gnome_parse_geometry
583 (XSTRING_DATA(Vgtk_initial_geometry), &x, &y, &w, &h)) {
590 /* set the position of the frame's root window now. When the
591 frame was created, the position was initialized to (0,0). */
593 struct window *win = XWINDOW(f->root_window);
595 WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f);
596 WINDOW_TOP(win) = FRAME_TOP_BORDER_END(f);
598 if (!NILP(f->minibuffer_window)) {
599 win = XWINDOW(f->minibuffer_window);
600 WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f);
604 gtk_set_initial_frame_size(f, x, y, w, h);
608 resize_event_cb(GtkWidget * w, GtkAllocation * allocation, gpointer user_data)
610 struct frame *f = (struct frame *)user_data;
612 f->pixwidth = allocation->width;
613 f->pixheight = allocation->height;
615 if (FRAME_GTK_TEXT_WIDGET(f)->window) {
618 Fredraw_frame(frame, Qt);
625 delete_event_cb(GtkWidget * w, GdkEvent * ev, gpointer user_data)
627 struct frame *f = (struct frame *)user_data;
631 enqueue_misc_user_event(frame, Qeval, list3(Qdelete_frame, frame, Qt));
633 /* See if tickling the event queue helps us with our delays when
640 extern gboolean emacs_shell_event_handler(GtkWidget * wid, GdkEvent * event,
642 extern Lisp_Object build_gtk_object(GtkObject * obj);
645 #define GNOME_IS_APP(x) 0
646 #define gnome_app_set_contents(x,y) 0
649 static void cleanup_deleted_frame(gpointer data)
651 struct frame *f = (struct frame *)data;
655 Fdelete_frame(frame, Qt);
658 #ifdef HAVE_DRAGNDROP
660 dragndrop_data_received(GtkWidget * widget,
661 GdkDragContext * context,
664 GtkSelectionData * data, guint info, guint time);
667 dragndrop_dropped(GtkWidget * widget,
668 GdkDragContext * drag_context,
669 gint x, gint y, guint time, gpointer user_data);
671 Lisp_Object Vcurrent_drag_object;
673 #define DRAG_SELECTION_DATA_ERROR "Error converting drag data to external format"
675 dragndrop_get_drag(GtkWidget * widget,
676 GdkDragContext * drag_context,
677 GtkSelectionData * data,
678 guint info, guint time, gpointer user_data)
680 gtk_selection_data_set(data, GDK_SELECTION_TYPE_STRING, 8,
681 DRAG_SELECTION_DATA_ERROR,
682 strlen(DRAG_SELECTION_DATA_ERROR));
685 case TARGET_TYPE_STRING:
687 Lisp_Object string = Vcurrent_drag_object;
689 if (!STRINGP(Vcurrent_drag_object)) {
690 string = Fprin1_to_string(string, Qnil);
691 /* Convert to a string */
694 gtk_selection_data_set(data, GDK_SELECTION_TYPE_STRING,
695 8, XSTRING_DATA(string),
696 XSTRING_LENGTH(string));
699 case TARGET_TYPE_URI_LIST:
704 Vcurrent_drag_object = Qnil;
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.
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);
722 gtk_target_list_new(dnd_target_table, dnd_n_targets);
724 /* only drag if this is really a press */
725 if (EVENT_TYPE(lisp_event) != button_press_event)
728 /* get the desired type */
729 if (!NILP(dtyp) && STRINGP(dtyp))
730 dnd_typ = gdk_atom_intern(XSTRING_DATA(dtyp), FALSE);
732 gtk_drag_begin(wid, tl, GDK_ACTION_COPY,
733 lisp_event->event.button.button, NULL);
735 Vcurrent_drag_object = data;
737 gtk_target_list_unref(tl);
743 /* Creates the widgets for a frame.
744 lisp_window_id is a Lisp description of an X window or Xt
747 This function does not map the windows. (That is
748 done by gtk_popup_frame().)
751 gtk_create_widgets(struct frame *f, Lisp_Object lisp_window_id,
755 GtkWidget *text, *container, *shell;
756 gboolean embedded_p = !NILP(lisp_window_id);
761 if (STRINGP(f->name))
762 TO_EXTERNAL_FORMAT(LISP_STRING, f->name, C_STRING_ALLOCA, name,
767 FRAME_GTK_TOP_LEVEL_FRAME_P(f) = 1;
770 CHECK_GTK_OBJECT(lisp_window_id);
772 if (!GTK_IS_CONTAINER(XGTK_OBJECT(lisp_window_id)->object)) {
774 ("Window ID must be a GtkContainer subclass",
778 shell = gtk_vbox_new(FALSE, 0);
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);
785 shell = GTK_WIDGET(gnome_app_new("SXEmacs", "SXEmacs/GNOME"));
787 shell = GTK_WIDGET(gtk_window_new(GTK_WINDOW_TOPLEVEL));
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));
800 gtk_container_set_border_width(GTK_CONTAINER(shell), 0);
802 gtk_object_set_data(GTK_OBJECT(shell), GTK_DATA_FRAME_IDENTIFIER, f);
804 FRAME_GTK_SHELL_WIDGET(f) = shell;
806 text = GTK_WIDGET(gtk_xemacs_new(f));
808 if (!GNOME_IS_APP(shell))
810 GTK_WIDGET(gtk_vbox_new(FALSE, INTERNAL_BORDER_WIDTH));
814 FRAME_GTK_CONTAINER_WIDGET(f) = container;
815 FRAME_GTK_TEXT_WIDGET(f) = text;
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);
831 /* Create the initial menubar widget. */
832 menubar_visible = gtk_initialize_frame_menubar(f);
834 if (menubar_visible) {
835 gtk_widget_show_all(FRAME_GTK_MENUBAR_WIDGET(f));
837 #endif /* HAVE_MENUBARS */
840 if (GNOME_IS_APP(shell))
841 gnome_app_set_contents(GNOME_APP(shell), text);
844 /* Now comes the drawing area, which should fill the rest of the
847 gtk_box_pack_end(GTK_BOX(container), text, TRUE, TRUE, 0);
849 /* Connect main event handler */
850 gtk_signal_connect(GTK_OBJECT(shell), "delete-event",
851 GTK_SIGNAL_FUNC(delete_event_cb), f);
854 static char *events_to_frob[] = { "focus-in-event",
856 "enter-notify-event",
857 "leave-notify-event",
860 "property-notify-event",
861 "selection-clear-event",
862 "selection-request-event",
863 "selection-notify-event",
865 /* "configure-event", */
866 "visibility-notify-event",
871 for (i = 0; events_to_frob[i]; i++) {
872 gtk_signal_connect(GTK_OBJECT(shell), events_to_frob[i],
874 (emacs_shell_event_handler), f);
878 gtk_signal_connect(GTK_OBJECT(shell), "size-allocate",
879 GTK_SIGNAL_FUNC(resize_event_cb), f);
881 /* This might be safe to call now... */
882 /* gtk_signal_connect (GTK_OBJECT (shell), "event", GTK_SIGNAL_FUNC (emacs_shell_event_handler), f); */
884 /* Let's make sure we get all the events we can */
885 gtk_widget_set_events(text, GDK_ALL_EVENTS_MASK);
887 if (shell != container)
888 gtk_container_add(GTK_CONTAINER(shell), container);
890 gtk_widget_set_name(shell, "SXEmacs::shell");
891 gtk_widget_set_name(container, "SXEmacs::container");
892 gtk_widget_set_name(text, "SXEmacs::text");
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));
898 gtk_widget_realize(shell);
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)
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;
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));
916 gtk_widget_show_all(FRAME_GTK_SHELL_WIDGET(f));
920 static void allocate_gtk_frame_struct(struct frame *f)
922 /* zero out all slots. */
923 f->frame_data = xnew_and_zero(struct gtk_frame);
925 /* yeah, except the lisp ones */
926 FRAME_GTK_ICON_PIXMAP(f) = Qnil;
927 FRAME_GTK_ICON_PIXMAP_MASK(f) = Qnil;
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().
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);
942 /************************************************************************/
944 /************************************************************************/
946 static void gtk_init_frame_1(struct frame *f, Lisp_Object props)
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);
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,
964 initially_unmapped = Fplist_get(props, Qinitially_unmapped, Qnil);
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
978 allocate_gtk_frame_struct(f);
979 gtk_create_widgets(f, lisp_window_id, popup);
981 if (!NILP(initially_unmapped)) {
982 gtk_object_set_data(GTK_OBJECT(FRAME_GTK_SHELL_WIDGET(f)),
983 UNMAPPED_DATA_IDENTIFIER, (gpointer) 1);
987 static void gtk_init_frame_2(struct frame *f, Lisp_Object props)
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. */
992 update_frame_face_values(f);
993 gtk_initialize_frame_size(f);
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.
1000 * It turns out it gives problems with FVWMs name based mapping.
1001 * We'll just need to be carefull in the modeline specs.
1003 update_frame_title(f);
1006 static void gtk_init_frame_3(struct frame *f)
1008 /* Pop up the frame. */
1012 static void gtk_mark_frame(struct frame *f)
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));
1024 static void gtk_set_frame_icon(struct frame *f)
1026 GdkPixmap *gtk_pixmap = NULL, *gtk_mask = NULL;
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);
1037 gdk_window_set_icon(GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f)),
1038 NULL, gtk_pixmap, gtk_mask);
1041 static void gtk_set_frame_pointer(struct frame *f)
1043 GtkWidget *w = FRAME_GTK_TEXT_WIDGET(f);
1044 GdkCursor *c = XIMAGE_INSTANCE_GTK_CURSOR(f->pointer);
1046 if (POINTER_IMAGE_INSTANCEP(f->pointer)) {
1047 gdk_window_set_cursor(GET_GTK_WIDGET_WINDOW(w), c);
1051 stderr_out("POINTER_IMAGE_INSTANCEP (f->pointer) failed!\n");
1055 static Lisp_Object gtk_get_frame_parent(struct frame *f)
1057 GtkWidget *parentwid =
1058 gtk_object_get_data(GTK_OBJECT(FRAME_GTK_SHELL_WIDGET(f)),
1059 TRANSIENT_DATA_IDENTIFIER);
1061 /* find the frame whose wid is 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)
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
1083 struct frame *f = decode_gtk_frame(frame);
1085 /* Arrrrggghhh... this defeats the whole purpose of using
1086 Gdk... do we really need this? */
1087 int sz = snprintf(str, sizeof(str), "%lu",
1088 GDK_WINDOW_XWINDOW(GET_GTK_WIDGET_WINDOW
1089 (FRAME_GTK_TEXT_WIDGET(f))));
1090 assert(sz >= 0 && sz < sizeof(str));
1091 return build_string(str);
1095 /************************************************************************/
1096 /* manipulating the X window */
1097 /************************************************************************/
1099 static void gtk_set_frame_position(struct frame *f, int xoff, int yoff)
1101 gtk_widget_set_uposition(FRAME_GTK_SHELL_WIDGET(f), xoff, yoff);
1104 /* Call this to change the size of frame S's x-window. */
1106 static void gtk_set_frame_size(struct frame *f, int cols, int rows)
1108 GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
1109 GdkGeometry geometry;
1110 GdkWindowHints geometry_mask = 0x00;
1112 if (GTK_IS_WINDOW(shell)) {
1113 /* Update the cell size */
1114 default_face_height_and_width(make_frame(f),
1115 &geometry.height_inc,
1116 &geometry.width_inc);
1117 geometry_mask |= GDK_HINT_RESIZE_INC;
1119 gtk_window_set_geometry_hints(GTK_WINDOW(shell),
1120 FRAME_GTK_TEXT_WIDGET(f),
1121 &geometry, geometry_mask);
1124 change_frame_size(f, rows, cols, 0);
1129 gtk_widget_size_request(FRAME_GTK_SHELL_WIDGET(f), &req);
1130 gtk_widget_set_usize(FRAME_GTK_SHELL_WIDGET(f), req.width,
1135 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
1136 /* There is NO equivalent to XWarpPointer under Gtk */
1137 static void gtk_set_mouse_position(struct window *w, int x, int y)
1139 struct frame *f = XFRAME(w->frame);
1140 Display *display = GDK_DISPLAY();
1141 XWarpPointer(display, None,
1142 GDK_WINDOW_XWINDOW(GET_GTK_WIDGET_WINDOW
1143 (FRAME_GTK_TEXT_WIDGET(f))), 0, 0, 0, 0,
1144 w->pixel_left + x, w->pixel_top + y);
1146 #endif /* STUPID_X_SPECIFIC_GTK_STUFF */
1149 gtk_get_mouse_position(struct device *d, Lisp_Object * frame, int *x, int *y)
1151 /* Returns the pixel position within the editor text widget */
1153 GdkWindow *w = gdk_window_at_pointer(&win_x, &win_y);
1154 struct frame *f = NULL;
1159 /* At this point, w is the innermost GdkWindow containing the
1160 ** pointer and win_x and win_y are the coordinates of that window.
1162 f = gtk_any_window_to_frame(d, w);
1167 XSETFRAME(*frame, f);
1169 gdk_window_get_pointer(GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f)),
1170 &win_x, &win_y, NULL);
1178 static void gtk_cant_notify_wm_error(void)
1180 error("Can't notify window manager of iconification.");
1183 /* Raise frame F. */
1184 static void gtk_raise_frame_1(struct frame *f, int force)
1186 if (FRAME_VISIBLE_P(f) || force) {
1187 GdkWindow *emacs_window =
1188 GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f));
1190 gdk_window_raise(emacs_window);
1194 static void gtk_raise_frame(struct frame *f)
1196 gtk_raise_frame_1(f, 1);
1199 /* Lower frame F. */
1200 static void gtk_lower_frame(struct frame *f)
1202 if (FRAME_VISIBLE_P(f)) {
1203 gdk_window_lower(GET_GTK_WIDGET_WINDOW
1204 (FRAME_GTK_SHELL_WIDGET(f)));
1208 /* Change from withdrawn state to mapped state. */
1209 static void gtk_make_frame_visible(struct frame *f)
1211 gtk_widget_map(FRAME_GTK_SHELL_WIDGET(f));
1212 gtk_raise_frame_1(f, 0);
1215 /* Change from mapped state to withdrawn state. */
1216 static void gtk_make_frame_invisible(struct frame *f)
1218 gtk_widget_unmap(FRAME_GTK_SHELL_WIDGET(f));
1221 static int gtk_frame_visible_p(struct frame *f)
1223 GtkWidget *w = FRAME_GTK_SHELL_WIDGET(f);
1225 f->visible = (GTK_OBJECT_FLAGS(w) & GTK_VISIBLE);
1230 static int gtk_frame_totally_visible_p(struct frame *f)
1232 return FRAME_GTK_TOTALLY_VISIBLE_P(f);
1235 /* Change window state from mapped to iconified. */
1236 static void gtk_iconify_frame(struct frame *f)
1238 GdkWindow *w = GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f));
1240 /* There is no equivalent to XIconifyWindow in Gtk/Gdk. */
1241 if (!XIconifyWindow(GDK_WINDOW_XDISPLAY(w),
1242 GDK_WINDOW_XWINDOW(w),
1243 DefaultScreen(GDK_WINDOW_XDISPLAY(w))))
1244 gtk_cant_notify_wm_error();
1249 /* Sets the X focus to frame f. */
1250 static void gtk_focus_on_frame(struct frame *f)
1252 GtkWidget *shell_widget;
1254 assert(FRAME_GTK_P(f));
1256 shell_widget = FRAME_GTK_SHELL_WIDGET(f);
1257 if (!GET_GTK_WIDGET_WINDOW(shell_widget))
1260 gtk_widget_grab_focus(shell_widget);
1263 /* Destroy the window of frame S. */
1264 static void gtk_delete_frame(struct frame *f)
1266 GtkWidget *w = FRAME_GTK_SHELL_WIDGET(f);
1268 gtk_widget_destroy(w);
1270 if (FRAME_GTK_GEOM_FREE_ME_PLEASE(f))
1271 xfree(FRAME_GTK_GEOM_FREE_ME_PLEASE(f));
1272 xfree(f->frame_data);
1276 static void gtk_recompute_cell_sizes(struct frame *frm)
1278 if (GTK_IS_WINDOW(FRAME_GTK_SHELL_WIDGET(frm))) {
1279 GtkWindow *w = GTK_WINDOW(FRAME_GTK_SHELL_WIDGET(frm));
1280 GdkGeometry geometry;
1281 GdkWindowHints geometry_mask;
1282 gint width_inc = 10;
1283 gint height_inc = 10;
1285 default_face_height_and_width(make_frame(frm), &height_inc,
1287 geometry_mask = GDK_HINT_RESIZE_INC;
1288 geometry.width_inc = width_inc;
1289 geometry.height_inc = height_inc;
1291 gtk_window_set_geometry_hints(w, FRAME_GTK_TEXT_WIDGET(frm),
1292 &geometry, geometry_mask);
1297 gtk_update_frame_external_traits(struct frame *frm, Lisp_Object name)
1299 Lisp_Object frame = Qnil;
1301 XSETFRAME(frame, frm);
1303 if (EQ(name, Qforeground)) {
1304 Lisp_Object color = FACE_FOREGROUND(Vdefault_face, frame);
1307 if (!EQ(color, Vthe_null_color_instance)) {
1308 fgc = COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(color));
1309 /* #### BILL!!! The X code set the XtNforeground property of
1310 the text widget here. Why did they bother? All that type
1311 of thing is done down in the guts of the redisplay code,
1312 not in the Emacs* widgets. */
1314 } else if (EQ(name, Qbackground)) {
1315 Lisp_Object color = FACE_BACKGROUND(Vdefault_face, frame);
1318 if (!EQ(color, Vthe_null_color_instance)) {
1319 bgc = COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(color));
1320 if (FRAME_GTK_SHELL_WIDGET(frm)->window) {
1321 gdk_window_set_background(FRAME_GTK_SHELL_WIDGET
1322 (frm)->window, bgc);
1324 if (FRAME_GTK_TEXT_WIDGET(frm)->window) {
1325 gdk_window_set_background(FRAME_GTK_TEXT_WIDGET
1326 (frm)->window, bgc);
1330 /* Really crappy way to force the modeline shadows to be
1331 redrawn. But effective. */
1332 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED(frm);
1333 MARK_FRAME_CHANGED(frm);
1334 } else if (EQ(name, Qfont)) {
1336 FACE_FONT(Vdefault_face, frame, Vcharset_ascii);
1338 if (!EQ(font, Vthe_null_font_instance)) {
1339 /* #### BILL!!! The X code set the XtNfont property of the
1340 text widget here. Why did they bother? All that type of
1341 thing is done down in the guts of the redisplay code, not
1342 in the Emacs* widgets. */
1347 #ifdef HAVE_TOOLBARS
1348 /* Setting the background clears the entire frame area
1349 including the toolbar so we force an immediate redraw of
1351 if (EQ(name, Qbackground))
1352 MAYBE_DEVMETH(XDEVICE(frm->device), redraw_frame_toolbars,
1354 #endif /* HAVE_TOOLBARS */
1356 /* Set window manager resize increment hints according to
1357 the new character size */
1358 if (EQ(name, Qfont) && FRAME_GTK_TOP_LEVEL_FRAME_P(frm))
1359 gtk_recompute_cell_sizes(frm);
1362 /************************************************************************/
1363 /* initialization */
1364 /************************************************************************/
1366 void syms_of_frame_gtk(void)
1368 defsymbol(&Qwindow_id, "window-id");
1369 defsymbol(&Qtext_widget, "text-widget");
1370 defsymbol(&Qcontainer_widget, "container-widget");
1371 defsymbol(&Qshell_widget, "shell-widget");
1372 defsymbol(&Qdetachable_menubar, "detachable-menubar");
1374 #ifdef HAVE_DRAGNDROP
1375 staticpro(&Vcurrent_drag_object);
1376 Vcurrent_drag_object = Qnil;
1377 DEFSUBR(Fgtk_start_drag_internal);
1379 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
1380 DEFSUBR(Fgtk_window_id);
1384 void console_type_create_frame_gtk(void)
1387 CONSOLE_HAS_METHOD(gtk, init_frame_1);
1388 CONSOLE_HAS_METHOD(gtk, init_frame_2);
1389 CONSOLE_HAS_METHOD(gtk, init_frame_3);
1390 CONSOLE_HAS_METHOD(gtk, mark_frame);
1391 CONSOLE_HAS_METHOD(gtk, focus_on_frame);
1392 CONSOLE_HAS_METHOD(gtk, delete_frame);
1393 CONSOLE_HAS_METHOD(gtk, get_mouse_position);
1394 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
1395 CONSOLE_HAS_METHOD(gtk, set_mouse_position);
1397 CONSOLE_HAS_METHOD(gtk, raise_frame);
1398 CONSOLE_HAS_METHOD(gtk, lower_frame);
1399 CONSOLE_HAS_METHOD(gtk, make_frame_visible);
1400 CONSOLE_HAS_METHOD(gtk, make_frame_invisible);
1401 CONSOLE_HAS_METHOD(gtk, iconify_frame);
1402 CONSOLE_HAS_METHOD(gtk, set_frame_size);
1403 CONSOLE_HAS_METHOD(gtk, set_frame_position);
1404 CONSOLE_HAS_METHOD(gtk, frame_property);
1405 CONSOLE_HAS_METHOD(gtk, internal_frame_property_p);
1406 CONSOLE_HAS_METHOD(gtk, frame_properties);
1407 CONSOLE_HAS_METHOD(gtk, set_frame_properties);
1408 CONSOLE_HAS_METHOD(gtk, set_title_from_bufbyte);
1409 CONSOLE_HAS_METHOD(gtk, set_icon_name_from_bufbyte);
1410 CONSOLE_HAS_METHOD(gtk, frame_visible_p);
1411 CONSOLE_HAS_METHOD(gtk, frame_totally_visible_p);
1412 CONSOLE_HAS_METHOD(gtk, frame_iconified_p);
1413 CONSOLE_HAS_METHOD(gtk, set_frame_pointer);
1414 CONSOLE_HAS_METHOD(gtk, set_frame_icon);
1415 CONSOLE_HAS_METHOD(gtk, get_frame_parent);
1416 CONSOLE_HAS_METHOD(gtk, update_frame_external_traits);
1419 void vars_of_frame_gtk(void)
1421 DEFVAR_LISP("default-gtk-frame-plist", &Vdefault_gtk_frame_plist /*
1422 Plist of default frame-creation properties for Gtk frames.
1423 These override what is specified in the resource database and in
1424 `default-frame-plist', but are overridden by the arguments to the
1425 particular call to `make-frame'.
1427 Note: In many cases, properties of a frame are available as specifiers
1428 instead of through the frame-properties mechanism.
1430 Here is a list of recognized frame properties, other than those
1431 documented in `set-frame-properties' (they can be queried and
1432 set at any time, except as otherwise noted):
1434 initially-unmapped If non-nil, the frame will not be visible
1435 when it is created. In this case, you
1436 need to call `make-frame-visible' to make
1438 popup If non-nil, it should be a frame, and this
1439 frame will be created as a "popup" frame
1440 whose parent is the given frame. This
1441 will make the window manager treat the
1442 frame as a dialog box, which may entail
1443 doing different things (e.g. not asking
1444 for positioning, and not iconifying
1445 separate from its parent).
1446 inter-line-space Not currently implemented.
1447 toolbar-shadow-thickness Thickness of toolbar shadows.
1448 background-toolbar-color Color of toolbar background.
1449 bottom-toolbar-shadow-color Color of bottom shadows on toolbars.
1450 (*Not* specific to the bottom-toolbar.)
1451 top-toolbar-shadow-color Color of top shadows on toolbars.
1452 (*Not* specific to the top-toolbar.)
1453 internal-border-width Width of internal border around text area.
1454 border-width Width of external border around text area.
1455 top Y position (in pixels) of the upper-left
1456 outermost corner of the frame (i.e. the
1457 upper-left of the window-manager
1459 left X position (in pixels) of the upper-left
1460 outermost corner of the frame (i.e. the
1461 upper-left of the window-manager
1463 border-color Color of external border around text area.
1464 cursor-color Color of text cursor.
1466 See also `default-frame-plist', which specifies properties which apply
1467 to all frames, not just Gtk frames.
1469 Vdefault_gtk_frame_plist = Qnil;
1471 gtk_console_methods->device_specific_frame_props =
1472 &Vdefault_gtk_frame_plist;