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 Gdk... do we really need this? */
1087 GDK_WINDOW_XWINDOW(GET_GTK_WIDGET_WINDOW
1088 (FRAME_GTK_TEXT_WIDGET(f))));
1089 return build_string(str);
1093 /************************************************************************/
1094 /* manipulating the X window */
1095 /************************************************************************/
1097 static void gtk_set_frame_position(struct frame *f, int xoff, int yoff)
1099 gtk_widget_set_uposition(FRAME_GTK_SHELL_WIDGET(f), xoff, yoff);
1102 /* Call this to change the size of frame S's x-window. */
1104 static void gtk_set_frame_size(struct frame *f, int cols, int rows)
1106 GtkWidget *shell = FRAME_GTK_SHELL_WIDGET(f);
1107 GdkGeometry geometry;
1108 GdkWindowHints geometry_mask = 0x00;
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;
1117 gtk_window_set_geometry_hints(GTK_WINDOW(shell),
1118 FRAME_GTK_TEXT_WIDGET(f),
1119 &geometry, geometry_mask);
1122 change_frame_size(f, rows, cols, 0);
1127 gtk_widget_size_request(FRAME_GTK_SHELL_WIDGET(f), &req);
1128 gtk_widget_set_usize(FRAME_GTK_SHELL_WIDGET(f), req.width,
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)
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);
1144 #endif /* STUPID_X_SPECIFIC_GTK_STUFF */
1147 gtk_get_mouse_position(struct device *d, Lisp_Object * frame, int *x, int *y)
1149 /* Returns the pixel position within the editor text widget */
1151 GdkWindow *w = gdk_window_at_pointer(&win_x, &win_y);
1152 struct frame *f = NULL;
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.
1160 f = gtk_any_window_to_frame(d, w);
1165 XSETFRAME(*frame, f);
1167 gdk_window_get_pointer(GET_GTK_WIDGET_WINDOW(FRAME_GTK_TEXT_WIDGET(f)),
1168 &win_x, &win_y, NULL);
1176 static void gtk_cant_notify_wm_error(void)
1178 error("Can't notify window manager of iconification.");
1181 /* Raise frame F. */
1182 static void gtk_raise_frame_1(struct frame *f, int force)
1184 if (FRAME_VISIBLE_P(f) || force) {
1185 GdkWindow *emacs_window =
1186 GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f));
1188 gdk_window_raise(emacs_window);
1192 static void gtk_raise_frame(struct frame *f)
1194 gtk_raise_frame_1(f, 1);
1197 /* Lower frame F. */
1198 static void gtk_lower_frame(struct frame *f)
1200 if (FRAME_VISIBLE_P(f)) {
1201 gdk_window_lower(GET_GTK_WIDGET_WINDOW
1202 (FRAME_GTK_SHELL_WIDGET(f)));
1206 /* Change from withdrawn state to mapped state. */
1207 static void gtk_make_frame_visible(struct frame *f)
1209 gtk_widget_map(FRAME_GTK_SHELL_WIDGET(f));
1210 gtk_raise_frame_1(f, 0);
1213 /* Change from mapped state to withdrawn state. */
1214 static void gtk_make_frame_invisible(struct frame *f)
1216 gtk_widget_unmap(FRAME_GTK_SHELL_WIDGET(f));
1219 static int gtk_frame_visible_p(struct frame *f)
1221 GtkWidget *w = FRAME_GTK_SHELL_WIDGET(f);
1223 f->visible = (GTK_OBJECT_FLAGS(w) & GTK_VISIBLE);
1228 static int gtk_frame_totally_visible_p(struct frame *f)
1230 return FRAME_GTK_TOTALLY_VISIBLE_P(f);
1233 /* Change window state from mapped to iconified. */
1234 static void gtk_iconify_frame(struct frame *f)
1236 GdkWindow *w = GET_GTK_WIDGET_WINDOW(FRAME_GTK_SHELL_WIDGET(f));
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();
1247 /* Sets the X focus to frame f. */
1248 static void gtk_focus_on_frame(struct frame *f)
1250 GtkWidget *shell_widget;
1252 assert(FRAME_GTK_P(f));
1254 shell_widget = FRAME_GTK_SHELL_WIDGET(f);
1255 if (!GET_GTK_WIDGET_WINDOW(shell_widget))
1258 gtk_widget_grab_focus(shell_widget);
1261 /* Destroy the window of frame S. */
1262 static void gtk_delete_frame(struct frame *f)
1264 GtkWidget *w = FRAME_GTK_SHELL_WIDGET(f);
1266 gtk_widget_destroy(w);
1268 if (FRAME_GTK_GEOM_FREE_ME_PLEASE(f))
1269 xfree(FRAME_GTK_GEOM_FREE_ME_PLEASE(f));
1270 xfree(f->frame_data);
1274 static void gtk_recompute_cell_sizes(struct frame *frm)
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;
1283 default_face_height_and_width(make_frame(frm), &height_inc,
1285 geometry_mask = GDK_HINT_RESIZE_INC;
1286 geometry.width_inc = width_inc;
1287 geometry.height_inc = height_inc;
1289 gtk_window_set_geometry_hints(w, FRAME_GTK_TEXT_WIDGET(frm),
1290 &geometry, geometry_mask);
1295 gtk_update_frame_external_traits(struct frame *frm, Lisp_Object name)
1297 Lisp_Object frame = Qnil;
1299 XSETFRAME(frame, frm);
1301 if (EQ(name, Qforeground)) {
1302 Lisp_Object color = FACE_FOREGROUND(Vdefault_face, frame);
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. */
1312 } else if (EQ(name, Qbackground)) {
1313 Lisp_Object color = FACE_BACKGROUND(Vdefault_face, frame);
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);
1322 if (FRAME_GTK_TEXT_WIDGET(frm)->window) {
1323 gdk_window_set_background(FRAME_GTK_TEXT_WIDGET
1324 (frm)->window, bgc);
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)) {
1334 FACE_FONT(Vdefault_face, frame, Vcharset_ascii);
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. */
1345 #ifdef HAVE_TOOLBARS
1346 /* Setting the background clears the entire frame area
1347 including the toolbar so we force an immediate redraw of
1349 if (EQ(name, Qbackground))
1350 MAYBE_DEVMETH(XDEVICE(frm->device), redraw_frame_toolbars,
1352 #endif /* HAVE_TOOLBARS */
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);
1360 /************************************************************************/
1361 /* initialization */
1362 /************************************************************************/
1364 void syms_of_frame_gtk(void)
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");
1372 #ifdef HAVE_DRAGNDROP
1373 staticpro(&Vcurrent_drag_object);
1374 Vcurrent_drag_object = Qnil;
1375 DEFSUBR(Fgtk_start_drag_internal);
1377 #ifdef STUPID_X_SPECIFIC_GTK_STUFF
1378 DEFSUBR(Fgtk_window_id);
1382 void console_type_create_frame_gtk(void)
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);
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);
1417 void vars_of_frame_gtk(void)
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'.
1425 Note: In many cases, properties of a frame are available as specifiers
1426 instead of through the frame-properties mechanism.
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):
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
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
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
1461 border-color Color of external border around text area.
1462 cursor-color Color of text cursor.
1464 See also `default-frame-plist', which specifies properties which apply
1465 to all frames, not just Gtk frames.
1467 Vdefault_gtk_frame_plist = Qnil;
1469 gtk_console_methods->device_specific_frame_props =
1470 &Vdefault_gtk_frame_plist;