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 XEmacs. */
25 /* 7-8-00 !!#### This file needs definite Mule review. */
30 #include "console-x.h"
31 #include "xintrinsicp.h" /* CoreP.h needs this */
32 #include <X11/CoreP.h> /* Numerous places access the fields of
33 a core widget directly. We could
34 use XtGetValues(), but ... */
35 #include <X11/Shell.h>
36 #include <X11/ShellP.h>
38 #include "EmacsManager.h"
39 #include "EmacsFrameP.h"
40 #include "EmacsShell.h"
41 #ifdef EXTERNAL_WIDGET
42 #include "ExternalShell.h"
45 #include "objects-x.h"
46 #include "scrollbar-x.h"
49 #include "events/events.h"
53 #include "ui/window.h"
54 #include "ui/gutter.h"
56 #if defined (HAVE_OFFIX_DND) || defined (HAVE_CDE)
57 #include "events/events-mod.h"
60 /* Default properties to use when creating frames. */
61 Lisp_Object Vdefault_x_frame_plist;
63 Lisp_Object Qoverride_redirect;
64 Lisp_Object Qwindow_id;
65 Lisp_Object Qx_resource_name;
67 EXFUN(Fx_window_id, 1);
69 /************************************************************************/
70 /* helper functions */
71 /************************************************************************/
73 /* Return the Emacs frame-object corresponding to an X window */
74 struct frame *x_window_to_frame(struct device *d, Window wdesc)
76 Lisp_Object tail, frame;
79 /* This function was previously written to accept only a window argument
80 (and to loop over all devices looking for a matching window), but
81 that is incorrect because window ID's are not unique across displays. */
83 for (tail = DEVICE_FRAME_LIST(d); CONSP(tail); tail = XCDR(tail)) {
88 if (FRAME_X_P(f) && XtWindow(FRAME_X_TEXT_WIDGET(f)) == wdesc)
94 /* Like x_window_to_frame but also compares the window with the widget's
96 struct frame *x_any_window_to_frame(struct device *d, Window wdesc)
99 assert(DEVICE_X_P(d));
101 w = XtWindowToWidget(DEVICE_X_DISPLAY(d), wdesc);
106 /* We used to map over all frames here and then map over all widgets
107 belonging to that frame. However it turns out that this was very fragile
108 as it requires our display structures to be in sync _and_ that the
109 loop is told about every new widget somebody adds. Therefore we
110 now let Xt find it for us (which does a bottom-up search which
111 could even be faster) */
112 return x_any_widget_or_parent_to_frame(d, w);
115 static struct frame *x_find_frame_for_window(struct device *d, Window wdesc)
117 Lisp_Object tail, frame;
119 /* This function was previously written to accept only a window argument
120 (and to loop over all devices looking for a matching window), but
121 that is incorrect because window ID's are not unique across displays. */
123 for (tail = DEVICE_FRAME_LIST(d); CONSP(tail); tail = XCDR(tail)) {
126 /* This frame matches if the window is any of its widgets. */
127 if (wdesc == XtWindow(FRAME_X_SHELL_WIDGET(f)) ||
128 wdesc == XtWindow(FRAME_X_CONTAINER_WIDGET(f)) ||
129 wdesc == XtWindow(FRAME_X_TEXT_WIDGET(f)))
132 /* Match if the window is one of the widgets at the top of the frame
133 (menubar, Energize psheets). */
135 /* Note: Jamie once said
137 "Do *not* match if the window is this frame's psheet."
139 But this is wrong and will screw up some functions that expect
140 x_any_window_to_frame() to work as advertised. I think the reason
141 for this statement is that, in the old (broken) event loop, where
142 not all events went through XtDispatchEvent(), psheet events
143 would incorrectly get sucked away by Emacs if this function matched
144 on psheet widgets. */
146 /* Note: that this called only from
147 x_any_widget_or_parent_to_frame it is unnecessary to iterate
148 over the top level widgets. */
150 /* Note: we use to special case scrollbars but this turns out to be a bad idea
152 1. We sometimes get events for _unmapped_ scrollbars and our
153 callers don't want us to fail.
154 2. Starting with the 21.2 widget stuff there are now loads of
155 widgets to check and it is easy to forget adding them in a loop here.
156 See x_any_window_to_frame
157 3. We pick up all widgets now anyway. */
163 struct frame *x_any_widget_or_parent_to_frame(struct device *d, Widget widget)
166 struct frame *f = x_find_frame_for_window(d, XtWindow(widget));
169 widget = XtParent(widget);
175 struct frame *decode_x_frame(Lisp_Object frame)
178 XSETFRAME(frame, selected_frame());
179 CHECK_LIVE_FRAME(frame);
180 /* this will also catch dead frames, but putting in the above check
181 results in a more useful error */
182 CHECK_X_FRAME(frame);
183 return XFRAME(frame);
186 /************************************************************************/
187 /* window-manager interactions */
188 /************************************************************************/
191 /* Not currently used. */
193 void x_wm_mark_shell_size_user_specified(Widget wmshell)
195 if (!XtIsWMShell(wmshell))
197 EmacsShellSetSizeUserSpecified(wmshell);
200 void x_wm_mark_shell_position_user_specified(Widget wmshell)
202 if (!XtIsWMShell(wmshell))
204 EmacsShellSetPositionUserSpecified(wmshell);
209 void x_wm_set_shell_iconic_p(Widget shell, int iconic_p)
211 if (!XtIsWMShell(shell))
214 /* Because of questionable logic in Shell.c, this sequence can't work:
216 w = XtCreatePopupShell (...);
217 Xt_SET_VALUE (w, XtNiconic, True);
220 The iconic resource is only consulted at initialization time (when
221 XtCreatePopupShell is called) instead of at realization time (just
222 before the window gets created, which would be more sensible) or
223 at management-time (just before the window gets mapped, which would
224 be most sensible of all).
226 The bug is that Shell's SetValues method doesn't do anything to
227 w->wm.wm_hints.initial_state until after the widget has been realized.
228 Calls to XtSetValues are ignored in the window between creation and
229 realization. This is true of MIT X11R5 patch level 25, at least.
230 (Apparently some other versions of Xt don't have this bug?)
232 Xt_SET_VALUE(shell, XtNiconic, iconic_p);
233 EmacsShellSmashIconicHint(shell, iconic_p);
236 void x_wm_set_cell_size(Widget wmshell, int cw, int ch)
240 if (!XtIsWMShell(wmshell))
242 if (cw <= 0 || ch <= 0)
245 XtSetArg(al[0], XtNwidthInc, cw);
246 XtSetArg(al[1], XtNheightInc, ch);
247 XtSetValues(wmshell, al, 2);
250 void x_wm_set_variable_size(Widget wmshell, int width, int height)
254 if (!XtIsWMShell(wmshell))
256 #ifdef DEBUG_GEOMETRY_MANAGEMENT
257 /* See comment in EmacsShell.c */
258 printf("x_wm_set_variable_size: %d %d\n", width, height);
262 XtSetArg(al[0], XtNwidthCells, width);
263 XtSetArg(al[1], XtNheightCells, height);
264 XtSetValues(wmshell, al, 2);
267 /* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS
268 and WM_DELETE_WINDOW, then add them. (They may already be present
269 because of the toolkit (Motif adds them, for example, but Xt doesn't).
271 static void x_wm_hack_wm_protocols(Widget widget)
273 Display *dpy = XtDisplay(widget);
274 struct device *d = get_device_from_display(dpy);
275 Window w = XtWindow(widget);
279 assert(XtIsWMShell(widget));
282 Atom type, *atoms = 0;
284 unsigned long nitems = 0;
285 unsigned long bytes_after;
288 XGetWindowProperty(dpy, w, DEVICE_XATOM_WM_PROTOCOLS(d), 0,
289 100, False, XA_ATOM, &type, &format,
290 &nitems, &bytes_after,
291 (unsigned char **)((void*)&atoms))
292 && format == 32 && type == XA_ATOM)
296 DEVICE_XATOM_WM_DELETE_WINDOW(d))
298 else if (atoms[nitems] ==
299 DEVICE_XATOM_WM_TAKE_FOCUS(d))
303 XFree((char *)atoms);
309 props[count++] = DEVICE_XATOM_WM_DELETE_WINDOW(d);
311 props[count++] = DEVICE_XATOM_WM_TAKE_FOCUS(d);
313 XChangeProperty(dpy, w, DEVICE_XATOM_WM_PROTOCOLS(d),
314 XA_ATOM, 32, PropModeAppend,
315 (unsigned char *)props, count);
319 static void x_wm_store_class_hints(Widget shell, char *frame_name)
321 Display *dpy = XtDisplay(shell);
322 char *app_name, *app_class;
323 XClassHint classhint;
325 if (!XtIsWMShell(shell))
328 XtGetApplicationNameAndClass(dpy, &app_name, &app_class);
329 classhint.res_name = frame_name;
330 classhint.res_class = app_class;
331 XSetClassHint(dpy, XtWindow(shell), &classhint);
334 #ifndef HAVE_WMCOMMAND
335 static void x_wm_maybe_store_wm_command(struct frame *f)
337 Widget w = FRAME_X_SHELL_WIDGET(f);
338 struct device *d = XDEVICE(FRAME_DEVICE(f));
343 if (NILP(DEVICE_X_WM_COMMAND_FRAME(d))) {
346 make_argc_argv(Vcommand_line_args, &argc, &argv);
347 XSetCommand(XtDisplay(w), XtWindow(w), argv, argc);
348 free_argc_argv(argv);
349 XSETFRAME(DEVICE_X_WM_COMMAND_FRAME(d), f);
353 /* If we're deleting the frame on which the WM_COMMAND property has been
354 set, then move that property to another frame so that there is exactly
355 one frame that has that property set.
357 static void x_wm_maybe_move_wm_command(struct frame *f)
359 struct device *d = XDEVICE(FRAME_DEVICE(f));
361 /* There may not be a frame in DEVICE_X_WM_COMMAND_FRAME()
362 if we C-c'ed at startup at the right time. */
363 if (FRAMEP(DEVICE_X_WM_COMMAND_FRAME(d))
364 && f == XFRAME(DEVICE_X_WM_COMMAND_FRAME(d))) {
365 Lisp_Object rest = DEVICE_FRAME_LIST(d);
366 DEVICE_X_WM_COMMAND_FRAME(d) = Qnil;
367 /* find some random other X frame that is not this one, or give up */
368 /* skip non-top-level (ExternalClient) frames */
369 while (!NILP(rest) &&
370 (f == XFRAME(XCAR(rest)) ||
371 !FRAME_X_TOP_LEVEL_FRAME_P(XFRAME(XCAR(rest)))))
375 f = XFRAME(XCAR(rest));
377 x_wm_maybe_store_wm_command(f);
381 #endif /* !HAVE_WMCOMMAND */
383 static int x_frame_iconified_p(struct frame *f)
387 unsigned long nitems, bytesafter;
388 unsigned long *datap = 0;
391 struct device *d = XDEVICE(FRAME_DEVICE(f));
393 widget = FRAME_X_SHELL_WIDGET(f);
394 if (Success == XGetWindowProperty(XtDisplay(widget), XtWindow(widget),
395 DEVICE_XATOM_WM_STATE(d), 0, 2, False,
396 DEVICE_XATOM_WM_STATE(d),
397 &actual_type, &actual_format, &nitems,
399 (unsigned char **)((void*)&datap))
401 if (nitems <= 2 /* "suggested" by ICCCM version 1 */
402 && datap[0] == IconicState)
404 XFree((char *)datap);
409 /************************************************************************/
410 /* frame properties */
411 /************************************************************************/
413 /* Connect the frame-property names (symbols) to the corresponding
414 X Resource Manager names. The name of a property, as a Lisp symbol,
415 has an `x-resource-name' property which is a Lisp_String. */
417 static void init_x_prop_symbols(void)
419 #define def(sym, rsrc) \
420 Fput (sym, Qx_resource_name, build_string (rsrc))
421 #define defi(sym,rsrc) \
422 def (sym, rsrc); Fput (sym, Qintegerp, Qt)
424 #if 0 /* this interferes with things. #### fix this right */
425 def(Qminibuffer, XtNminibuffer);
426 def(Qunsplittable, XtNunsplittable);
428 defi(Qinternal_border_width, XtNinternalBorderWidth);
430 def(Qtop_toolbar_shadow_color, XtNtopToolBarShadowColor);
431 def(Qbottom_toolbar_shadow_color, XtNbottomToolBarShadowColor);
432 def(Qbackground_toolbar_color, XtNbackgroundToolBarColor);
433 def(Qtop_toolbar_shadow_pixmap, XtNtopToolBarShadowPixmap);
434 def(Qbottom_toolbar_shadow_pixmap, XtNbottomToolBarShadowPixmap);
435 defi(Qtoolbar_shadow_thickness, XtNtoolBarShadowThickness);
437 def(Qscrollbar_placement, XtNscrollBarPlacement);
438 defi(Qinter_line_space, XtNinterline);
439 /* font, foreground */
440 def(Qiconic, XtNiconic);
441 def(Qbar_cursor, XtNbarCursor);
442 def(Qvisual_bell, XtNvisualBell);
443 defi(Qbell_volume, XtNbellVolume);
444 def(Qpointer_background, XtNpointerBackground);
445 def(Qpointer_color, XtNpointerColor);
446 def(Qtext_pointer, XtNtextPointer);
447 def(Qspace_pointer, XtNspacePointer);
448 def(Qmodeline_pointer, XtNmodeLinePointer);
449 def(Qgc_pointer, XtNgcPointer);
450 /* geometry, initial_geometry */
451 def(Qinitially_unmapped, XtNinitiallyUnmapped);
452 /* preferred_width, preferred_height */
453 def(Quse_backing_store, XtNuseBackingStore);
457 def(Qborder_color, XtNborderColor);
458 defi(Qborder_width, XtNborderWidth);
459 defi(Qwidth, XtNwidth);
460 defi(Qheight, XtNheight);
467 static Lisp_Object color_to_string(Widget w, unsigned long pixel)
473 XQueryColor(XtDisplay(w), w->core.colormap, &color);
474 sprintf(buf, "#%04x%04x%04x", color.red, color.green, color.blue);
475 return build_string(buf);
479 x_get_top_level_position(Display * d, Window w, Position * x, Position * y)
481 Window root, parent = w, *children;
482 unsigned int nchildren;
483 XWindowAttributes xwa;
487 if (!XQueryTree(d, w, &root, &parent, &children, &nchildren)) {
494 while (root != parent);
495 XGetWindowAttributes(d, w, &xwa);
501 static void x_smash_bastardly_shell_position(Widget shell)
503 /* Naturally those bastards who wrote Xt couldn't be bothered
504 to learn about race conditions and such. We can't trust
505 the X and Y values to have any semblance of correctness,
506 so we smash the right values in place. */
508 /* We might be called before we've actually realized the window (if
509 we're checking for the minibuffer resource). This will bomb in
510 that case so we don't bother calling it. */
512 x_get_top_level_position(XtDisplay(shell), XtWindow(shell),
513 &shell->core.x, &shell->core.y);
517 static Lisp_Object x_frame_property(struct frame *f, Lisp_Object property)
519 Widget shell = FRAME_X_SHELL_WIDGET(f);
520 EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET(f);
521 Widget gw = (Widget) w;
523 if (EQ(Qleft, property) || EQ(Qtop, property)) {
525 if (!XtWindow(shell))
527 x_get_top_level_position(XtDisplay(shell), XtWindow(shell), &x,
529 if (EQ(Qleft, property))
531 if (EQ(Qtop, property))
534 if (EQ(Qborder_width, property))
535 return make_int(w->core.border_width);
536 if (EQ(Qinternal_border_width, property))
537 return make_int(w->emacs_frame.internal_border_width);
538 if (EQ(Qborder_color, property))
539 return color_to_string(gw, w->core.border_pixel);
541 if (EQ(Qtop_toolbar_shadow_color, property))
542 return color_to_string(gw,
543 w->emacs_frame.top_toolbar_shadow_pixel);
544 if (EQ(Qbottom_toolbar_shadow_color, property))
545 return color_to_string(gw,
547 bottom_toolbar_shadow_pixel);
548 if (EQ(Qbackground_toolbar_color, property))
549 return color_to_string(gw,
550 w->emacs_frame.background_toolbar_pixel);
551 if (EQ(Qtoolbar_shadow_thickness, property))
552 return make_int(w->emacs_frame.toolbar_shadow_thickness);
553 #endif /* HAVE_TOOLBARS */
554 if (EQ(Qinter_line_space, property))
555 return make_int(w->emacs_frame.interline);
556 if (EQ(Qwindow_id, property))
557 return Fx_window_id(make_frame(f));
562 static int x_internal_frame_property_p(struct frame *f, Lisp_Object property)
564 return EQ(property, Qleft)
565 || EQ(property, Qtop)
566 || EQ(property, Qborder_width)
567 || EQ(property, Qinternal_border_width)
568 || EQ(property, Qborder_color)
570 || EQ(property, Qtop_toolbar_shadow_color)
571 || EQ(property, Qbottom_toolbar_shadow_color)
572 || EQ(property, Qbackground_toolbar_color)
573 || EQ(property, Qtoolbar_shadow_thickness)
574 #endif /* HAVE_TOOLBARS */
575 || EQ(property, Qinter_line_space)
576 || EQ(property, Qwindow_id)
577 || STRINGP(property);
580 static Lisp_Object x_frame_properties(struct frame *f)
582 Lisp_Object props = Qnil;
583 Widget shell = FRAME_X_SHELL_WIDGET(f);
584 EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET(f);
585 Widget gw = (Widget) w;
588 props = cons3(Qwindow_id, Fx_window_id(make_frame(f)), props);
590 cons3(Qinter_line_space, make_int(w->emacs_frame.interline), props);
593 props = cons3(Qtoolbar_shadow_thickness,
594 make_int(w->emacs_frame.toolbar_shadow_thickness), props);
595 props = cons3(Qbackground_toolbar_color,
597 w->emacs_frame.background_toolbar_pixel),
600 cons3(Qbottom_toolbar_shadow_color,
602 w->emacs_frame.bottom_toolbar_shadow_pixel),
605 cons3(Qtop_toolbar_shadow_color,
606 color_to_string(gw, w->emacs_frame.top_toolbar_shadow_pixel),
608 #endif /* HAVE_TOOLBARS */
610 props = cons3(Qborder_color,
611 color_to_string(gw, w->core.border_pixel), props);
612 props = cons3(Qinternal_border_width,
613 make_int(w->emacs_frame.internal_border_width), props);
614 props = cons3(Qborder_width, make_int(w->core.border_width), props);
616 if (!XtWindow(shell))
619 x_get_top_level_position(XtDisplay(shell), XtWindow(shell), &x,
622 props = cons3(Qtop, make_int(y), props);
623 props = cons3(Qleft, make_int(x), props);
628 /* Functions called only from `x_set_frame_properties' to set
629 individual properties. */
632 x_set_frame_text_value(struct frame *f, Bufbyte * value,
633 String Xt_resource_name,
634 String Xt_resource_encoding_name)
636 Atom encoding = XA_STRING;
637 String new_XtValue = (String) value;
638 String old_XtValue = NULL;
642 /* Optimize for common ASCII case */
643 for (ptr = value; *ptr; ptr++)
644 if (!BYTE_ASCII_P(*ptr)) {
646 encoding = DEVICE_XATOM_COMPOUND_TEXT(
647 XDEVICE(FRAME_DEVICE(f)));
648 C_STRING_TO_EXTERNAL(value, tmp, Qctext);
649 new_XtValue = (String) tmp;
654 /* #### Caching is device-independent - belongs in update_frame_title. */
655 Xt_GET_VALUE(FRAME_X_SHELL_WIDGET(f), Xt_resource_name, &old_XtValue);
656 if (!old_XtValue || strcmp(new_XtValue, old_XtValue)) {
658 XtSetArg(al[0], Xt_resource_name, new_XtValue);
659 XtSetArg(al[1], Xt_resource_encoding_name, encoding);
660 XtSetValues(FRAME_X_SHELL_WIDGET(f), al, 2);
664 static void x_set_title_from_bufbyte(struct frame *f, Bufbyte * name)
666 x_set_frame_text_value(f, name, XtNtitle, XtNtitleEncoding);
669 static void x_set_icon_name_from_bufbyte(struct frame *f, Bufbyte * name)
671 x_set_frame_text_value(f, name, XtNiconName, XtNiconNameEncoding);
674 /* Set the initial frame size as specified. This function is used
675 when the frame's widgets have not yet been realized. In this
676 case, it is not sufficient just to set the width and height of
677 the EmacsFrame widget, because they will be ignored when the
678 widget is realized (instead, the shell's geometry resource is
682 x_set_initial_frame_size(struct frame *f, int flags, int x, int y,
683 unsigned int w, unsigned int h)
685 char shell_geom[255];
688 char uspos = !!(flags & (XValue | YValue));
689 char ussize = !!(flags & (WidthValue | HeightValue));
692 /* assign the correct size to the EmacsFrame widget ... */
693 EmacsFrameSetCharSize(FRAME_X_TEXT_WIDGET(f), w, h);
695 /* and also set the WMShell's geometry */
696 (flags & XNegative) ? (xval = -x, xsign = '-') : (xval = x, xsign =
698 (flags & YNegative) ? (yval = -y, ysign = '-') : (yval = y, ysign =
702 sprintf(shell_geom, "=%dx%d%c%d%c%d", w, h, xsign, xval, ysign,
705 sprintf(shell_geom, "=%c%d%c%d", xsign, xval, ysign, yval);
707 sprintf(shell_geom, "=%dx%d", w, h);
709 if (uspos || ussize) {
710 temp = xnew_atomic_array(char, 1 + strlen(shell_geom));
711 strcpy(temp, shell_geom);
712 FRAME_X_GEOM_FREE_ME_PLEASE(f) = temp;
716 Xt_SET_VALUE(FRAME_X_SHELL_WIDGET(f), XtNgeometry, temp);
719 /* Report to X that a frame property of frame S is being set or changed.
720 If the property is not specially recognized, do nothing.
723 static void x_set_frame_properties(struct frame *f, Lisp_Object plist)
726 Dimension width = 0, height = 0;
727 Bool width_specified_p = False;
728 Bool height_specified_p = False;
729 Bool x_position_specified_p = False;
730 Bool y_position_specified_p = False;
731 Bool internal_border_width_specified = False;
735 /* We can be called after the X IO error handler has seen a
736 broken pipe on the relevant display. Don't do anything in
738 if (!FRAME_LIVE_P (f) || DEVICE_X_BEING_DELETED (XDEVICE (FRAME_DEVICE (f))))
741 w = FRAME_X_TEXT_WIDGET (f);
743 for (tail = plist; !NILP(tail); tail = Fcdr(Fcdr(tail))) {
744 Lisp_Object prop = Fcar(tail);
745 Lisp_Object val = Fcar(Fcdr(tail));
750 if (XSTRING_LENGTH(prop) == 0)
753 LISP_STRING_TO_EXTERNAL(prop, extprop, Qctext);
755 const Extbyte *extval;
758 TO_EXTERNAL_FORMAT(LISP_STRING, val,
759 ALLOCA, (extval, extvallen),
761 XtVaSetValues(w, XtVaTypedArg, extprop,
762 XtRString, extval, extvallen + 1,
765 XtVaSetValues(w, XtVaTypedArg, extprop, XtRInt,
766 XINT(val), sizeof(int),
768 } else if (SYMBOLP(prop)) {
769 Lisp_Object str = Fget(prop, Qx_resource_name, Qnil);
770 int int_p = !NILP(Fget(prop, Qintegerp, Qnil));
772 if (NILP(prop) || NILP(str)) {
773 /* Kludge to handle the font property. */
774 if (EQ(prop, Qfont)) {
775 /* If the value is not a string we silently ignore it. */
777 Lisp_Object frm, font_spec;
781 Fget(Fget_face(Qdefault),
784 Fadd_spec_to_specifier
785 (font_spec, val, frm, Qnil,
787 update_frame_face_values(f);
796 /* Kludge the width/height so that we interpret them in characters
797 instead of pixels. Yuck yuck yuck. */
798 if (!strcmp((char *)XSTRING_DATA(str), "width")) {
801 width_specified_p = True;
804 if (!strcmp((char *)XSTRING_DATA(str), "height")) {
807 height_specified_p = True;
810 /* Further kludge the x/y. */
811 if (!strcmp((char *)XSTRING_DATA(str), "x")) {
813 x = (Position) XINT(val);
814 x_position_specified_p = True;
817 if (!strcmp((char *)XSTRING_DATA(str), "y")) {
819 y = (Position) XINT(val);
820 y_position_specified_p = True;
823 /* Have you figured out by now that this entire function is
824 one gigantic kludge? */
825 if (!strcmp((char *)XSTRING_DATA(str),
826 "internalBorderWidth")) {
827 internal_border_width_specified = True;
832 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str),
834 } else if (EQ(val, Qt)) {
835 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str), True); /* XtN... */
836 } else if (EQ(val, Qnil)) {
837 Xt_SET_VALUE(w, (char *)XSTRING_DATA(str), False); /* XtN... */
840 XtVaSetValues(w, XtVaTypedArg,
842 (char *)XSTRING_DATA(str),
845 XSTRING_LENGTH(val) + 1,
849 #ifdef HAVE_SCROLLBARS
850 if (!strcmp((char *)XSTRING_DATA(str), "scrollBarWidth")
851 || !strcmp((char *)XSTRING_DATA(str),
852 "scrollBarHeight")) {
853 x_update_frame_scrollbars(f);
855 #endif /* HAVE_SCROLLBARS */
859 /* Kludge kludge kludge. We need to deal with the size and position
862 int size_specified_p = width_specified_p || height_specified_p;
863 int position_specified_p = x_position_specified_p ||
864 y_position_specified_p;
866 if (!width_specified_p)
867 width = FRAME_WIDTH(f);
868 if (!height_specified_p)
869 height = FRAME_HEIGHT(f);
871 /* Kludge kludge kludge kludge. */
872 if (position_specified_p &&
873 (!x_position_specified_p || !y_position_specified_p)) {
875 Widget shell = FRAME_X_SHELL_WIDGET(f);
876 x_get_top_level_position(XtDisplay(shell),
878 (x_position_specified_p ?
880 (y_position_specified_p ?
883 x = (int)(FRAME_X_SHELL_WIDGET(f)->core.x);
884 y = (int)(FRAME_X_SHELL_WIDGET(f)->core.y);
888 if (!f->init_finished) {
890 (size_specified_p ? WidthValue | HeightValue : 0) |
891 (position_specified_p ? XValue | YValue |
892 (x < 0 ? XNegative : 0) | (y < 0 ? YNegative : 0)
895 || position_specified_p
896 || internal_border_width_specified)
897 x_set_initial_frame_size(f, flags, x, y, width,
900 if (size_specified_p || internal_border_width_specified) {
903 Fset_frame_size(frame, make_int(width),
904 make_int(height), Qnil);
906 if (position_specified_p) {
909 Fset_frame_position(frame, make_int(x),
916 static int frame_title_format_already_set;
918 static void maybe_set_frame_title_format(Widget shell)
921 /* Only do this if this is the first X frame we're creating.
923 If the *title resource (or -title option) was specified, then
924 set frame-title-format to its value.
927 if (!frame_title_format_already_set) {
928 /* No doubt there's a less stupid way to do this. */
930 XtResource resources[2];
931 results[0] = results[1] = 0;
932 resources[0].resource_name = XtNtitle;
933 resources[0].resource_class = XtCTitle;
934 resources[0].resource_type = XtRString;
935 resources[0].resource_size = sizeof(String);
936 resources[0].resource_offset = 0;
937 resources[0].default_type = XtRString;
938 resources[0].default_addr = 0;
939 resources[1].resource_name = XtNiconName;
940 resources[1].resource_class = XtCIconName;
941 resources[1].resource_type = XtRString;
942 resources[1].resource_size = sizeof(String);
943 resources[1].resource_offset = sizeof(char *);
944 resources[1].default_type = XtRString;
945 resources[1].default_addr = 0;
946 XtGetSubresources(XtParent(shell), (XtPointer) results,
948 shell->core.widget_class->core_class.
949 class_name, resources, XtNumber(resources), 0,
952 Vframe_title_format = build_string(results[0]);
954 Vframe_icon_title_format = build_string(results[1]);
957 frame_title_format_already_set = 1;
964 static Widget CurrentDragWidget = NULL;
965 static XtCallbackRec dnd_convert_cb_rec[2];
966 static XtCallbackRec dnd_destroy_cb_rec[2];
967 static int drag_not_done = 0;
970 x_cde_destroy_callback(Widget widget, XtPointer clientData, XtPointer callData)
972 DtDndDragFinishCallbackStruct *dragFinishInfo =
973 (DtDndDragFinishCallbackStruct *) callData;
974 DtDndContext *dragData = dragFinishInfo->dragData;
978 if (callData != NULL && dragData != NULL) {
979 if (dragData->protocol == DtDND_BUFFER_TRANSFER) {
980 for (i = 0; i < dragData->numItems; i++) {
981 XtFree((char *)dragData->data.buffers[i].bp);
982 if (dragData->data.buffers[i].name)
983 XtFree(dragData->data.buffers[i].name);
986 for (i = 0; i < dragData->numItems; i++)
987 XtFree(dragData->data.files[i]);
991 /* free the data string */
994 CurrentDragWidget = NULL;
998 x_cde_convert_callback(Widget widget, XtPointer clientData, XtPointer callData)
1000 DtDndConvertCallbackStruct *convertInfo =
1001 (DtDndConvertCallbackStruct *) callData;
1002 char *textdata = (char *)clientData;
1003 char *textptr = NULL;
1006 if (convertInfo == NULL) {
1010 if ((convertInfo->dragData->protocol != DtDND_BUFFER_TRANSFER
1011 && convertInfo->dragData->protocol != DtDND_FILENAME_TRANSFER) ||
1012 (convertInfo->reason != DtCR_DND_CONVERT_DATA)) {
1016 for (textptr = textdata, i = 0;
1017 i < convertInfo->dragData->numItems;
1018 textptr += strlen(textptr) + 1, i++) {
1019 if (convertInfo->dragData->protocol == DtDND_BUFFER_TRANSFER) {
1020 convertInfo->dragData->data.buffers[i].bp =
1021 XtNewString(textptr);
1022 convertInfo->dragData->data.buffers[i].size =
1024 convertInfo->dragData->data.buffers[i].name = NULL;
1026 convertInfo->dragData->data.files[i] =
1027 XtNewString(textptr);
1031 convertInfo->status = DtDND_SUCCESS;
1034 static Lisp_Object abort_current_drag(Lisp_Object arg)
1036 if (CurrentDragWidget && drag_not_done) {
1037 XmDragCancel(CurrentDragWidget);
1038 CurrentDragWidget = NULL;
1043 DEFUN("cde-start-drag-internal", Fcde_start_drag_internal, 3, 3, 0, /*
1044 Start a CDE drag from a buffer.
1045 First argument is the event that started the drag (must be a
1046 button-press-event),
1047 second arg defines if the data should be treated as a buffer or
1048 a filename transfer (set to nil for buffer transfer),
1049 and the third argument is a list of data strings.
1050 WARNING: can only handle plain/text and file: transfers!
1052 (event, dragtype, dragdata))
1054 if (EVENTP(event)) {
1055 struct frame *f = decode_x_frame(Fselected_frame(Qnil));
1057 Widget wid = FRAME_X_TEXT_WIDGET(f);
1058 Display *display = XtDisplayOfObject(wid);
1059 struct device *d = get_device_from_display(display);
1060 struct x_device *xd = DEVICE_X_DATA(d);
1061 XWindowAttributes win_attrib;
1062 unsigned int modifier = 0, state = 0;
1064 int numItems = 0, textlen = 0, pos = 0;
1065 Lisp_Event *lisp_event = XEVENT(event);
1066 Lisp_Object item = Qnil;
1067 struct gcpro gcpro1;
1069 /* only drag if this is really a press */
1070 if (EVENT_TYPE(lisp_event) != button_press_event
1071 || !LISTP(dragdata))
1077 * not so cross hack that converts a emacs event back to a XEvent
1080 x_event.xbutton.type = ButtonPress;
1081 x_event.xbutton.send_event = False;
1082 x_event.xbutton.display = XtDisplayOfObject(wid);
1083 x_event.xbutton.window = XtWindowOfObject(wid);
1084 x_event.xbutton.root = XRootWindow(x_event.xbutton.display, 0);
1085 x_event.xbutton.subwindow = 0;
1086 x_event.xbutton.time = lisp_event->timestamp;
1087 x_event.xbutton.x = lisp_event->event.button.x;
1088 x_event.xbutton.y = lisp_event->event.button.y;
1089 if (Success == XGetWindowAttributes(x_event.xbutton.display,
1090 x_event.xbutton.window,
1092 x_event.xbutton.x_root =
1093 win_attrib.x + lisp_event->event.button.x;
1094 x_event.xbutton.y_root =
1095 win_attrib.y + lisp_event->event.button.y;
1097 x_event.xbutton.x_root = lisp_event->event.button.x; /* this is wrong */
1098 x_event.xbutton.y_root = lisp_event->event.button.y;
1100 modifier = lisp_event->event.button.modifiers;
1101 if (modifier & XEMACS_MOD_SHIFT)
1103 if (modifier & XEMACS_MOD_CONTROL)
1104 state |= ControlMask;
1105 if (modifier & XEMACS_MOD_META)
1106 state |= xd->MetaMask;
1107 if (modifier & XEMACS_MOD_SUPER)
1108 state |= xd->SuperMask;
1109 if (modifier & XEMACS_MOD_HYPER)
1110 state |= xd->HyperMask;
1111 if (modifier & XEMACS_MOD_ALT)
1112 state |= xd->AltMask;
1113 state |= Button1Mask << (lisp_event->event.button.button - 1);
1115 x_event.xbutton.state = state;
1116 x_event.xbutton.button = lisp_event->event.button.button;
1117 x_event.xkey.same_screen = True;
1119 /* convert data strings into a big string */
1121 while (!NILP(item)) {
1122 if (!STRINGP(XCAR(item))) {
1126 textlen += XSTRING_LENGTH(XCAR(item)) + 1;
1133 * concatenate all strings given to one large string, with
1134 * \0 as separator. List is ended by \0.
1136 Ctext = (char*)xmalloc_atomic(textlen + 1);
1140 while (!NILP(item)) {
1141 if (!STRINGP(XCAR(item))) {
1148 (const char *)XSTRING_DATA(XCAR(item)));
1149 pos += XSTRING_LENGTH(XCAR(item)) + 1;
1154 dnd_convert_cb_rec[0].callback = x_cde_convert_callback;
1155 dnd_convert_cb_rec[0].closure = (XtPointer) Ctext;
1156 dnd_convert_cb_rec[1].callback = NULL;
1157 dnd_convert_cb_rec[1].closure = NULL;
1159 dnd_destroy_cb_rec[0].callback = x_cde_destroy_callback;
1160 dnd_destroy_cb_rec[0].closure = (XtPointer) Ctext;
1161 dnd_destroy_cb_rec[1].callback = NULL;
1162 dnd_destroy_cb_rec[1].closure = NULL;
1165 DtDndDragStart(wid, &x_event,
1167 DtDND_BUFFER_TRANSFER :
1168 DtDND_FILENAME_TRANSFER), numItems,
1169 XmDROP_COPY, dnd_convert_cb_rec,
1170 dnd_destroy_cb_rec, NULL, 0);
1175 return numItems ? Qt : Qnil;
1182 x_cde_transfer_callback(Widget widget, XtPointer clientData, XtPointer callData)
1184 char *filePath, *hurl;
1185 int ii, enqueue = 1;
1186 Lisp_Object frame = Qnil;
1187 Lisp_Object l_type = Qnil;
1188 Lisp_Object l_data = Qnil;
1189 DtDndTransferCallbackStruct *transferInfo = NULL;
1190 struct gcpro gcpro1, gcpro2, gcpro3;
1193 this needs to be changed to the new protocol:
1194 - we need the button, modifier and pointer states to create a
1195 correct misc_user_event
1196 - the data must be converted to the new format (URL/MIME)
1200 transferInfo = (DtDndTransferCallbackStruct *) callData;
1201 if (transferInfo == NULL)
1204 GCPRO3(frame, l_type, l_data);
1206 frame = make_frame((struct frame *)clientData);
1208 if (transferInfo->dropData->protocol == DtDND_FILENAME_TRANSFER) {
1209 l_type = Qdragdrop_URL;
1211 for (ii = 0; ii < transferInfo->dropData->numItems; ii++) {
1212 filePath = transferInfo->dropData->data.files[ii];
1213 hurl = dnd_url_hexify_string((char *)filePath, "file:");
1214 /* #### Mule-izing required */
1215 l_data = Fcons(make_string((Bufbyte *) hurl,
1216 strlen(hurl)), l_data);
1219 } else if (transferInfo->dropData->protocol == DtDND_BUFFER_TRANSFER) {
1220 int speccount = specpdl_depth();
1222 /* Problem: all buffers a treated as text/plain!!!
1223 Solution: Also support DtDND_TEXT_TRANSFER
1224 perhaps implementation of the Motif protocol
1225 (which is the base of CDE) will clear this */
1226 l_type = Qdragdrop_MIME;
1227 record_unwind_protect(abort_current_drag, Qnil);
1229 for (ii = 0; ii < transferInfo->dropData->numItems; ii++) {
1230 /* let us forget this name thing for now... */
1231 /* filePath = transferInfo->dropData->data.buffers[ii].name;
1232 path = (filePath == NULL) ? Qnil
1233 : make_string ((Bufbyte *)filePath, strlen (filePath)); */
1234 /* what, if the data is no text, and how can I tell it? */
1238 (make_string((Bufbyte *) "text/plain", 10)),
1239 make_string((Bufbyte *) "8bit", 4),
1240 make_string((Bufbyte *) transferInfo->
1241 dropData->data.buffers[ii].bp,
1242 transferInfo->dropData->data.
1243 buffers[ii].size)), l_data);
1246 unbind_to(speccount, Qnil);
1247 } else /* the other cases: NOOP_TRANSFER */
1250 /* The Problem: no button and mods from CDE... */
1252 enqueue_misc_user_event_pos(frame, Qdragdrop_drop_dispatch,
1253 Fcons(l_type, l_data),
1254 0 /* this is the button */ ,
1255 0 /* these are the mods */ ,
1256 transferInfo->x, transferInfo->y);
1261 #endif /* HAVE_CDE */
1264 /************************************************************************/
1265 /* widget creation */
1266 /************************************************************************/
1268 /* The widget hierarchy is
1270 argv[0] shell container FRAME-NAME
1271 ApplicationShell EmacsShell EmacsManager EmacsFrame
1273 We accept geometry specs in this order:
1275 *FRAME-NAME.geometry
1276 *EmacsFrame.geometry
1279 Other possibilities for widget hierarchies might be
1281 argv[0] frame container FRAME-NAME
1282 ApplicationShell EmacsShell EmacsManager EmacsFrame
1284 argv[0] FRAME-NAME container FRAME-NAME
1285 ApplicationShell EmacsShell EmacsManager EmacsFrame
1287 argv[0] FRAME-NAME container emacsTextPane
1288 ApplicationShell EmacsShell EmacsManager EmacsFrame
1290 #ifdef EXTERNAL_WIDGET
1291 The ExternalShell widget is simply a replacement for the Shell widget
1292 which is able to deal with using an externally-supplied window instead
1293 of always creating its own.
1298 #ifdef EXTERNAL_WIDGET
1300 static int is_valid_window(Window w, struct device *d)
1302 XWindowAttributes xwa;
1303 Display *dpy = DEVICE_X_DISPLAY(d);
1305 expect_x_error(dpy);
1306 XGetWindowAttributes(dpy, w, &xwa);
1307 return !x_error_occurred_p(dpy);
1310 #endif /* EXTERNAL_WIDGET */
1312 /* This sends a synthetic mouse-motion event to the frame, if the mouse
1313 is over the frame. This ensures that the cursor gets set properly
1314 before the user moves the mouse for the first time. */
1316 static void x_send_synthetic_mouse_event(struct frame *f)
1318 /* #### write this function. */
1321 static int first_x_frame_p(struct frame *f)
1323 Lisp_Object rest = DEVICE_FRAME_LIST(XDEVICE(f->device));
1324 while (!NILP(rest) &&
1325 (f == XFRAME(XCAR(rest)) || !FRAME_X_P(XFRAME(XCAR(rest)))))
1330 /* Figure out what size the EmacsFrame widget should initially be,
1331 and set it. Should be called after the default font has been
1332 determined but before the widget has been realized. */
1334 static void x_initialize_frame_size(struct frame *f)
1336 /* Geometry of the AppShell */
1340 unsigned int app_w = 0;
1341 unsigned int app_h = 0;
1343 /* Geometry of the EmacsFrame */
1344 int frame_flags = 0;
1347 unsigned int frame_w = 0;
1348 unsigned int frame_h = 0;
1350 /* Hairily merged geometry */
1353 unsigned int w = 80;
1354 unsigned int h = 40;
1357 char *geom = 0, *ew_geom = 0;
1358 Boolean iconic_p = False, ew_iconic_p = False;
1360 Widget wmshell = FRAME_X_SHELL_WIDGET(f);
1361 /* #### This may not be an ApplicationShell any more, with the 'popup
1363 Widget app_shell = XtParent(wmshell);
1364 Widget ew = FRAME_X_TEXT_WIDGET(f);
1366 /* set the position of the frame's root window now. When the
1367 frame was created, the position was initialized to (0,0). */
1369 struct window *win = XWINDOW(f->root_window);
1371 WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f)
1372 + FRAME_LEFT_GUTTER_BOUNDS(f);
1373 WINDOW_TOP(win) = FRAME_TOP_BORDER_END(f)
1374 + FRAME_TOP_GUTTER_BOUNDS(f);
1376 if (!NILP(f->minibuffer_window)) {
1377 win = XWINDOW(f->minibuffer_window);
1378 WINDOW_LEFT(win) = FRAME_LEFT_BORDER_END(f)
1379 + FRAME_LEFT_GUTTER_BOUNDS(f);
1383 #ifdef EXTERNAL_WIDGET
1384 /* If we're an external widget, then the size of the frame is predetermined
1385 (by the client) and is not our decision to make. */
1386 if (FRAME_X_EXTERNAL_WINDOW_P(f))
1391 /* #### this junk has not been tested; therefore it's
1392 probably wrong. Doesn't really matter at this point because
1393 currently all frames are either top-level or external widgets. */
1395 /* If we're not our own top-level window, then we shouldn't go messing around
1396 with top-level shells or "Emacs.geometry" or any such stuff. Therefore,
1397 we do as follows to determine the size of the frame:
1399 1) If a value for the frame's "geometry" resource was specified, then
1400 use it. (This specifies a size in characters.)
1401 2) Else, if the "width" and "height" resources were specified, then
1402 leave them alone. (This is a value in pixels. Sorry, we can't break
1403 Xt conventions here.)
1404 3) Else, assume a size of 64x12. (This is somewhat arbitrary, but
1405 it's unlikely that a size of 80x40 is desirable because we're probably
1406 inside of a dialog box.)
1408 Set the widget's x, y, height, and width as determined. Don't set the
1409 top-level container widget, because we don't necessarily know what it
1410 is. (Assume it is smart and pays attention to our values.)
1413 if (!FRAME_X_TOP_LEVEL_FRAME_P(f)) {
1414 Xt_GET_VALUE(ew, XtNgeometry, &ew_geom);
1416 frame_flags = XParseGeometry(ew_geom,
1418 &frame_w, &frame_h);
1419 if (!(frame_flags & (WidthValue | HeightValue))) {
1421 XtSetArg(al[0], XtNwidth, &frame_w);
1422 XtSetArg(al[1], XtNheight, &frame_h);
1423 XtGetValues(ew, al, 2);
1424 if (!frame_w && !frame_h) {
1427 frame_flags |= WidthValue | HeightValue;
1430 if (frame_flags & (WidthValue | HeightValue))
1431 EmacsFrameSetCharSize(ew, frame_w, frame_h);
1432 if (frame_flags & (XValue | YValue)) {
1434 XtSetArg(al[0], XtNwidth, &frame_w);
1435 XtSetArg(al[1], XtNheight, &frame_h);
1436 XtGetValues(ew, al, 2);
1438 if (frame_flags & XNegative)
1440 if (frame_flags & YNegative)
1443 XtSetArg(al[0], XtNx, frame_x);
1444 XtSetArg(al[1], XtNy, frame_y);
1445 XtSetValues(ew, al, 2);
1451 /* OK, we're a top-level shell. */
1453 if (!XtIsWMShell(wmshell))
1456 /* If the EmacsFrame doesn't have a geometry but the shell does,
1457 treat that as the geometry of the frame.
1458 (Is this bogus? I'm not sure.) */
1460 Xt_GET_VALUE(ew, XtNgeometry, &ew_geom);
1462 Xt_GET_VALUE(wmshell, XtNgeometry, &geom);
1465 Xt_SET_VALUE(ew, XtNgeometry, ew_geom);
1469 /* If the Shell is iconic, then the EmacsFrame is iconic.
1470 (Is this bogus? I'm not sure.) */
1471 Xt_GET_VALUE(ew, XtNiconic, &ew_iconic_p);
1473 Xt_GET_VALUE(wmshell, XtNiconic, &iconic_p);
1475 ew_iconic_p = iconic_p;
1476 Xt_SET_VALUE(ew, XtNiconic, iconic_p);
1480 Xt_GET_VALUE(app_shell, XtNgeometry, &geom);
1483 XParseGeometry(geom, &app_x, &app_y, &app_w, &app_h);
1486 frame_flags = XParseGeometry(ew_geom,
1488 &frame_w, &frame_h);
1490 if (first_x_frame_p(f)) {
1491 /* If this is the first frame created:
1492 ====================================
1494 - Use the ApplicationShell's size/position, if specified.
1495 (This is "Emacs.geometry", or the "-geometry" command line arg.)
1496 - Else use the EmacsFrame's size/position.
1497 (This is "*FRAME-NAME.geometry")
1499 - If the AppShell is iconic, the frame should be iconic.
1501 AppShell comes first so that -geometry always applies to the first
1502 frame created, even if there is an "every frame" entry in the
1505 if (app_flags & (XValue | YValue)) {
1510 (XValue | YValue | XNegative | YNegative));
1511 } else if (frame_flags & (XValue | YValue)) {
1516 (XValue | YValue | XNegative | YNegative));
1519 if (app_flags & (WidthValue | HeightValue)) {
1522 flags |= (app_flags & (WidthValue | HeightValue));
1523 } else if (frame_flags & (WidthValue | HeightValue)) {
1526 flags |= (frame_flags & (WidthValue | HeightValue));
1529 /* If the AppShell is iconic, then the EmacsFrame is iconic. */
1531 Xt_GET_VALUE(app_shell, XtNiconic, &iconic_p);
1533 ew_iconic_p = iconic_p;
1534 Xt_SET_VALUE(ew, XtNiconic, iconic_p);
1538 /* If this is not the first frame created:
1539 ========================================
1541 - use the EmacsFrame's size/position if specified
1542 - Otherwise, use the ApplicationShell's size, but not position.
1544 So that means that one can specify the position of the first frame
1545 with "Emacs.geometry" or `-geometry'; but can only specify the
1546 position of subsequent frames with "*FRAME-NAME.geometry".
1548 AppShell comes second so that -geometry does not apply to subsequent
1549 frames when there is an "every frame" entry in the resource db,
1550 but does apply to the first frame.
1552 if (frame_flags & (XValue | YValue)) {
1557 (XValue | YValue | XNegative | YNegative));
1560 if (frame_flags & (WidthValue | HeightValue)) {
1563 flags |= (frame_flags & (WidthValue | HeightValue));
1564 } else if (app_flags & (WidthValue | HeightValue)) {
1567 flags |= (app_flags & (WidthValue | HeightValue));
1571 x_set_initial_frame_size(f, flags, x, y, w, h);
1574 static void x_get_layout_sizes(struct frame *f, Dimension * topbreadth)
1578 /* compute height of all top-area widgets */
1579 for (i = 0, *topbreadth = 0; i < FRAME_X_NUM_TOP_WIDGETS(f); i++) {
1580 Widget wid = FRAME_X_TOP_WIDGETS(f)[i];
1581 if (wid && XtIsManaged(wid))
1583 wid->core.height + 2 * wid->core.border_width;
1588 x_layout_widgets(Widget w, XtPointer client_data, XtPointer call_data)
1590 struct frame *f = (struct frame *)client_data;
1591 EmacsManagerResizeStruct *emst = (EmacsManagerResizeStruct *) call_data;
1592 Dimension width = emst->width;
1593 Dimension height = emst->height;
1594 Widget text = FRAME_X_TEXT_WIDGET(f);
1595 Dimension textbord = text->core.border_width;
1596 Dimension topbreadth;
1597 Position text_x = 0, text_y = 0;
1600 x_get_layout_sizes(f, &topbreadth);
1602 /* first the menubar and psheets ... */
1603 for (i = 0; i < FRAME_X_NUM_TOP_WIDGETS(f); i++) {
1604 Widget wid = FRAME_X_TOP_WIDGETS(f)[i];
1605 if (wid && XtIsManaged(wid)) {
1606 Dimension bord = wid->core.border_width;
1607 XtConfigureWidget(wid, 0, text_y,
1608 width - 2 * bord, wid->core.height,
1610 text_y += wid->core.height + 2 * bord;
1614 #ifdef HAVE_SCROLLBARS
1615 f->scrollbar_y_offset = topbreadth + textbord;
1618 /* finally the text area */
1620 Dimension nw = width - 2 * textbord;
1621 Dimension nh = height - text_y - 2 * textbord;
1623 if (nh != f->pixheight || nw != f->pixwidth)
1624 MARK_FRAME_SIZE_SLIPPED(f);
1625 XtConfigureWidget(text, text_x, text_y, nw, nh, textbord);
1630 x_do_query_geometry(Widget w, XtPointer client_data, XtPointer call_data)
1632 struct frame *f = (struct frame *)client_data;
1633 EmacsManagerQueryGeometryStruct *emst =
1634 (EmacsManagerQueryGeometryStruct *) call_data;
1635 Widget text = FRAME_X_TEXT_WIDGET(f);
1636 Dimension textbord = text->core.border_width;
1637 Dimension topbreadth;
1638 XtWidgetGeometry req, repl;
1639 int mask = emst->request_mode & (CWWidth | CWHeight);
1641 x_get_layout_sizes(f, &topbreadth);
1643 /* Strip away menubar from suggested size, and ask the text widget
1644 what size it wants to be. */
1645 req.request_mode = mask;
1647 req.width = emst->proposed_width - 2 * textbord;
1648 if (mask & CWHeight)
1649 req.height = emst->proposed_height - topbreadth - 2 * textbord;
1650 XtQueryGeometry(text, &req, &repl);
1652 /* Now add the menubar back again */
1653 emst->proposed_width = repl.width + 2 * textbord;
1654 emst->proposed_height = repl.height + topbreadth + 2 * textbord;
1657 /* Creates the widgets for a frame.
1658 lisp_window_id is a Lisp description of an X window or Xt
1660 parent is a frame to use as the parent.
1661 overridep if non-nil says to set the override-redirect setting.
1663 This function does not create or map the windows. (That is
1664 done by x_popup_frame().)
1667 x_create_widgets(struct frame *f, Lisp_Object lisp_window_id,
1668 Lisp_Object parent, Lisp_Object overridep)
1670 struct device *d = XDEVICE(f->device);
1671 Visual *visual = DEVICE_X_VISUAL(d);
1672 int depth = DEVICE_X_DEPTH(d);
1673 Colormap cmap = DEVICE_X_COLORMAP(d);
1674 #ifdef EXTERNAL_WIDGET
1675 Window window_id = 0;
1680 Widget text, container, shell;
1681 Widget parentwid = 0;
1682 #ifdef HAVE_MENUBARS
1683 int menubar_visible;
1687 if (STRINGP(f->name))
1688 LISP_STRING_TO_EXTERNAL(f->name, name, Qctext);
1692 /* The widget hierarchy is
1694 argv[0] shell pane FRAME-NAME
1695 ApplicationShell EmacsShell EmacsManager EmacsFrame
1697 (the type of the shell is ExternalShell if this frame is running
1698 in another client's window)
1700 However the EmacsShell widget has WM_CLASS of FRAME-NAME/Emacs.
1701 Normally such shells have name/class shellname/appclass, which in this
1702 case would be "shell/Emacs" instead of "frame-name/Emacs". We could
1703 also get around this by naming the shell "frame-name", but that would
1704 be confusing because the text area (the EmacsFrame widget inferior of
1705 the shell) is also called that. So we just set the WM_CLASS property.
1708 #ifndef EXTERNAL_WIDGET
1709 if (!NILP(lisp_window_id))
1711 ("support for external widgets was not enabled at compile-time");
1713 if (!NILP(lisp_window_id)) {
1716 CHECK_STRING(lisp_window_id);
1717 string = (char *)XSTRING_DATA(lisp_window_id);
1718 if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X'))
1719 sscanf(string + 2, "%lxu", &window_id);
1721 else if (string[0] == 'w') {
1722 sscanf(string + 1, "%x", &parent_widget);
1724 window_id = XtWindow(parent_widget);
1728 sscanf(string, "%lu", &window_id);
1729 if (!is_valid_window(window_id, d))
1730 error("Invalid window %lu", (unsigned long)window_id);
1731 FRAME_X_EXTERNAL_WINDOW_P(f) = 1;
1733 #endif /* EXTERNAL_WIDGET */
1734 FRAME_X_TOP_LEVEL_FRAME_P(f) = 1;
1737 XtSetArg(al[ac], XtNallowShellResize, True);
1739 #ifdef LWLIB_USES_MOTIF
1740 /* Motif sucks beans. Without this in here, it will delete the window
1741 out from under us when it receives a WM_DESTROY_WINDOW message
1743 XtSetArg(al[ac], XmNdeleteResponse, XmDO_NOTHING);
1747 #ifdef EXTERNAL_WIDGET
1749 XtSetArg(al[ac], XtNwindow, window_id);
1752 #endif /* EXTERNAL_WIDGET */
1754 XtSetArg(al[ac], XtNinput, True);
1756 XtSetArg(al[ac], XtNminWidthCells, 10);
1758 XtSetArg(al[ac], XtNminHeightCells, 1);
1760 XtSetArg(al[ac], XtNvisual, visual);
1762 XtSetArg(al[ac], XtNdepth, depth);
1764 XtSetArg(al[ac], XtNcolormap, cmap);
1768 if (!NILP(overridep)) {
1769 XtSetArg(al[ac], XtNoverrideRedirect, True);
1773 /* #### maybe we should check for FRAMEP instead? */
1774 if (!NILP(parent)) {
1775 parentwid = FRAME_X_SHELL_WIDGET(XFRAME(parent));
1776 XtSetArg(al[ac], XtNtransientFor, parentwid);
1780 shell = XtCreatePopupShell("shell", (
1781 #ifdef EXTERNAL_WIDGET
1783 externalShellWidgetClass :
1786 transientEmacsShellWidgetClass
1788 topLevelEmacsShellWidgetClass),
1789 parentwid ? parentwid :
1790 DEVICE_XT_APP_SHELL(d), al, ac);
1791 FRAME_X_SHELL_WIDGET(f) = shell;
1792 maybe_set_frame_title_format(shell);
1794 /* Create the manager widget */
1796 XtSetArg(al[ac], XtNvisual, visual);
1798 XtSetArg(al[ac], XtNdepth, depth);
1800 XtSetArg(al[ac], XtNcolormap, cmap);
1803 container = XtCreateWidget("container",
1804 emacsManagerWidgetClass, shell, al, ac);
1805 FRAME_X_CONTAINER_WIDGET(f) = container;
1806 XtAddCallback(container, XtNresizeCallback, x_layout_widgets,
1808 XtAddCallback(container, XtNqueryGeometryCallback, x_do_query_geometry,
1811 /* Create the text area */
1813 XtSetArg(al[ac], XtNvisual, visual);
1815 XtSetArg(al[ac], XtNdepth, depth);
1817 XtSetArg(al[ac], XtNcolormap, cmap);
1819 XtSetArg(al[ac], XtNborderWidth, 0);
1820 ac++; /* should this be settable? */
1821 XtSetArg(al[ac], XtNemacsFrame, f);
1823 text = XtCreateWidget(name, emacsFrameClass, container, al, ac);
1824 FRAME_X_TEXT_WIDGET(f) = text;
1826 #ifdef HAVE_MENUBARS
1827 /* Create the initial menubar widget. */
1828 menubar_visible = x_initialize_frame_menubar(f);
1829 FRAME_X_TOP_WIDGETS(f)[0] = menubar = FRAME_X_MENUBAR_WIDGET(f);
1830 FRAME_X_NUM_TOP_WIDGETS(f) = 1;
1832 if (menubar_visible)
1833 XtManageChild(menubar);
1834 #endif /* HAVE_MENUBARS */
1835 XtManageChild(text);
1836 XtManageChild(container);
1839 /* We used to call XtPopup() in x_popup_frame, but that doesn't give
1840 you control over whether the widget is initially mapped or not
1841 because XtPopup() makes an unconditional call to XMapRaised().
1842 Boy, those Xt designers were clever.
1844 When we first removed it we only kept the XtRealizeWidget call in
1845 XtPopup. For everything except HP's that was enough. For HP's,
1846 though, the failure to call the popup callbacks resulted in XEmacs
1847 not accepting any input. Bizarre but true. Stupid but true.
1849 So, in case there are any other gotchas floating out there along
1850 the same lines I've duplicated the majority of XtPopup here. It
1851 assumes no grabs and that the widget is not already popped up, both
1852 valid assumptions for the one place this is called from. */
1853 static void xemacs_XtPopup(Widget widget)
1855 ShellWidget shell_widget = (ShellWidget) widget;
1856 XtGrabKind call_data = XtGrabNone;
1858 XtCallCallbacks(widget, XtNpopupCallback, (XtPointer) & call_data);
1860 shell_widget->shell.popped_up = TRUE;
1861 shell_widget->shell.grab_kind = XtGrabNone;
1862 shell_widget->shell.spring_loaded = False;
1864 if (shell_widget->shell.create_popup_child_proc != NULL)
1865 (*(shell_widget->shell.create_popup_child_proc)) (widget);
1867 /* The XtSetValues below are not in XtPopup menu. We just want to
1868 make absolutely sure... */
1869 Xt_SET_VALUE(widget, XtNmappedWhenManaged, False);
1870 XtRealizeWidget(widget);
1871 Xt_SET_VALUE(widget, XtNmappedWhenManaged, True);
1874 /* create the windows for the specified frame and display them.
1875 Note that the widgets have already been created, and any
1876 necessary geometry calculations have already been done. */
1877 static void x_popup_frame(struct frame *f)
1879 Widget shell_widget = FRAME_X_SHELL_WIDGET(f);
1880 Widget frame_widget = FRAME_X_TEXT_WIDGET(f);
1881 struct device *d = XDEVICE(FRAME_DEVICE(f));
1883 /* Before mapping the window, make sure that the WMShell's notion of
1884 whether it should be iconified is synchronized with the EmacsFrame's
1887 if (FRAME_X_TOP_LEVEL_FRAME_P(f))
1888 x_wm_set_shell_iconic_p(shell_widget,
1889 ((EmacsFrame) frame_widget)
1890 ->emacs_frame.iconic);
1892 xemacs_XtPopup(shell_widget);
1894 if (!((EmacsFrame) frame_widget)->emacs_frame.initially_unmapped)
1895 XtMapWidget(shell_widget);
1897 /* We may have set f->visible to 1 in x_init_frame(), so undo
1899 FRAME_X_TOTALLY_VISIBLE_P(f) = 0;
1903 #ifdef EXTERNAL_WIDGET
1904 if (FRAME_X_EXTERNAL_WINDOW_P(f))
1905 ExternalShellReady(shell_widget, XtWindow(frame_widget),
1909 if (FRAME_X_TOP_LEVEL_FRAME_P(f)) {
1910 /* tell the window manager about us. */
1911 x_wm_store_class_hints(shell_widget, XtName(frame_widget));
1913 #ifndef HAVE_WMCOMMAND
1914 x_wm_maybe_store_wm_command(f);
1915 #endif /* HAVE_WMCOMMAND */
1917 x_wm_hack_wm_protocols(shell_widget);
1921 #endif /* HAVE_XIM */
1924 /* Allow XEmacs to respond to EditRes requests. See the O'Reilly Xt */
1925 /* Intrinsics Programming Manual, Motif Edition, Aug 1993, Sect 14.14, */
1927 XtAddEventHandler(shell_widget, /* the shell widget in question */
1928 (EventMask) NoEventMask, /* OR with existing mask */
1929 True, /* called on non-maskable events? */
1930 (XtEventHandler) _XEditResCheckMessages, /* the handler */
1932 #endif /* HACK_EDITRES */
1936 XtCallbackRec dnd_transfer_cb_rec[2];
1938 dnd_transfer_cb_rec[0].callback = x_cde_transfer_callback;
1939 dnd_transfer_cb_rec[0].closure = (XtPointer) f;
1940 dnd_transfer_cb_rec[1].callback = NULL;
1941 dnd_transfer_cb_rec[1].closure = NULL;
1943 DtDndVaDropRegister(FRAME_X_TEXT_WIDGET(f),
1944 DtDND_FILENAME_TRANSFER |
1945 DtDND_BUFFER_TRANSFER, XmDROP_COPY,
1946 dnd_transfer_cb_rec, DtNtextIsBuffer, True,
1947 DtNregisterChildren, True,
1948 DtNpreserveRegistration, False, NULL);
1950 #endif /* HAVE_CDE */
1952 /* Do a stupid property change to force the server to generate a
1953 propertyNotify event so that the event_stream server timestamp will
1954 be initialized to something relevant to the time we created the window.
1956 XChangeProperty(XtDisplay(frame_widget), XtWindow(frame_widget),
1957 DEVICE_XATOM_WM_PROTOCOLS(d), XA_ATOM, 32,
1958 PropModeAppend, (unsigned char *)NULL, 0);
1960 x_send_synthetic_mouse_event(f);
1963 static void allocate_x_frame_struct(struct frame *f)
1965 /* zero out all slots. */
1966 f->frame_data = xnew_and_zero(struct x_frame);
1968 /* yeah, except the lisp ones */
1969 FRAME_X_ICON_PIXMAP(f) = Qnil;
1970 FRAME_X_ICON_PIXMAP_MASK(f) = Qnil;
1973 /************************************************************************/
1974 /* Lisp functions */
1975 /************************************************************************/
1977 static void x_init_frame_1(struct frame *f, Lisp_Object props)
1979 /* This function can GC */
1980 Lisp_Object device = FRAME_DEVICE(f);
1981 Lisp_Object lisp_window_id = Fplist_get(props, Qwindow_id, Qnil);
1982 Lisp_Object popup = Fplist_get(props, Qpopup, Qnil);
1983 Lisp_Object overridep = Fplist_get (props, Qoverride_redirect, Qnil);
1987 popup = Fselected_frame(device);
1988 CHECK_LIVE_FRAME(popup);
1989 if (!EQ(device, FRAME_DEVICE(XFRAME(popup))))
1990 signal_simple_error_2
1991 ("Parent must be on same device as frame", device,
1996 * Previously we set this only if NILP (DEVICE_SELECTED_FRAME (d))
1997 * to make sure that messages were displayed as soon as possible
1998 * if we're creating the first frame on a device. But it is
1999 * better to just set this all the time, so that when a new frame
2000 * is created that covers the selected frame, echo area status
2001 * messages can still be seen. f->visible is reset later if the
2002 * initially-unmapped property is found to be non-nil in the
2007 allocate_x_frame_struct(f);
2008 x_create_widgets(f, lisp_window_id, popup, overridep);
2011 static void x_init_frame_2(struct frame *f, Lisp_Object props)
2013 /* Set up the values of the widget/frame. A case could be made for putting
2014 this inside of the widget's initialize method. */
2016 update_frame_face_values(f);
2017 x_initialize_frame_size(f);
2019 * update_frame_title() can't be done here, because some of the
2020 * modeline specs depend on the frame's device having a selected
2021 * frame, and that may not have been set up yet. The redisplay
2022 * will update the frame title anyway, so nothing is lost.
2024 * It turns out it gives problems with FVWMs name based mapping.
2025 * We'll just need to be careful in the modeline specs.
2027 update_frame_title(f);
2030 static void x_init_frame_3(struct frame *f)
2032 /* Pop up the frame. */
2037 static void x_mark_frame(struct frame *f)
2039 mark_object(FRAME_X_ICON_PIXMAP(f));
2040 mark_object(FRAME_X_ICON_PIXMAP_MASK(f));
2043 static void x_set_frame_icon(struct frame *f)
2045 Pixmap x_pixmap, x_mask;
2047 if (IMAGE_INSTANCEP(f->icon)
2048 && IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(f->icon))) {
2049 x_pixmap = XIMAGE_INSTANCE_X_PIXMAP(f->icon);
2050 x_mask = XIMAGE_INSTANCE_X_MASK(f->icon);
2056 /* Store the X data into the widget. */
2059 XtSetArg(al[0], XtNiconPixmap, x_pixmap);
2060 XtSetArg(al[1], XtNiconMask, x_mask);
2061 XtSetValues(FRAME_X_SHELL_WIDGET(f), al, 2);
2065 static void x_set_frame_pointer(struct frame *f)
2067 XDefineCursor(XtDisplay(FRAME_X_TEXT_WIDGET(f)),
2068 XtWindow(FRAME_X_TEXT_WIDGET(f)),
2069 XIMAGE_INSTANCE_X_CURSOR(f->pointer));
2070 XSync(XtDisplay(FRAME_X_TEXT_WIDGET(f)), 0);
2073 static Lisp_Object x_get_frame_parent(struct frame *f)
2075 Widget parentwid = 0;
2077 Xt_GET_VALUE(FRAME_X_SHELL_WIDGET(f), XtNtransientFor, &parentwid);
2078 /* find the frame whose wid is parentwid */
2080 Lisp_Object frmcons;
2081 DEVICE_FRAME_LOOP(frmcons, XDEVICE(FRAME_DEVICE(f))) {
2082 Lisp_Object frame = XCAR(frmcons);
2083 if (FRAME_X_SHELL_WIDGET(XFRAME(frame)) == parentwid)
2090 DEFUN("x-window-id", Fx_window_id, 0, 1, 0, /*
2091 Get the ID of the X11 window.
2092 This gives us a chance to manipulate the Emacs window from within a
2093 different program. Since the ID is an unsigned long, we return it as
2099 struct frame *f = decode_x_frame(frame);
2101 sprintf(str, "%lu", XtWindow(FRAME_X_TEXT_WIDGET(f)));
2102 return build_string(str);
2105 /************************************************************************/
2106 /* manipulating the X window */
2107 /************************************************************************/
2109 static void x_set_frame_position(struct frame *f, int xoff, int yoff)
2111 Widget w = FRAME_X_SHELL_WIDGET(f);
2112 Display *dpy = XtDisplay(w);
2113 Dimension frame_w = DisplayWidth(dpy, DefaultScreen(dpy));
2114 Dimension frame_h = DisplayHeight(dpy, DefaultScreen(dpy));
2115 Dimension shell_w, shell_h, shell_bord;
2119 XtSetArg(al[0], XtNwidth, &shell_w);
2120 XtSetArg(al[1], XtNheight, &shell_h);
2121 XtSetArg(al[2], XtNborderWidth, &shell_bord);
2122 XtGetValues(w, al, 3);
2125 xoff >= 0 && yoff >= 0 ? NorthWestGravity :
2126 xoff >= 0 ? SouthWestGravity :
2127 yoff >= 0 ? NorthEastGravity : SouthEastGravity;
2129 xoff += frame_w - shell_w - 2 * shell_bord;
2131 yoff += frame_h - shell_h - 2 * shell_bord;
2133 /* Update the hints so that, if this window is currently iconified, it will
2134 come back at the right place. We can't look at s->visible to determine
2135 whether it is iconified because it might not be up-to-date yet (the queue
2136 might not be processed). */
2137 XtSetArg(al[0], XtNwinGravity, win_gravity);
2138 XtSetArg(al[1], XtNx, xoff);
2139 XtSetArg(al[2], XtNy, yoff);
2140 XtSetValues(w, al, 3);
2142 /* Sometimes you will find that
2144 (set-frame-position (selected-frame) -50 -50)
2146 doesn't put the frame where you expect it to: i.e. it's closer to
2147 the lower-right corner than it should be, and it appears that the
2148 size of the WM decorations was not taken into account. This is
2149 *not* a problem with this function. Both mwm and twm have bugs
2150 in handling this situation. (mwm ignores the window gravity and
2151 always assumes NorthWest, except the first time you map the
2152 window; twm gets things almost right, but forgets to account for
2153 the border width of the top-level window.) This function does
2154 what it's supposed to according to the ICCCM, and I'm not about
2155 to hack around window-manager bugs. */
2158 /* This is not necessary under either mwm or twm */
2159 x_wm_mark_shell_position_user_specified(w);
2163 /* Call this to change the size of frame S's x-window. */
2165 static void x_set_frame_size(struct frame *f, int cols, int rows)
2167 EmacsFrameSetCharSize(FRAME_X_TEXT_WIDGET(f), cols, rows);
2169 /* this is not correct. x_set_frame_size() is called from
2170 Fset_frame_size(), which may or may not have been called
2171 by the user (e.g. update_EmacsFrame() calls it when the font
2172 changes). For now, don't bother with getting this right. */
2173 x_wm_mark_shell_size_user_specified(FRAME_X_SHELL_WIDGET(f));
2177 static void x_set_mouse_position(struct window *w, int x, int y)
2179 struct frame *f = XFRAME(w->frame);
2181 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2182 XWarpPointer(display, None, XtWindow(FRAME_X_TEXT_WIDGET(f)),
2183 0, 0, 0, 0, w->pixel_left + x, w->pixel_top + y);
2187 x_get_mouse_position(struct device *d, Lisp_Object * frame, int *x, int *y)
2189 Display *display = DEVICE_X_DISPLAY(d);
2190 Window child_window;
2195 unsigned int keys_and_buttons;
2198 if (XQueryPointer(display, RootWindow(display, DefaultScreen(display)),
2199 &root_window, &child_window, &root_x, &root_y,
2200 &win_x, &win_y, &keys_and_buttons) == False)
2203 if (child_window == None)
2204 return 0; /* not over any window. */
2208 if (XTranslateCoordinates
2209 (display, root_window, win, root_x, root_y, &win_x, &win_y,
2210 &child_window) == False)
2214 if (child_window == None)
2218 /* At this point, win is the innermost window containing the pointer
2219 and win_x and win_y are the coordinates of that window. */
2220 f = x_any_window_to_frame(d, win);
2223 XSETFRAME(*frame, f);
2225 if (XTranslateCoordinates(display, win,
2226 XtWindow(FRAME_X_TEXT_WIDGET(f)),
2227 win_x, win_y, x, y, &child_window) == False)
2234 static void x_cant_notify_wm_error(void)
2236 error("Can't notify window manager of iconification.");
2239 /* Raise frame F. */
2240 static void x_raise_frame_1(struct frame *f, int force)
2242 if (FRAME_VISIBLE_P(f) || force) {
2243 Widget bottom_dialog;
2246 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2247 Window emacs_window = XtWindow(FRAME_X_SHELL_WIDGET(f));
2249 /* first raises all the dialog boxes, then put emacs just below the
2250 * bottom most dialog box */
2251 bottom_dialog = lw_raise_all_pop_up_widgets();
2252 if (bottom_dialog && XtWindow(bottom_dialog)) {
2253 xwc.sibling = XtWindow(bottom_dialog);
2254 xwc.stack_mode = Below;
2255 flags = CWSibling | CWStackMode;
2257 xwc.stack_mode = Above;
2258 flags = CWStackMode;
2261 if (!XReconfigureWMWindow(display, emacs_window,
2262 DefaultScreen(display), flags, &xwc))
2263 x_cant_notify_wm_error();
2267 static void x_raise_frame(struct frame *f)
2269 x_raise_frame_1(f, 1);
2272 /* Lower frame F. */
2273 static void x_lower_frame(struct frame *f)
2275 if (FRAME_VISIBLE_P(f)) {
2276 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2278 unsigned int flags = CWStackMode;
2280 xwc.stack_mode = Below;
2281 if (!XReconfigureWMWindow
2282 (display, XtWindow(FRAME_X_SHELL_WIDGET(f)),
2283 DefaultScreen(display), flags, &xwc))
2284 x_cant_notify_wm_error();
2288 static void x_enable_frame(struct frame *f)
2290 XtSetSensitive(FRAME_X_SHELL_WIDGET(f), True);
2293 static void x_disable_frame(struct frame *f)
2295 XtSetSensitive(FRAME_X_SHELL_WIDGET(f), False);
2298 /* Change from withdrawn state to mapped state. */
2299 static void x_make_frame_visible(struct frame *f)
2301 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2303 if (!FRAME_VISIBLE_P(f))
2304 XMapRaised(display, XtWindow(FRAME_X_SHELL_WIDGET(f)));
2306 x_raise_frame_1(f, 0);
2309 /* Change from mapped state to withdrawn state. */
2310 static void x_make_frame_invisible(struct frame *f)
2312 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2314 if (!FRAME_VISIBLE_P(f))
2317 if (!XWithdrawWindow(display,
2318 XtWindow(FRAME_X_SHELL_WIDGET(f)),
2319 DefaultScreen(display)))
2320 x_cant_notify_wm_error();
2323 static int x_frame_visible_p(struct frame *f)
2326 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2327 XWindowAttributes xwa;
2331 This is bad, very bad :-(
2332 It is not compatible with our tristate visible and
2333 it should never ever change the visibility for us, this leads to
2334 the frame-freeze problem under fvwm because with the pager
2336 Mappedness != Viewability != Visibility != Emacs f->visible
2338 This first unequalness is the reason for the frame freezing problem
2339 under fvwm (it happens when the frame is another fvwm-page)
2341 The second unequalness happen when it is on the same fvwm-page
2342 but in an invisible part of the visible screen.
2344 For now we just return the XEmacs internal value --- which might not be up
2345 to date. Is that a problem? ---. Otherwise we should
2346 use async visibility like in standard Emacs.
2349 if (!XGetWindowAttributes(display,
2350 XtWindow(FRAME_X_SHELL_WIDGET(f)), &xwa))
2353 result = xwa.map_state == IsViewable;
2354 /* In this implementation it should at least be != IsUnmapped
2357 f->visible = result;
2364 static int x_frame_totally_visible_p(struct frame *f)
2366 return FRAME_X_TOTALLY_VISIBLE_P(f);
2369 /* Change window state from mapped to iconified. */
2370 static void x_iconify_frame(struct frame *f)
2372 Display *display = DEVICE_X_DISPLAY(XDEVICE(f->device));
2374 if (!XIconifyWindow(display,
2375 XtWindow(FRAME_X_SHELL_WIDGET(f)),
2376 DefaultScreen(display)))
2377 x_cant_notify_wm_error();
2382 /* Sets the X focus to frame f. */
2383 static void x_focus_on_frame(struct frame *f)
2385 XWindowAttributes xwa;
2386 Widget shell_widget;
2389 assert(FRAME_X_P(f));
2391 shell_widget = FRAME_X_SHELL_WIDGET(f);
2392 if (!XtWindow(shell_widget))
2395 #ifdef EXTERNAL_WIDGET
2396 if (FRAME_X_EXTERNAL_WINDOW_P(f))
2397 ExternalShellSetFocus(shell_widget);
2398 #endif /* EXTERNAL_WIDGET */
2400 /* Do the ICCCM focus change if the window is still visible.
2401 The s->visible flag might not be up-to-date, because we might
2402 not have processed magic events recently. So make a server
2403 round-trip to find out whether it's really mapped right now.
2404 We grab the server to do this, because that's the only way to
2405 eliminate the race condition.
2407 XGrabServer(XtDisplay(shell_widget));
2408 if (XGetWindowAttributes(XtDisplay(shell_widget),
2409 XtWindow(shell_widget), &xwa))
2410 /* JV: it is bad to change the visibility like this, so we don't for the
2411 moment, at least change_frame_visibility should be called
2412 Note also that under fvwm a frame can be Viewable (and thus Mapped)
2413 but still X-invisible
2414 f->visible = xwa.map_state == IsViewable; */
2415 viewable = xwa.map_state == IsViewable;
2420 XGetInputFocus(XtDisplay(shell_widget), &focus, &revert_to);
2421 /* Don't explicitly set the focus on this window unless the focus
2422 was on some other window (not PointerRoot). Note that, even when
2423 running a point-to-type window manager like *twm, there is always
2424 a focus window; the window manager maintains that based on the
2425 mouse position. If you set the "NoTitleFocus" option in these
2426 window managers, then the server itself maintains the focus via
2427 PointerRoot, and changing that to focus on the window would make
2428 the window grab the focus. Very bad.
2430 if (focus != PointerRoot) {
2431 XSetInputFocus(XtDisplay(shell_widget),
2432 XtWindow(shell_widget),
2434 DEVICE_X_MOUSE_TIMESTAMP
2435 (XDEVICE(FRAME_DEVICE(f))));
2436 XFlush(XtDisplay(shell_widget));
2439 XUngrabServer(XtDisplay(shell_widget));
2440 XFlush(XtDisplay(shell_widget)); /* hey, I'd like to DEBUG this... */
2443 /* Destroy the X window of frame F. */
2444 static void x_delete_frame(struct frame *f)
2448 #ifndef HAVE_WMCOMMAND
2449 if (FRAME_X_TOP_LEVEL_FRAME_P(f))
2450 x_wm_maybe_move_wm_command(f);
2451 #endif /* HAVE_WMCOMMAND */
2454 DtDndDropUnregister(FRAME_X_TEXT_WIDGET(f));
2455 #endif /* HAVE_CDE */
2457 assert(FRAME_X_SHELL_WIDGET(f) != 0);
2458 dpy = XtDisplay(FRAME_X_SHELL_WIDGET(f));
2460 #ifdef EXTERNAL_WIDGET
2461 expect_x_error(dpy);
2462 /* for obscure reasons having (I think) to do with the internal
2463 window-to-widget hierarchy maintained by Xt, we have to call
2464 XtUnrealizeWidget() here. Xt can really suck. */
2465 if (f->being_deleted)
2466 XtUnrealizeWidget(FRAME_X_SHELL_WIDGET(f));
2467 XtDestroyWidget(FRAME_X_SHELL_WIDGET(f));
2468 x_error_occurred_p(dpy);
2470 XtDestroyWidget(FRAME_X_SHELL_WIDGET(f));
2471 /* make sure the windows are really gone! */
2472 /* #### Is this REALLY necessary? */
2474 #endif /* EXTERNAL_WIDGET */
2476 FRAME_X_SHELL_WIDGET(f) = 0;
2478 if (FRAME_X_GEOM_FREE_ME_PLEASE(f)) {
2479 xfree(FRAME_X_GEOM_FREE_ME_PLEASE(f));
2480 FRAME_X_GEOM_FREE_ME_PLEASE(f) = 0;
2483 if (f->frame_data) {
2484 xfree(f->frame_data);
2489 static void x_update_frame_external_traits(struct frame *frm, Lisp_Object name)
2495 XSETFRAME(frame, frm);
2497 if (EQ(name, Qforeground)) {
2498 Lisp_Object color = FACE_FOREGROUND(Vdefault_face, frame);
2501 if (!EQ(color, Vthe_null_color_instance)) {
2502 fgc = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(color));
2503 XtSetArg(al[ac], XtNforeground, (void *)fgc.pixel);
2506 } else if (EQ(name, Qbackground)) {
2507 Lisp_Object color = FACE_BACKGROUND(Vdefault_face, frame);
2510 if (!EQ(color, Vthe_null_color_instance)) {
2511 bgc = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(color));
2512 XtSetArg(al[ac], XtNbackground, (void *)bgc.pixel);
2516 /* Really crappy way to force the modeline shadows to be
2517 redrawn. But effective. */
2518 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED(frm);
2519 MARK_FRAME_CHANGED(frm);
2520 } else if (EQ(name, Qfont)) {
2522 FACE_FONT(Vdefault_face, frame, Vcharset_ascii);
2524 if (!EQ(font, Vthe_null_font_instance)) {
2525 XtSetArg(al[ac], XtNfont,
2527 FONT_INSTANCE_X_FONT(XFONT_INSTANCE(font)));
2533 XtSetValues(FRAME_X_TEXT_WIDGET(frm), al, ac);
2535 #ifdef HAVE_TOOLBARS
2536 /* Setting the background clears the entire frame area
2537 including the toolbar so we force an immediate redraw of
2539 if (EQ(name, Qbackground))
2540 MAYBE_DEVMETH(XDEVICE(frm->device), redraw_frame_toolbars,
2542 #endif /* HAVE_TOOLBARS */
2544 /* Set window manager resize increment hints according to
2545 the new character size */
2546 if (EQ(name, Qfont))
2547 EmacsFrameRecomputeCellSize(FRAME_X_TEXT_WIDGET(frm));
2550 /************************************************************************/
2551 /* initialization */
2552 /************************************************************************/
2554 void syms_of_frame_x(void)
2556 defsymbol(&Qwindow_id, "window-id");
2557 defsymbol(&Qoverride_redirect, "override-redirect");
2558 defsymbol(&Qx_resource_name, "x-resource-name");
2560 DEFSUBR(Fx_window_id);
2562 DEFSUBR(Fcde_start_drag_internal);
2566 void console_type_create_frame_x(void)
2569 CONSOLE_HAS_METHOD(x, init_frame_1);
2570 CONSOLE_HAS_METHOD(x, init_frame_2);
2571 CONSOLE_HAS_METHOD(x, init_frame_3);
2572 CONSOLE_HAS_METHOD(x, mark_frame);
2573 CONSOLE_HAS_METHOD(x, focus_on_frame);
2574 CONSOLE_HAS_METHOD(x, delete_frame);
2575 CONSOLE_HAS_METHOD(x, get_mouse_position);
2576 CONSOLE_HAS_METHOD(x, set_mouse_position);
2577 CONSOLE_HAS_METHOD(x, raise_frame);
2578 CONSOLE_HAS_METHOD(x, lower_frame);
2579 CONSOLE_HAS_METHOD(x, enable_frame);
2580 CONSOLE_HAS_METHOD(x, disable_frame);
2581 CONSOLE_HAS_METHOD(x, make_frame_visible);
2582 CONSOLE_HAS_METHOD(x, make_frame_invisible);
2583 CONSOLE_HAS_METHOD(x, iconify_frame);
2584 CONSOLE_HAS_METHOD(x, set_frame_size);
2585 CONSOLE_HAS_METHOD(x, set_frame_position);
2586 CONSOLE_HAS_METHOD(x, frame_property);
2587 CONSOLE_HAS_METHOD(x, internal_frame_property_p);
2588 CONSOLE_HAS_METHOD(x, frame_properties);
2589 CONSOLE_HAS_METHOD(x, set_frame_properties);
2590 CONSOLE_HAS_METHOD(x, set_title_from_bufbyte);
2591 CONSOLE_HAS_METHOD(x, set_icon_name_from_bufbyte);
2592 CONSOLE_HAS_METHOD(x, frame_visible_p);
2593 CONSOLE_HAS_METHOD(x, frame_totally_visible_p);
2594 CONSOLE_HAS_METHOD(x, frame_iconified_p);
2595 CONSOLE_HAS_METHOD(x, set_frame_pointer);
2596 CONSOLE_HAS_METHOD(x, set_frame_icon);
2597 CONSOLE_HAS_METHOD(x, get_frame_parent);
2598 CONSOLE_HAS_METHOD(x, update_frame_external_traits);
2601 void vars_of_frame_x(void)
2603 #ifdef EXTERNAL_WIDGET
2604 Fprovide(intern("external-widget"));
2607 /* this call uses only safe functions from emacs.c */
2608 init_x_prop_symbols();
2610 DEFVAR_LISP("default-x-frame-plist", &Vdefault_x_frame_plist /*
2611 Plist of default frame-creation properties for X frames.
2612 These override what is specified in the resource database and in
2613 `default-frame-plist', but are overridden by the arguments to the
2614 particular call to `make-frame'.
2616 Note: In many cases, properties of a frame are available as specifiers
2617 instead of through the frame-properties mechanism.
2619 Here is a list of recognized frame properties, other than those
2620 documented in `set-frame-properties' (they can be queried and
2621 set at any time, except as otherwise noted):
2623 window-id The X window ID corresponding to the
2624 frame. May be set only at startup, and
2625 only if external widget support was
2626 compiled in; doing so causes the frame
2627 to be created as an "external widget"
2628 in another program that uses an existing
2629 window in the program rather than creating
2631 initially-unmapped If non-nil, the frame will not be visible
2632 when it is created. In this case, you
2633 need to call `make-frame-visible' to make
2635 popup If non-nil, it should be a frame, and this
2636 frame will be created as a "popup" frame
2637 whose parent is the given frame. This
2638 will make the window manager treat the
2639 frame as a dialog box, which may entail
2640 doing different things (e.g. not asking
2641 for positioning, and not iconifying
2642 separate from its parent).
2643 override-redirect If non-nil, the frame will not be subject to
2644 window-manager control. In particular, it
2645 will lack decorations, for more attractive
2646 appearance of balloon help, aka tooltips.
2647 inter-line-space Not currently implemented.
2648 toolbar-shadow-thickness Thickness of toolbar shadows.
2649 background-toolbar-color Color of toolbar background.
2650 bottom-toolbar-shadow-color Color of bottom shadows on toolbars.
2651 (*Not* specific to the bottom-toolbar.)
2652 top-toolbar-shadow-color Color of top shadows on toolbars.
2653 (*Not* specific to the top-toolbar.)
2654 internal-border-width Width of internal border around text area.
2655 border-width Width of external border around text area.
2656 top Y position (in pixels) of the upper-left
2657 outermost corner of the frame (i.e. the
2658 upper-left of the window-manager
2660 left X position (in pixels) of the upper-left
2661 outermost corner of the frame (i.e. the
2662 upper-left of the window-manager
2664 border-color Color of external border around text area.
2665 cursor-color Color of text cursor.
2667 See also `default-frame-plist', which specifies properties which apply
2668 to all frames, not just X frames.
2670 Vdefault_x_frame_plist = Qnil;
2672 x_console_methods->device_specific_frame_props =
2673 &Vdefault_x_frame_plist;